1 /* 2 * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 * $FreeBSD$ 12 * 13 */ 14 15 #include <sm/gen.h> 16 17 SM_IDSTR(copyright, 18 "@(#) Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.\n\ 19 All rights reserved.\n\ 20 Copyright (c) 1990, 1993, 1994\n\ 21 The Regents of the University of California. All rights reserved.\n") 22 23 SM_IDSTR(id, "@(#)$Id: mail.local.c,v 8.253 2004/11/01 20:42:42 ca Exp $") 24 25 #include <stdlib.h> 26 #include <sm/errstring.h> 27 #include <sm/io.h> 28 #include <sm/limits.h> 29 # include <unistd.h> 30 # ifdef EX_OK 31 # undef EX_OK /* unistd.h may have another use for this */ 32 # endif /* EX_OK */ 33 # define LOCKFILE_PMODE 0 34 #include <sm/mbdb.h> 35 #include <sm/sysexits.h> 36 37 #ifndef HASHSPOOL 38 # define HASHSPOOL 0 39 #endif /* ! HASHSPOOL */ 40 #ifndef HASHSPOOLMD5 41 # define HASHSPOOLMD5 0 42 #endif /* ! HASHSPOOLMD5 */ 43 44 /* 45 ** This is not intended to work on System V derived systems 46 ** such as Solaris or HP-UX, since they use a totally different 47 ** approach to mailboxes (essentially, they have a set-group-ID program 48 ** rather than set-user-ID, and they rely on the ability to "give away" 49 ** files to do their work). IT IS NOT A BUG that this doesn't 50 ** work on such architectures. 51 */ 52 53 54 #include <stdio.h> 55 #include <errno.h> 56 #include <fcntl.h> 57 #include <sys/types.h> 58 #include <sys/stat.h> 59 #include <time.h> 60 #include <stdlib.h> 61 # include <sys/socket.h> 62 # include <sys/file.h> 63 # include <netinet/in.h> 64 # include <arpa/nameser.h> 65 # include <netdb.h> 66 # include <pwd.h> 67 68 #include <sm/string.h> 69 #include <syslog.h> 70 #include <ctype.h> 71 72 #include <sm/conf.h> 73 #include <sendmail/pathnames.h> 74 75 #if HASHSPOOL 76 # define HASH_NONE 0 77 # define HASH_USER 1 78 # if HASHSPOOLMD5 79 # define HASH_MD5 2 80 # include <openssl/md5.h> 81 # endif /* HASHSPOOLMD5 */ 82 #endif /* HASHSPOOL */ 83 84 85 #ifndef LOCKTO_RM 86 # define LOCKTO_RM 300 /* timeout for stale lockfile removal */ 87 #endif /* ! LOCKTO_RM */ 88 #ifndef LOCKTO_GLOB 89 # define LOCKTO_GLOB 400 /* global timeout for lockfile creation */ 90 #endif /* ! LOCKTO_GLOB */ 91 92 /* define a realloc() which works for NULL pointers */ 93 #define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size)) 94 95 /* 96 ** If you don't have flock, you could try using lockf instead. 97 */ 98 99 #ifdef LDA_USE_LOCKF 100 # define flock(a, b) lockf(a, b, 0) 101 # ifdef LOCK_EX 102 # undef LOCK_EX 103 # endif /* LOCK_EX */ 104 # define LOCK_EX F_LOCK 105 #endif /* LDA_USE_LOCKF */ 106 107 #ifndef LOCK_EX 108 # include <sys/file.h> 109 #endif /* ! LOCK_EX */ 110 111 /* 112 ** If you don't have setreuid, and you have saved uids, and you have 113 ** a seteuid() call that doesn't try to emulate using setuid(), then 114 ** you can try defining LDA_USE_SETEUID. 115 */ 116 117 #ifdef LDA_USE_SETEUID 118 # define setreuid(r, e) seteuid(e) 119 #endif /* LDA_USE_SETEUID */ 120 121 #ifdef LDA_CONTENTLENGTH 122 # define CONTENTLENGTH 1 123 #endif /* LDA_CONTENTLENGTH */ 124 125 #ifndef INADDRSZ 126 # define INADDRSZ 4 /* size of an IPv4 address in bytes */ 127 #endif /* ! INADDRSZ */ 128 129 #ifdef MAILLOCK 130 # include <maillock.h> 131 #endif /* MAILLOCK */ 132 133 #ifndef MAILER_DAEMON 134 # define MAILER_DAEMON "MAILER-DAEMON" 135 #endif /* ! MAILER_DAEMON */ 136 137 #ifdef CONTENTLENGTH 138 char ContentHdr[40] = "Content-Length: "; 139 off_t HeaderLength; 140 off_t BodyLength; 141 #endif /* CONTENTLENGTH */ 142 143 bool EightBitMime = true; /* advertise 8BITMIME in LMTP */ 144 char ErrBuf[10240]; /* error buffer */ 145 int ExitVal = EX_OK; /* sysexits.h error value. */ 146 bool nobiff = false; 147 bool nofsync = false; 148 bool HoldErrs = false; /* Hold errors in ErrBuf */ 149 bool LMTPMode = false; 150 bool BounceQuota = false; /* permanent error when over quota */ 151 bool CloseMBDB = false; 152 char *HomeMailFile = NULL; /* store mail in homedir */ 153 154 #if HASHSPOOL 155 int HashType = HASH_NONE; 156 int HashDepth = 0; 157 bool StripRcptDomain = true; 158 #else /* HASHSPOOL */ 159 # define StripRcptDomain true 160 #endif /* HASHSPOOL */ 161 char SpoolPath[MAXPATHLEN]; 162 163 char *parseaddr __P((char *, bool)); 164 char *process_recipient __P((char *)); 165 void dolmtp __P((void)); 166 void deliver __P((int, char *)); 167 int e_to_sys __P((int)); 168 void notifybiff __P((char *)); 169 int store __P((char *, bool *)); 170 void usage __P((void)); 171 int lockmbox __P((char *)); 172 void unlockmbox __P((void)); 173 void mailerr __P((const char *, const char *, ...)); 174 void flush_error __P((void)); 175 #if HASHSPOOL 176 const char *hashname __P((char *)); 177 #endif /* HASHSPOOL */ 178 179 180 static void 181 sm_exit(status) 182 int status; 183 { 184 if (CloseMBDB) 185 { 186 sm_mbdb_terminate(); 187 CloseMBDB = false; /* not really necessary, but ... */ 188 } 189 exit(status); 190 } 191 192 int 193 main(argc, argv) 194 int argc; 195 char *argv[]; 196 { 197 struct passwd *pw; 198 int ch, fd; 199 uid_t uid; 200 char *from; 201 char *mbdbname = "pw"; 202 int err; 203 extern char *optarg; 204 extern int optind; 205 206 207 /* make sure we have some open file descriptors */ 208 for (fd = 10; fd < 30; fd++) 209 (void) close(fd); 210 211 /* use a reasonable umask */ 212 (void) umask(0077); 213 214 # ifdef LOG_MAIL 215 openlog("mail.local", 0, LOG_MAIL); 216 # else /* LOG_MAIL */ 217 openlog("mail.local", 0); 218 # endif /* LOG_MAIL */ 219 220 from = NULL; 221 222 /* XXX can this be converted to a compile time check? */ 223 if (sm_strlcpy(SpoolPath, _PATH_MAILDIR, sizeof(SpoolPath)) >= 224 sizeof(SpoolPath)) 225 { 226 mailerr("421", "Configuration error: _PATH_MAILDIR too large"); 227 sm_exit(EX_CONFIG); 228 } 229 #if HASHSPOOL 230 while ((ch = getopt(argc, argv, "7BbdD:f:h:r:lH:p:ns")) != -1) 231 #else /* HASHSPOOL */ 232 while ((ch = getopt(argc, argv, "7BbdD:f:h:r:ls")) != -1) 233 #endif /* HASHSPOOL */ 234 { 235 switch(ch) 236 { 237 case '7': /* Do not advertise 8BITMIME */ 238 EightBitMime = false; 239 break; 240 241 case 'B': 242 nobiff = true; 243 break; 244 245 case 'b': /* bounce mail when over quota. */ 246 BounceQuota = true; 247 break; 248 249 case 'd': /* Backward compatible. */ 250 break; 251 252 case 'D': /* mailbox database type */ 253 mbdbname = optarg; 254 break; 255 256 case 'f': 257 case 'r': /* Backward compatible. */ 258 if (from != NULL) 259 { 260 mailerr(NULL, "Multiple -f options"); 261 usage(); 262 } 263 from = optarg; 264 break; 265 266 case 'h': 267 if (optarg != NULL || *optarg != '\0') 268 HomeMailFile = optarg; 269 else 270 { 271 mailerr(NULL, "-h: missing filename"); 272 usage(); 273 } 274 break; 275 276 case 'l': 277 LMTPMode = true; 278 break; 279 280 case 's': 281 nofsync++; 282 break; 283 284 #if HASHSPOOL 285 case 'H': 286 if (optarg == NULL || *optarg == '\0') 287 { 288 mailerr(NULL, "-H: missing hashinfo"); 289 usage(); 290 } 291 switch(optarg[0]) 292 { 293 case 'u': 294 HashType = HASH_USER; 295 break; 296 297 # if HASHSPOOLMD5 298 case 'm': 299 HashType = HASH_MD5; 300 break; 301 # endif /* HASHSPOOLMD5 */ 302 303 default: 304 mailerr(NULL, "-H: unknown hash type"); 305 usage(); 306 } 307 if (optarg[1] == '\0') 308 { 309 mailerr(NULL, "-H: invalid hash depth"); 310 usage(); 311 } 312 HashDepth = atoi(&optarg[1]); 313 if ((HashDepth <= 0) || ((HashDepth * 2) >= MAXPATHLEN)) 314 { 315 mailerr(NULL, "-H: invalid hash depth"); 316 usage(); 317 } 318 break; 319 320 case 'p': 321 if (optarg == NULL || *optarg == '\0') 322 { 323 mailerr(NULL, "-p: missing spool path"); 324 usage(); 325 } 326 if (sm_strlcpy(SpoolPath, optarg, sizeof(SpoolPath)) >= 327 sizeof(SpoolPath)) 328 { 329 mailerr(NULL, "-p: invalid spool path"); 330 usage(); 331 } 332 break; 333 334 case 'n': 335 StripRcptDomain = false; 336 break; 337 #endif /* HASHSPOOL */ 338 339 case '?': 340 default: 341 usage(); 342 } 343 } 344 argc -= optind; 345 argv += optind; 346 347 /* initialize biff structures */ 348 if (!nobiff) 349 notifybiff(NULL); 350 351 err = sm_mbdb_initialize(mbdbname); 352 if (err != EX_OK) 353 { 354 char *errcode = "521"; 355 356 if (err == EX_TEMPFAIL) 357 errcode = "421"; 358 359 mailerr(errcode, "Can not open mailbox database %s: %s", 360 mbdbname, sm_strexit(err)); 361 sm_exit(err); 362 } 363 CloseMBDB = true; 364 365 if (LMTPMode) 366 { 367 if (argc > 0) 368 { 369 mailerr("421", "Users should not be specified in command line if LMTP required"); 370 sm_exit(EX_TEMPFAIL); 371 } 372 373 dolmtp(); 374 /* NOTREACHED */ 375 sm_exit(EX_OK); 376 } 377 378 /* Non-LMTP from here on out */ 379 if (*argv == '\0') 380 usage(); 381 382 /* 383 ** If from not specified, use the name from getlogin() if the 384 ** uid matches, otherwise, use the name from the password file 385 ** corresponding to the uid. 386 */ 387 388 uid = getuid(); 389 if (from == NULL && ((from = getlogin()) == NULL || 390 (pw = getpwnam(from)) == NULL || 391 pw->pw_uid != uid)) 392 from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???"; 393 394 /* 395 ** There is no way to distinguish the error status of one delivery 396 ** from the rest of the deliveries. So, if we failed hard on one 397 ** or more deliveries, but had no failures on any of the others, we 398 ** return a hard failure. If we failed temporarily on one or more 399 ** deliveries, we return a temporary failure regardless of the other 400 ** failures. This results in the delivery being reattempted later 401 ** at the expense of repeated failures and multiple deliveries. 402 */ 403 404 HoldErrs = true; 405 fd = store(from, NULL); 406 HoldErrs = false; 407 if (fd < 0) 408 { 409 flush_error(); 410 sm_exit(ExitVal); 411 } 412 for (; *argv != NULL; ++argv) 413 deliver(fd, *argv); 414 sm_exit(ExitVal); 415 /* NOTREACHED */ 416 return ExitVal; 417 } 418 419 char * 420 parseaddr(s, rcpt) 421 char *s; 422 bool rcpt; 423 { 424 char *p; 425 int l; 426 427 if (*s++ != '<') 428 return NULL; 429 430 p = s; 431 432 /* at-domain-list */ 433 while (*p == '@') 434 { 435 p++; 436 while (*p != ',' && *p != ':' && *p != '\0') 437 p++; 438 if (*p == '\0') 439 return NULL; 440 441 /* Skip over , or : */ 442 p++; 443 } 444 445 s = p; 446 447 /* local-part */ 448 while (*p != '\0' && *p != '@' && *p != '>') 449 { 450 if (*p == '\\') 451 { 452 if (*++p == '\0') 453 return NULL; 454 } 455 else if (*p == '\"') 456 { 457 p++; 458 while (*p != '\0' && *p != '\"') 459 { 460 if (*p == '\\') 461 { 462 if (*++p == '\0') 463 return NULL; 464 } 465 p++; 466 } 467 if (*p == '\0' || *(p + 1) == '\0') 468 return NULL; 469 } 470 /* +detail ? */ 471 if (*p == '+' && rcpt) 472 *p = '\0'; 473 p++; 474 } 475 476 /* @domain */ 477 if (*p == '@') 478 { 479 if (rcpt) 480 *p++ = '\0'; 481 while (*p != '\0' && *p != '>') 482 p++; 483 } 484 485 if (*p != '>') 486 return NULL; 487 else 488 *p = '\0'; 489 p++; 490 491 if (*p != '\0' && *p != ' ') 492 return NULL; 493 494 if (*s == '\0') 495 s = MAILER_DAEMON; 496 497 l = strlen(s) + 1; 498 if (l < 0) 499 return NULL; 500 p = malloc(l); 501 if (p == NULL) 502 { 503 mailerr("421 4.3.0", "Memory exhausted"); 504 sm_exit(EX_TEMPFAIL); 505 } 506 507 (void) sm_strlcpy(p, s, l); 508 return p; 509 } 510 511 char * 512 process_recipient(addr) 513 char *addr; 514 { 515 SM_MBDB_T user; 516 517 switch (sm_mbdb_lookup(addr, &user)) 518 { 519 case EX_OK: 520 return NULL; 521 522 case EX_NOUSER: 523 return "550 5.1.1 User unknown"; 524 525 case EX_TEMPFAIL: 526 return "451 4.3.0 User database failure; retry later"; 527 528 default: 529 return "550 5.3.0 User database failure"; 530 } 531 } 532 533 #define RCPT_GROW 30 534 535 void 536 dolmtp() 537 { 538 char *return_path = NULL; 539 char **rcpt_addr = NULL; 540 int rcpt_num = 0; 541 int rcpt_alloc = 0; 542 bool gotlhlo = false; 543 char *err; 544 int msgfd; 545 char *p; 546 int i; 547 char myhostname[1024]; 548 char buf[4096]; 549 550 memset(myhostname, '\0', sizeof myhostname); 551 (void) gethostname(myhostname, sizeof myhostname - 1); 552 if (myhostname[0] == '\0') 553 sm_strlcpy(myhostname, "localhost", sizeof myhostname); 554 555 printf("220 %s LMTP ready\r\n", myhostname); 556 for (;;) 557 { 558 (void) fflush(stdout); 559 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) 560 sm_exit(EX_OK); 561 p = buf + strlen(buf) - 1; 562 if (p >= buf && *p == '\n') 563 *p-- = '\0'; 564 if (p >= buf && *p == '\r') 565 *p-- = '\0'; 566 567 switch (buf[0]) 568 { 569 case 'd': 570 case 'D': 571 if (sm_strcasecmp(buf, "data") == 0) 572 { 573 bool inbody = false; 574 575 if (rcpt_num == 0) 576 { 577 mailerr("503 5.5.1", "No recipients"); 578 continue; 579 } 580 HoldErrs = true; 581 msgfd = store(return_path, &inbody); 582 HoldErrs = false; 583 if (msgfd < 0 && !inbody) 584 { 585 flush_error(); 586 continue; 587 } 588 589 for (i = 0; i < rcpt_num; i++) 590 { 591 if (msgfd < 0) 592 { 593 /* print error for rcpt */ 594 flush_error(); 595 continue; 596 } 597 p = strchr(rcpt_addr[i], '+'); 598 if (p != NULL) 599 *p = '\0'; 600 deliver(msgfd, rcpt_addr[i]); 601 } 602 if (msgfd >= 0) 603 (void) close(msgfd); 604 goto rset; 605 } 606 goto syntaxerr; 607 /* NOTREACHED */ 608 break; 609 610 case 'l': 611 case 'L': 612 if (sm_strncasecmp(buf, "lhlo ", 5) == 0) 613 { 614 /* check for duplicate per RFC 1651 4.2 */ 615 if (gotlhlo) 616 { 617 mailerr("503", "%s Duplicate LHLO", 618 myhostname); 619 continue; 620 } 621 gotlhlo = true; 622 printf("250-%s\r\n", myhostname); 623 if (EightBitMime) 624 printf("250-8BITMIME\r\n"); 625 printf("250-ENHANCEDSTATUSCODES\r\n"); 626 printf("250 PIPELINING\r\n"); 627 continue; 628 } 629 goto syntaxerr; 630 /* NOTREACHED */ 631 break; 632 633 case 'm': 634 case 'M': 635 if (sm_strncasecmp(buf, "mail ", 5) == 0) 636 { 637 if (return_path != NULL) 638 { 639 mailerr("503 5.5.1", 640 "Nested MAIL command"); 641 continue; 642 } 643 if (sm_strncasecmp(buf + 5, "from:", 5) != 0 || 644 ((return_path = parseaddr(buf + 10, 645 false)) == NULL)) 646 { 647 mailerr("501 5.5.4", 648 "Syntax error in parameters"); 649 continue; 650 } 651 printf("250 2.5.0 Ok\r\n"); 652 continue; 653 } 654 goto syntaxerr; 655 /* NOTREACHED */ 656 break; 657 658 case 'n': 659 case 'N': 660 if (sm_strcasecmp(buf, "noop") == 0) 661 { 662 printf("250 2.0.0 Ok\r\n"); 663 continue; 664 } 665 goto syntaxerr; 666 /* NOTREACHED */ 667 break; 668 669 case 'q': 670 case 'Q': 671 if (sm_strcasecmp(buf, "quit") == 0) 672 { 673 printf("221 2.0.0 Bye\r\n"); 674 sm_exit(EX_OK); 675 } 676 goto syntaxerr; 677 /* NOTREACHED */ 678 break; 679 680 case 'r': 681 case 'R': 682 if (sm_strncasecmp(buf, "rcpt ", 5) == 0) 683 { 684 if (return_path == NULL) 685 { 686 mailerr("503 5.5.1", 687 "Need MAIL command"); 688 continue; 689 } 690 if (rcpt_num >= rcpt_alloc) 691 { 692 rcpt_alloc += RCPT_GROW; 693 rcpt_addr = (char **) 694 REALLOC((char *) rcpt_addr, 695 rcpt_alloc * 696 sizeof(char **)); 697 if (rcpt_addr == NULL) 698 { 699 mailerr("421 4.3.0", 700 "Memory exhausted"); 701 sm_exit(EX_TEMPFAIL); 702 } 703 } 704 if (sm_strncasecmp(buf + 5, "to:", 3) != 0 || 705 ((rcpt_addr[rcpt_num] = parseaddr(buf + 8, 706 StripRcptDomain)) == NULL)) 707 { 708 mailerr("501 5.5.4", 709 "Syntax error in parameters"); 710 continue; 711 } 712 err = process_recipient(rcpt_addr[rcpt_num]); 713 if (err != NULL) 714 { 715 mailerr(NULL, "%s", err); 716 continue; 717 } 718 rcpt_num++; 719 printf("250 2.1.5 Ok\r\n"); 720 continue; 721 } 722 else if (sm_strcasecmp(buf, "rset") == 0) 723 { 724 printf("250 2.0.0 Ok\r\n"); 725 726 rset: 727 while (rcpt_num > 0) 728 free(rcpt_addr[--rcpt_num]); 729 if (return_path != NULL) 730 free(return_path); 731 return_path = NULL; 732 continue; 733 } 734 goto syntaxerr; 735 /* NOTREACHED */ 736 break; 737 738 case 'v': 739 case 'V': 740 if (sm_strncasecmp(buf, "vrfy ", 5) == 0) 741 { 742 printf("252 2.3.3 Try RCPT to attempt delivery\r\n"); 743 continue; 744 } 745 goto syntaxerr; 746 /* NOTREACHED */ 747 break; 748 749 default: 750 syntaxerr: 751 mailerr("500 5.5.2", "Syntax error"); 752 continue; 753 /* NOTREACHED */ 754 break; 755 } 756 } 757 } 758 759 int 760 store(from, inbody) 761 char *from; 762 bool *inbody; 763 { 764 FILE *fp = NULL; 765 time_t tval; 766 bool eline; /* previous line was empty */ 767 bool fullline = true; /* current line is terminated */ 768 bool prevfl; /* previous line was terminated */ 769 char line[2048]; 770 int fd; 771 char tmpbuf[sizeof _PATH_LOCTMP + 1]; 772 773 if (inbody != NULL) 774 *inbody = false; 775 776 (void) umask(0077); 777 (void) sm_strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf); 778 if ((fd = mkstemp(tmpbuf)) < 0 || (fp = fdopen(fd, "w+")) == NULL) 779 { 780 if (fd >= 0) 781 (void) close(fd); 782 mailerr("451 4.3.0", "Unable to open temporary file"); 783 return -1; 784 } 785 (void) unlink(tmpbuf); 786 787 if (LMTPMode) 788 { 789 printf("354 Go ahead\r\n"); 790 (void) fflush(stdout); 791 } 792 if (inbody != NULL) 793 *inbody = true; 794 795 (void) time(&tval); 796 (void) fprintf(fp, "From %s %s", from, ctime(&tval)); 797 798 #ifdef CONTENTLENGTH 799 HeaderLength = 0; 800 BodyLength = -1; 801 #endif /* CONTENTLENGTH */ 802 803 line[0] = '\0'; 804 eline = true; 805 while (fgets(line, sizeof(line), stdin) != (char *) NULL) 806 { 807 size_t line_len = 0; 808 int peek; 809 810 prevfl = fullline; /* preserve state of previous line */ 811 while (line[line_len] != '\n' && line_len < sizeof(line) - 2) 812 line_len++; 813 line_len++; 814 815 /* Check for dot-stuffing */ 816 if (prevfl && LMTPMode && line[0] == '.') 817 { 818 if (line[1] == '\n' || 819 (line[1] == '\r' && line[2] == '\n')) 820 goto lmtpdot; 821 memcpy(line, line + 1, line_len); 822 line_len--; 823 } 824 825 /* Check to see if we have the full line from fgets() */ 826 fullline = false; 827 if (line_len > 0) 828 { 829 if (line[line_len - 1] == '\n') 830 { 831 if (line_len >= 2 && 832 line[line_len - 2] == '\r') 833 { 834 line[line_len - 2] = '\n'; 835 line[line_len - 1] = '\0'; 836 line_len--; 837 } 838 fullline = true; 839 } 840 else if (line[line_len - 1] == '\r') 841 { 842 /* Did we just miss the CRLF? */ 843 peek = fgetc(stdin); 844 if (peek == '\n') 845 { 846 line[line_len - 1] = '\n'; 847 fullline = true; 848 } 849 else 850 (void) ungetc(peek, stdin); 851 } 852 } 853 else 854 fullline = true; 855 856 #ifdef CONTENTLENGTH 857 if (prevfl && line[0] == '\n' && HeaderLength == 0) 858 { 859 eline = false; 860 if (fp != NULL) 861 HeaderLength = ftell(fp); 862 if (HeaderLength <= 0) 863 { 864 /* 865 ** shouldn't happen, unless ftell() is 866 ** badly broken 867 */ 868 869 HeaderLength = -1; 870 } 871 } 872 #else /* CONTENTLENGTH */ 873 if (prevfl && line[0] == '\n') 874 eline = true; 875 #endif /* CONTENTLENGTH */ 876 else 877 { 878 if (eline && line[0] == 'F' && 879 fp != NULL && 880 !memcmp(line, "From ", 5)) 881 (void) putc('>', fp); 882 eline = false; 883 #ifdef CONTENTLENGTH 884 /* discard existing "Content-Length:" headers */ 885 if (prevfl && HeaderLength == 0 && 886 (line[0] == 'C' || line[0] == 'c') && 887 sm_strncasecmp(line, ContentHdr, 15) == 0) 888 { 889 /* 890 ** be paranoid: clear the line 891 ** so no "wrong matches" may occur later 892 */ 893 line[0] = '\0'; 894 continue; 895 } 896 #endif /* CONTENTLENGTH */ 897 898 } 899 if (fp != NULL) 900 { 901 (void) fwrite(line, sizeof(char), line_len, fp); 902 if (ferror(fp)) 903 { 904 mailerr("451 4.3.0", 905 "Temporary file write error"); 906 (void) fclose(fp); 907 fp = NULL; 908 continue; 909 } 910 } 911 } 912 913 /* check if an error occurred */ 914 if (fp == NULL) 915 return -1; 916 917 if (LMTPMode) 918 { 919 /* Got a premature EOF -- toss message and exit */ 920 sm_exit(EX_OK); 921 } 922 923 /* If message not newline terminated, need an extra. */ 924 if (fp != NULL && strchr(line, '\n') == NULL) 925 (void) putc('\n', fp); 926 927 lmtpdot: 928 929 #ifdef CONTENTLENGTH 930 if (fp != NULL) 931 BodyLength = ftell(fp); 932 if (HeaderLength == 0 && BodyLength > 0) /* empty body */ 933 { 934 HeaderLength = BodyLength; 935 BodyLength = 0; 936 } 937 else 938 BodyLength = BodyLength - HeaderLength - 1 ; 939 940 if (HeaderLength > 0 && BodyLength >= 0) 941 { 942 (void) sm_snprintf(line, sizeof line, "%lld\n", 943 (LONGLONG_T) BodyLength); 944 (void) sm_strlcpy(&ContentHdr[16], line, 945 sizeof(ContentHdr) - 16); 946 } 947 else 948 BodyLength = -1; /* Something is wrong here */ 949 #endif /* CONTENTLENGTH */ 950 951 /* Output a newline; note, empty messages are allowed. */ 952 if (fp != NULL) 953 (void) putc('\n', fp); 954 955 if (fp == NULL || fflush(fp) == EOF || ferror(fp) != 0) 956 { 957 mailerr("451 4.3.0", "Temporary file write error"); 958 if (fp != NULL) 959 (void) fclose(fp); 960 return -1; 961 } 962 return fd; 963 } 964 965 void 966 deliver(fd, name) 967 int fd; 968 char *name; 969 { 970 struct stat fsb; 971 struct stat sb; 972 char path[MAXPATHLEN]; 973 int mbfd = -1, nr = 0, nw, off; 974 int exitval; 975 char *p; 976 char *errcode; 977 off_t curoff, cursize; 978 #ifdef CONTENTLENGTH 979 off_t headerbytes; 980 int readamount; 981 #endif /* CONTENTLENGTH */ 982 char biffmsg[100], buf[8 * 1024]; 983 SM_MBDB_T user; 984 985 /* 986 ** Disallow delivery to unknown names -- special mailboxes can be 987 ** handled in the sendmail aliases file. 988 */ 989 990 exitval = sm_mbdb_lookup(name, &user); 991 switch (exitval) 992 { 993 case EX_OK: 994 break; 995 996 case EX_NOUSER: 997 exitval = EX_UNAVAILABLE; 998 mailerr("550 5.1.1", "%s: User unknown", name); 999 break; 1000 1001 case EX_TEMPFAIL: 1002 mailerr("451 4.3.0", "%s: User database failure; retry later", 1003 name); 1004 break; 1005 1006 default: 1007 exitval = EX_UNAVAILABLE; 1008 mailerr("550 5.3.0", "%s: User database failure", name); 1009 break; 1010 } 1011 1012 if (exitval != EX_OK) 1013 { 1014 if (ExitVal != EX_TEMPFAIL) 1015 ExitVal = exitval; 1016 return; 1017 } 1018 1019 endpwent(); 1020 1021 /* 1022 ** Keep name reasonably short to avoid buffer overruns. 1023 ** This isn't necessary on BSD because of the proper 1024 ** definition of snprintf(), but it can cause problems 1025 ** on other systems. 1026 ** Also, clear out any bogus characters. 1027 */ 1028 1029 #if !HASHSPOOL 1030 if (strlen(name) > 40) 1031 name[40] = '\0'; 1032 for (p = name; *p != '\0'; p++) 1033 { 1034 if (!isascii(*p)) 1035 *p &= 0x7f; 1036 else if (!isprint(*p)) 1037 *p = '.'; 1038 } 1039 #endif /* !HASHSPOOL */ 1040 1041 1042 if (HomeMailFile == NULL) 1043 { 1044 if (sm_strlcpyn(path, sizeof(path), 1045 #if HASHSPOOL 1046 4, 1047 #else /* HASHSPOOL */ 1048 3, 1049 #endif /* HASHSPOOL */ 1050 SpoolPath, "/", 1051 #if HASHSPOOL 1052 hashname(name), 1053 #endif /* HASHSPOOL */ 1054 name) >= sizeof(path)) 1055 { 1056 exitval = EX_UNAVAILABLE; 1057 mailerr("550 5.1.1", "%s: Invalid mailbox path", name); 1058 return; 1059 } 1060 } 1061 else if (*user.mbdb_homedir == '\0') 1062 { 1063 exitval = EX_UNAVAILABLE; 1064 mailerr("550 5.1.1", "%s: User missing home directory", name); 1065 return; 1066 } 1067 else if (sm_snprintf(path, sizeof(path), "%s/%s", 1068 user.mbdb_homedir, HomeMailFile) >= sizeof(path)) 1069 { 1070 exitval = EX_UNAVAILABLE; 1071 mailerr("550 5.1.1", "%s: Invalid mailbox path", name); 1072 return; 1073 } 1074 1075 1076 /* 1077 ** If the mailbox is linked or a symlink, fail. There's an obvious 1078 ** race here, that the file was replaced with a symbolic link after 1079 ** the lstat returned, but before the open. We attempt to detect 1080 ** this by comparing the original stat information and information 1081 ** returned by an fstat of the file descriptor returned by the open. 1082 ** 1083 ** NB: this is a symptom of a larger problem, that the mail spooling 1084 ** directory is writeable by the wrong users. If that directory is 1085 ** writeable, system security is compromised for other reasons, and 1086 ** it cannot be fixed here. 1087 ** 1088 ** If we created the mailbox, set the owner/group. If that fails, 1089 ** just return. Another process may have already opened it, so we 1090 ** can't unlink it. Historically, binmail set the owner/group at 1091 ** each mail delivery. We no longer do this, assuming that if the 1092 ** ownership or permissions were changed there was a reason. 1093 ** 1094 ** XXX 1095 ** open(2) should support flock'ing the file. 1096 */ 1097 1098 tryagain: 1099 #ifdef MAILLOCK 1100 p = name; 1101 #else /* MAILLOCK */ 1102 p = path; 1103 #endif /* MAILLOCK */ 1104 if ((off = lockmbox(p)) != 0) 1105 { 1106 if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL) 1107 { 1108 ExitVal = EX_TEMPFAIL; 1109 errcode = "451 4.3.0"; 1110 } 1111 else 1112 errcode = "551 5.3.0"; 1113 1114 mailerr(errcode, "lockmailbox %s failed; error code %d %s", 1115 p, off, errno > 0 ? sm_errstring(errno) : ""); 1116 return; 1117 } 1118 1119 if (lstat(path, &sb) < 0) 1120 { 1121 int save_errno; 1122 int mode = S_IRUSR|S_IWUSR; 1123 gid_t gid = user.mbdb_gid; 1124 1125 #ifdef MAILGID 1126 (void) umask(0007); 1127 gid = MAILGID; 1128 mode |= S_IRGRP|S_IWGRP; 1129 #endif /* MAILGID */ 1130 1131 mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, 1132 mode); 1133 save_errno = errno; 1134 1135 if (lstat(path, &sb) < 0) 1136 { 1137 ExitVal = EX_CANTCREAT; 1138 mailerr("550 5.2.0", 1139 "%s: lstat: file changed after open", path); 1140 goto err1; 1141 } 1142 if (mbfd < 0) 1143 { 1144 if (save_errno == EEXIST) 1145 goto tryagain; 1146 1147 /* open failed, don't try again */ 1148 mailerr("450 4.2.0", "%s: %s", path, 1149 sm_errstring(save_errno)); 1150 goto err0; 1151 } 1152 else if (fchown(mbfd, user.mbdb_uid, gid) < 0) 1153 { 1154 mailerr("451 4.3.0", "chown %u.%u: %s", 1155 user.mbdb_uid, gid, name); 1156 goto err1; 1157 } 1158 else 1159 { 1160 /* 1161 ** open() was successful, now close it so can 1162 ** be opened as the right owner again. 1163 ** Paranoia: reset mbdf since the file descriptor 1164 ** is no longer valid; better safe than sorry. 1165 */ 1166 1167 sb.st_uid = user.mbdb_uid; 1168 (void) close(mbfd); 1169 mbfd = -1; 1170 } 1171 } 1172 else if (sb.st_nlink != 1) 1173 { 1174 mailerr("550 5.2.0", "%s: too many links", path); 1175 goto err0; 1176 } 1177 else if (!S_ISREG(sb.st_mode)) 1178 { 1179 mailerr("550 5.2.0", "%s: irregular file", path); 1180 goto err0; 1181 } 1182 else if (sb.st_uid != user.mbdb_uid) 1183 { 1184 ExitVal = EX_CANTCREAT; 1185 mailerr("550 5.2.0", "%s: wrong ownership (%d)", 1186 path, (int) sb.st_uid); 1187 goto err0; 1188 } 1189 1190 /* change UID for quota checks */ 1191 if (setreuid(0, user.mbdb_uid) < 0) 1192 { 1193 mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)", 1194 (int) user.mbdb_uid, sm_errstring(errno), 1195 (int) getuid(), (int) geteuid()); 1196 goto err1; 1197 } 1198 #ifdef DEBUG 1199 fprintf(stderr, "new euid = %d\n", (int) geteuid()); 1200 #endif /* DEBUG */ 1201 mbfd = open(path, O_APPEND|O_WRONLY, 0); 1202 if (mbfd < 0) 1203 { 1204 mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno)); 1205 goto err0; 1206 } 1207 else if (fstat(mbfd, &fsb) < 0 || 1208 fsb.st_nlink != 1 || 1209 sb.st_nlink != 1 || 1210 !S_ISREG(fsb.st_mode) || 1211 sb.st_dev != fsb.st_dev || 1212 sb.st_ino != fsb.st_ino || 1213 # if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ 1214 sb.st_gen != fsb.st_gen || 1215 # endif /* HAS_ST_GEN && 0 */ 1216 sb.st_uid != fsb.st_uid) 1217 { 1218 ExitVal = EX_TEMPFAIL; 1219 mailerr("550 5.2.0", "%s: fstat: file changed after open", 1220 path); 1221 goto err1; 1222 } 1223 1224 #if 0 1225 /* 1226 ** This code could be reused if we decide to add a 1227 ** per-user quota field to the sm_mbdb interface. 1228 */ 1229 1230 /* 1231 ** Fail if the user has a quota specified, and delivery of this 1232 ** message would exceed that quota. We bounce such failures using 1233 ** EX_UNAVAILABLE, unless there were internal problems, since 1234 ** storing immense messages for later retries can cause queueing 1235 ** issues. 1236 */ 1237 1238 if (ui.quota > 0) 1239 { 1240 struct stat dsb; 1241 1242 if (fstat(fd, &dsb) < 0) 1243 { 1244 ExitVal = EX_TEMPFAIL; 1245 mailerr("451 4.3.0", 1246 "%s: fstat: can't stat temporary storage: %s", 1247 ui.mailspool, sm_errstring(errno)); 1248 goto err1; 1249 } 1250 1251 if (dsb.st_size + sb.st_size + 1 > ui.quota) 1252 { 1253 ExitVal = EX_UNAVAILABLE; 1254 mailerr("551 5.2.2", 1255 "%s: Mailbox full or quota exceeded", 1256 ui.mailspool); 1257 goto err1; 1258 } 1259 } 1260 #endif /* 0 */ 1261 1262 /* Wait until we can get a lock on the file. */ 1263 if (flock(mbfd, LOCK_EX) < 0) 1264 { 1265 mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno)); 1266 goto err1; 1267 } 1268 1269 /* Get the starting offset of the new message */ 1270 curoff = lseek(mbfd, (off_t) 0, SEEK_END); 1271 1272 if (!nobiff) 1273 { 1274 (void) sm_snprintf(biffmsg, sizeof(biffmsg), "%s@%lld\n", 1275 name, (LONGLONG_T) curoff); 1276 } 1277 1278 /* Copy the message into the file. */ 1279 if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1) 1280 { 1281 mailerr("450 4.2.0", "Temporary file: %s", 1282 sm_errstring(errno)); 1283 goto err1; 1284 } 1285 #ifdef DEBUG 1286 fprintf(stderr, "before writing: euid = %d\n", (int) geteuid()); 1287 #endif /* DEBUG */ 1288 #ifdef CONTENTLENGTH 1289 headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ; 1290 for (;;) 1291 { 1292 if (headerbytes == 0) 1293 { 1294 (void) sm_snprintf(buf, sizeof buf, "%s", ContentHdr); 1295 nr = strlen(buf); 1296 headerbytes = -1; 1297 readamount = 0; 1298 } 1299 else if (headerbytes > sizeof(buf) || headerbytes < 0) 1300 readamount = sizeof(buf); 1301 else 1302 readamount = headerbytes; 1303 if (readamount != 0) 1304 nr = read(fd, buf, readamount); 1305 if (nr <= 0) 1306 break; 1307 if (headerbytes > 0) 1308 headerbytes -= nr ; 1309 1310 #else /* CONTENTLENGTH */ 1311 while ((nr = read(fd, buf, sizeof(buf))) > 0) 1312 { 1313 #endif /* CONTENTLENGTH */ 1314 for (off = 0; off < nr; off += nw) 1315 { 1316 if ((nw = write(mbfd, buf + off, nr - off)) < 0) 1317 { 1318 errcode = "450 4.2.0"; 1319 #ifdef EDQUOT 1320 if (errno == EDQUOT && BounceQuota) 1321 errcode = "552 5.2.2"; 1322 #endif /* EDQUOT */ 1323 mailerr(errcode, "%s: %s", 1324 path, sm_errstring(errno)); 1325 goto err3; 1326 } 1327 } 1328 } 1329 if (nr < 0) 1330 { 1331 mailerr("450 4.2.0", "Temporary file: %s", 1332 sm_errstring(errno)); 1333 goto err3; 1334 } 1335 1336 /* Flush to disk, don't wait for update. */ 1337 if (!nofsync && fsync(mbfd) < 0) 1338 { 1339 mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno)); 1340 err3: 1341 #ifdef DEBUG 1342 fprintf(stderr, "reset euid = %d\n", (int) geteuid()); 1343 #endif /* DEBUG */ 1344 if (mbfd >= 0) 1345 (void) ftruncate(mbfd, curoff); 1346 err1: if (mbfd >= 0) 1347 (void) close(mbfd); 1348 err0: (void) setreuid(0, 0); 1349 unlockmbox(); 1350 return; 1351 } 1352 1353 /* 1354 ** Save the current size so if the close() fails below 1355 ** we can make sure no other process has changed the mailbox 1356 ** between the failed close and the re-open()/re-lock(). 1357 ** If something else has changed the size, we shouldn't 1358 ** try to truncate it as we may do more harm then good 1359 ** (e.g., truncate a later message delivery). 1360 */ 1361 1362 if (fstat(mbfd, &sb) < 0) 1363 cursize = 0; 1364 else 1365 cursize = sb.st_size; 1366 1367 1368 /* Close and check -- NFS doesn't write until the close. */ 1369 if (close(mbfd)) 1370 { 1371 errcode = "450 4.2.0"; 1372 #ifdef EDQUOT 1373 if (errno == EDQUOT && BounceQuota) 1374 errcode = "552 5.2.2"; 1375 #endif /* EDQUOT */ 1376 mailerr(errcode, "%s: %s", path, sm_errstring(errno)); 1377 mbfd = open(path, O_WRONLY, 0); 1378 if (mbfd < 0 || 1379 cursize == 0 1380 || flock(mbfd, LOCK_EX) < 0 || 1381 fstat(mbfd, &sb) < 0 || 1382 sb.st_size != cursize || 1383 sb.st_nlink != 1 || 1384 !S_ISREG(sb.st_mode) || 1385 sb.st_dev != fsb.st_dev || 1386 sb.st_ino != fsb.st_ino || 1387 # if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ 1388 sb.st_gen != fsb.st_gen || 1389 # endif /* HAS_ST_GEN && 0 */ 1390 sb.st_uid != fsb.st_uid 1391 ) 1392 { 1393 /* Don't use a bogus file */ 1394 if (mbfd >= 0) 1395 { 1396 (void) close(mbfd); 1397 mbfd = -1; 1398 } 1399 } 1400 1401 /* Attempt to truncate back to pre-write size */ 1402 goto err3; 1403 } 1404 else if (!nobiff) 1405 notifybiff(biffmsg); 1406 1407 if (setreuid(0, 0) < 0) 1408 { 1409 mailerr("450 4.2.0", "setreuid(0, 0): %s", 1410 sm_errstring(errno)); 1411 goto err0; 1412 } 1413 #ifdef DEBUG 1414 fprintf(stderr, "reset euid = %d\n", (int) geteuid()); 1415 #endif /* DEBUG */ 1416 unlockmbox(); 1417 if (LMTPMode) 1418 printf("250 2.1.5 %s Ok\r\n", name); 1419 } 1420 1421 /* 1422 ** user.lock files are necessary for compatibility with other 1423 ** systems, e.g., when the mail spool file is NFS exported. 1424 ** Alas, mailbox locking is more than just a local matter. 1425 ** EPA 11/94. 1426 */ 1427 1428 bool Locked = false; 1429 1430 #ifdef MAILLOCK 1431 int 1432 lockmbox(name) 1433 char *name; 1434 { 1435 int r = 0; 1436 1437 if (Locked) 1438 return 0; 1439 if ((r = maillock(name, 15)) == L_SUCCESS) 1440 { 1441 Locked = true; 1442 return 0; 1443 } 1444 switch (r) 1445 { 1446 case L_TMPLOCK: /* Can't create tmp file */ 1447 case L_TMPWRITE: /* Can't write pid into lockfile */ 1448 case L_MAXTRYS: /* Failed after retrycnt attempts */ 1449 errno = 0; 1450 r = EX_TEMPFAIL; 1451 break; 1452 case L_ERROR: /* Check errno for reason */ 1453 r = errno; 1454 break; 1455 default: /* other permanent errors */ 1456 errno = 0; 1457 r = EX_UNAVAILABLE; 1458 break; 1459 } 1460 return r; 1461 } 1462 1463 void 1464 unlockmbox() 1465 { 1466 if (Locked) 1467 mailunlock(); 1468 Locked = false; 1469 } 1470 #else /* MAILLOCK */ 1471 1472 char LockName[MAXPATHLEN]; 1473 1474 int 1475 lockmbox(path) 1476 char *path; 1477 { 1478 int statfailed = 0; 1479 time_t start; 1480 1481 if (Locked) 1482 return 0; 1483 if (strlen(path) + 6 > sizeof LockName) 1484 return EX_SOFTWARE; 1485 (void) sm_snprintf(LockName, sizeof LockName, "%s.lock", path); 1486 (void) time(&start); 1487 for (; ; sleep(5)) 1488 { 1489 int fd; 1490 struct stat st; 1491 time_t now; 1492 1493 /* global timeout */ 1494 (void) time(&now); 1495 if (now > start + LOCKTO_GLOB) 1496 { 1497 errno = 0; 1498 return EX_TEMPFAIL; 1499 } 1500 fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, LOCKFILE_PMODE); 1501 if (fd >= 0) 1502 { 1503 /* defeat lock checking programs which test pid */ 1504 (void) write(fd, "0", 2); 1505 Locked = true; 1506 (void) close(fd); 1507 return 0; 1508 } 1509 if (stat(LockName, &st) < 0) 1510 { 1511 if (statfailed++ > 5) 1512 { 1513 errno = 0; 1514 return EX_TEMPFAIL; 1515 } 1516 continue; 1517 } 1518 statfailed = 0; 1519 (void) time(&now); 1520 if (now < st.st_ctime + LOCKTO_RM) 1521 continue; 1522 1523 /* try to remove stale lockfile */ 1524 if (unlink(LockName) < 0) 1525 return errno; 1526 } 1527 } 1528 1529 void 1530 unlockmbox() 1531 { 1532 if (!Locked) 1533 return; 1534 (void) unlink(LockName); 1535 Locked = false; 1536 } 1537 #endif /* MAILLOCK */ 1538 1539 void 1540 notifybiff(msg) 1541 char *msg; 1542 { 1543 static bool initialized = false; 1544 static int f = -1; 1545 struct hostent *hp; 1546 struct servent *sp; 1547 int len; 1548 static struct sockaddr_in addr; 1549 1550 if (!initialized) 1551 { 1552 initialized = true; 1553 1554 /* Be silent if biff service not available. */ 1555 if ((sp = getservbyname("biff", "udp")) == NULL || 1556 (hp = gethostbyname("localhost")) == NULL || 1557 hp->h_length != INADDRSZ) 1558 return; 1559 1560 addr.sin_family = hp->h_addrtype; 1561 memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ); 1562 addr.sin_port = sp->s_port; 1563 } 1564 1565 /* No message, just return */ 1566 if (msg == NULL) 1567 return; 1568 1569 /* Couldn't initialize addr struct */ 1570 if (addr.sin_family == AF_UNSPEC) 1571 return; 1572 1573 if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1574 return; 1575 len = strlen(msg) + 1; 1576 (void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr)); 1577 } 1578 1579 void 1580 usage() 1581 { 1582 ExitVal = EX_USAGE; 1583 mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-d] [-l] [-s] [-f from|-r from] [-h filename] user ..."); 1584 sm_exit(ExitVal); 1585 } 1586 1587 void 1588 /*VARARGS2*/ 1589 #ifdef __STDC__ 1590 mailerr(const char *hdr, const char *fmt, ...) 1591 #else /* __STDC__ */ 1592 mailerr(hdr, fmt, va_alist) 1593 const char *hdr; 1594 const char *fmt; 1595 va_dcl 1596 #endif /* __STDC__ */ 1597 { 1598 size_t len = 0; 1599 SM_VA_LOCAL_DECL 1600 1601 (void) e_to_sys(errno); 1602 1603 SM_VA_START(ap, fmt); 1604 1605 if (LMTPMode && hdr != NULL) 1606 { 1607 sm_snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr); 1608 len = strlen(ErrBuf); 1609 } 1610 (void) sm_vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap); 1611 SM_VA_END(ap); 1612 1613 if (!HoldErrs) 1614 flush_error(); 1615 1616 /* Log the message to syslog. */ 1617 if (!LMTPMode) 1618 syslog(LOG_ERR, "%s", ErrBuf); 1619 } 1620 1621 void 1622 flush_error() 1623 { 1624 if (LMTPMode) 1625 printf("%s\r\n", ErrBuf); 1626 else 1627 { 1628 if (ExitVal != EX_USAGE) 1629 (void) fprintf(stderr, "mail.local: "); 1630 fprintf(stderr, "%s\n", ErrBuf); 1631 } 1632 } 1633 1634 #if HASHSPOOL 1635 const char * 1636 hashname(name) 1637 char *name; 1638 { 1639 static char p[MAXPATHLEN]; 1640 int i; 1641 int len; 1642 char *str; 1643 # if HASHSPOOLMD5 1644 char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_"; 1645 MD5_CTX ctx; 1646 unsigned char md5[18]; 1647 # if MAXPATHLEN <= 24 1648 ERROR _MAXPATHLEN <= 24 1649 # endif /* MAXPATHLEN <= 24 */ 1650 char b64[24]; 1651 MD5_LONG bits; 1652 int j; 1653 # endif /* HASHSPOOLMD5 */ 1654 1655 if (HashType == HASH_NONE || HashDepth * 2 >= MAXPATHLEN) 1656 { 1657 p[0] = '\0'; 1658 return p; 1659 } 1660 1661 switch(HashType) 1662 { 1663 case HASH_USER: 1664 str = name; 1665 break; 1666 1667 # if HASHSPOOLMD5 1668 case HASH_MD5: 1669 MD5_Init(&ctx); 1670 MD5_Update(&ctx, name, strlen(name)); 1671 MD5_Final(md5, &ctx); 1672 md5[16] = 0; 1673 md5[17] = 0; 1674 1675 for (i = 0; i < 6; i++) 1676 { 1677 bits = (unsigned) md5[(3 * i)] << 16; 1678 bits |= (unsigned) md5[(3 * i) + 1] << 8; 1679 bits |= (unsigned) md5[(3 * i) + 2]; 1680 1681 for (j = 3; j >= 0; j--) 1682 { 1683 b64[(4 * i) + j] = Base64[(bits & 0x3f)]; 1684 bits >>= 6; 1685 } 1686 } 1687 b64[22] = '\0'; 1688 str = b64; 1689 break; 1690 # endif /* HASHSPOOLMD5 */ 1691 } 1692 1693 len = strlen(str); 1694 for (i = 0; i < HashDepth; i++) 1695 { 1696 if (i < len) 1697 p[i * 2] = str[i]; 1698 else 1699 p[i * 2] = '_'; 1700 p[(i * 2) + 1] = '/'; 1701 } 1702 p[HashDepth * 2] = '\0'; 1703 return p; 1704 } 1705 #endif /* HASHSPOOL */ 1706 1707 /* 1708 * e_to_sys -- 1709 * Guess which errno's are temporary. Gag me. 1710 */ 1711 1712 int 1713 e_to_sys(num) 1714 int num; 1715 { 1716 /* Temporary failures override hard errors. */ 1717 if (ExitVal == EX_TEMPFAIL) 1718 return ExitVal; 1719 1720 switch (num) /* Hopefully temporary errors. */ 1721 { 1722 #ifdef EDQUOT 1723 case EDQUOT: /* Disc quota exceeded */ 1724 if (BounceQuota) 1725 { 1726 ExitVal = EX_UNAVAILABLE; 1727 break; 1728 } 1729 /* FALLTHROUGH */ 1730 #endif /* EDQUOT */ 1731 #ifdef EAGAIN 1732 case EAGAIN: /* Resource temporarily unavailable */ 1733 #endif /* EAGAIN */ 1734 #ifdef EBUSY 1735 case EBUSY: /* Device busy */ 1736 #endif /* EBUSY */ 1737 #ifdef EPROCLIM 1738 case EPROCLIM: /* Too many processes */ 1739 #endif /* EPROCLIM */ 1740 #ifdef EUSERS 1741 case EUSERS: /* Too many users */ 1742 #endif /* EUSERS */ 1743 #ifdef ECONNABORTED 1744 case ECONNABORTED: /* Software caused connection abort */ 1745 #endif /* ECONNABORTED */ 1746 #ifdef ECONNREFUSED 1747 case ECONNREFUSED: /* Connection refused */ 1748 #endif /* ECONNREFUSED */ 1749 #ifdef ECONNRESET 1750 case ECONNRESET: /* Connection reset by peer */ 1751 #endif /* ECONNRESET */ 1752 #ifdef EDEADLK 1753 case EDEADLK: /* Resource deadlock avoided */ 1754 #endif /* EDEADLK */ 1755 #ifdef EFBIG 1756 case EFBIG: /* File too large */ 1757 #endif /* EFBIG */ 1758 #ifdef EHOSTDOWN 1759 case EHOSTDOWN: /* Host is down */ 1760 #endif /* EHOSTDOWN */ 1761 #ifdef EHOSTUNREACH 1762 case EHOSTUNREACH: /* No route to host */ 1763 #endif /* EHOSTUNREACH */ 1764 #ifdef EMFILE 1765 case EMFILE: /* Too many open files */ 1766 #endif /* EMFILE */ 1767 #ifdef ENETDOWN 1768 case ENETDOWN: /* Network is down */ 1769 #endif /* ENETDOWN */ 1770 #ifdef ENETRESET 1771 case ENETRESET: /* Network dropped connection on reset */ 1772 #endif /* ENETRESET */ 1773 #ifdef ENETUNREACH 1774 case ENETUNREACH: /* Network is unreachable */ 1775 #endif /* ENETUNREACH */ 1776 #ifdef ENFILE 1777 case ENFILE: /* Too many open files in system */ 1778 #endif /* ENFILE */ 1779 #ifdef ENOBUFS 1780 case ENOBUFS: /* No buffer space available */ 1781 #endif /* ENOBUFS */ 1782 #ifdef ENOMEM 1783 case ENOMEM: /* Cannot allocate memory */ 1784 #endif /* ENOMEM */ 1785 #ifdef ENOSPC 1786 case ENOSPC: /* No space left on device */ 1787 #endif /* ENOSPC */ 1788 #ifdef EROFS 1789 case EROFS: /* Read-only file system */ 1790 #endif /* EROFS */ 1791 #ifdef ESTALE 1792 case ESTALE: /* Stale NFS file handle */ 1793 #endif /* ESTALE */ 1794 #ifdef ETIMEDOUT 1795 case ETIMEDOUT: /* Connection timed out */ 1796 #endif /* ETIMEDOUT */ 1797 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK 1798 case EWOULDBLOCK: /* Operation would block. */ 1799 #endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */ 1800 ExitVal = EX_TEMPFAIL; 1801 break; 1802 1803 default: 1804 ExitVal = EX_UNAVAILABLE; 1805 break; 1806 } 1807 return ExitVal; 1808 } 1809 1810 #if defined(ultrix) || defined(_CRAY) 1811 /* 1812 * Copyright (c) 1987, 1993 1813 * The Regents of the University of California. All rights reserved. 1814 * 1815 * Redistribution and use in source and binary forms, with or without 1816 * modification, are permitted provided that the following conditions 1817 * are met: 1818 * 1. Redistributions of source code must retain the above copyright 1819 * notice, this list of conditions and the following disclaimer. 1820 * 2. Redistributions in binary form must reproduce the above copyright 1821 * notice, this list of conditions and the following disclaimer in the 1822 * documentation and/or other materials provided with the distribution. 1823 * 3. All advertising materials mentioning features or use of this software 1824 * must display the following acknowledgement: 1825 * This product includes software developed by the University of 1826 * California, Berkeley and its contributors. 1827 * 4. Neither the name of the University nor the names of its contributors 1828 * may be used to endorse or promote products derived from this software 1829 * without specific prior written permission. 1830 * 1831 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1832 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1833 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1834 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1835 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1836 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1837 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1838 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1839 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1840 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1841 * SUCH DAMAGE. 1842 */ 1843 1844 # if defined(LIBC_SCCS) && !defined(lint) 1845 static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; 1846 # endif /* defined(LIBC_SCCS) && !defined(lint) */ 1847 1848 # include <sys/types.h> 1849 # include <sys/stat.h> 1850 # include <fcntl.h> 1851 # include <errno.h> 1852 # include <stdio.h> 1853 # include <ctype.h> 1854 1855 static int _gettemp(); 1856 1857 mkstemp(path) 1858 char *path; 1859 { 1860 int fd; 1861 1862 return (_gettemp(path, &fd) ? fd : -1); 1863 } 1864 1865 static 1866 _gettemp(path, doopen) 1867 char *path; 1868 register int *doopen; 1869 { 1870 extern int errno; 1871 register char *start, *trv; 1872 struct stat sbuf; 1873 unsigned int pid; 1874 1875 pid = getpid(); 1876 for (trv = path; *trv; ++trv); /* extra X's get set to 0's */ 1877 while (*--trv == 'X') 1878 { 1879 *trv = (pid % 10) + '0'; 1880 pid /= 10; 1881 } 1882 1883 /* 1884 * check the target directory; if you have six X's and it 1885 * doesn't exist this runs for a *very* long time. 1886 */ 1887 for (start = trv + 1;; --trv) 1888 { 1889 if (trv <= path) 1890 break; 1891 if (*trv == '/') 1892 { 1893 *trv = '\0'; 1894 if (stat(path, &sbuf) < 0) 1895 return(0); 1896 if (!S_ISDIR(sbuf.st_mode)) 1897 { 1898 errno = ENOTDIR; 1899 return(0); 1900 } 1901 *trv = '/'; 1902 break; 1903 } 1904 } 1905 1906 for (;;) 1907 { 1908 if (doopen) 1909 { 1910 if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR, 1911 0600)) >= 0) 1912 return(1); 1913 if (errno != EEXIST) 1914 return(0); 1915 } 1916 else if (stat(path, &sbuf) < 0) 1917 return(errno == ENOENT ? 1 : 0); 1918 1919 /* tricky little algorithm for backward compatibility */ 1920 for (trv = start;;) 1921 { 1922 if (!*trv) 1923 return(0); 1924 if (*trv == 'z') 1925 *trv++ = 'a'; 1926 else 1927 { 1928 if (isascii(*trv) && isdigit(*trv)) 1929 *trv = 'a'; 1930 else 1931 ++*trv; 1932 break; 1933 } 1934 } 1935 } 1936 /* NOTREACHED */ 1937 } 1938 #endif /* defined(ultrix) || defined(_CRAY) */ 1939