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