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