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