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