1 /* 2 * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #include <sendmail.h> 15 16 SM_RCSID("@(#)$Id: collect.c,v 8.237 2001/12/10 19:56:03 ca Exp $") 17 18 static void collecttimeout __P((time_t)); 19 static void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *)); 20 static void eatfrom __P((char *volatile, ENVELOPE *)); 21 static void collect_doheader __P((ENVELOPE *)); 22 static SM_FILE_T *collect_dfopen __P((ENVELOPE *)); 23 static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int)); 24 25 /* 26 ** COLLECT_EOH -- end-of-header processing in collect() 27 ** 28 ** Called by collect() when it encounters the blank line 29 ** separating the header from the message body, or when it 30 ** encounters EOF in a message that contains only a header. 31 ** 32 ** Parameters: 33 ** e -- envelope 34 ** numhdrs -- number of headers 35 ** hdrslen -- length of headers 36 ** 37 ** Results: 38 ** NULL, or handle to open data file 39 ** 40 ** Side Effects: 41 ** end-of-header check ruleset is invoked. 42 ** envelope state is updated. 43 ** headers may be added and deleted. 44 ** selects the queue. 45 ** opens the data file. 46 */ 47 48 static SM_FILE_T * 49 collect_eoh(e, numhdrs, hdrslen) 50 ENVELOPE *e; 51 int numhdrs; 52 int hdrslen; 53 { 54 char hnum[16]; 55 char hsize[16]; 56 57 /* call the end-of-header check ruleset */ 58 (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs); 59 (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen); 60 if (tTd(30, 10)) 61 sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 62 hnum, hsize); 63 (void) rscheck("check_eoh", hnum, hsize, e, false, true, 3, NULL, 64 e->e_id); 65 66 /* 67 ** Process the header, 68 ** select the queue, open the data file. 69 */ 70 71 collect_doheader(e); 72 return collect_dfopen(e); 73 } 74 75 /* 76 ** COLLECT_DOHEADER -- process header in collect() 77 ** 78 ** Called by collect() after it has finished parsing the header, 79 ** but before it selects the queue and creates the data file. 80 ** The results of processing the header will affect queue selection. 81 ** 82 ** Parameters: 83 ** e -- envelope 84 ** 85 ** Results: 86 ** none. 87 ** 88 ** Side Effects: 89 ** envelope state is updated. 90 ** headers may be added and deleted. 91 */ 92 93 static void 94 collect_doheader(e) 95 ENVELOPE *e; 96 { 97 /* 98 ** Find out some information from the headers. 99 ** Examples are who is the from person & the date. 100 */ 101 102 eatheader(e, true, false); 103 104 if (GrabTo && e->e_sendqueue == NULL) 105 usrerr("No recipient addresses found in header"); 106 107 /* collect statistics */ 108 if (OpMode != MD_VERIFY) 109 markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 110 111 /* 112 ** If we have a Return-Receipt-To:, turn it into a DSN. 113 */ 114 115 if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 116 { 117 ADDRESS *q; 118 119 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 120 if (!bitset(QHASNOTIFY, q->q_flags)) 121 q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 122 } 123 124 /* 125 ** Add an appropriate recipient line if we have none. 126 */ 127 128 if (hvalue("to", e->e_header) != NULL || 129 hvalue("cc", e->e_header) != NULL || 130 hvalue("apparently-to", e->e_header) != NULL) 131 { 132 /* have a valid recipient header -- delete Bcc: headers */ 133 e->e_flags |= EF_DELETE_BCC; 134 } 135 else if (hvalue("bcc", e->e_header) == NULL) 136 { 137 /* no valid recipient headers */ 138 register ADDRESS *q; 139 char *hdr = NULL; 140 141 /* create a recipient field */ 142 switch (NoRecipientAction) 143 { 144 case NRA_ADD_APPARENTLY_TO: 145 hdr = "Apparently-To"; 146 break; 147 148 case NRA_ADD_TO: 149 hdr = "To"; 150 break; 151 152 case NRA_ADD_BCC: 153 addheader("Bcc", " ", 0, e); 154 break; 155 156 case NRA_ADD_TO_UNDISCLOSED: 157 addheader("To", "undisclosed-recipients:;", 0, e); 158 break; 159 } 160 161 if (hdr != NULL) 162 { 163 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 164 { 165 if (q->q_alias != NULL) 166 continue; 167 if (tTd(30, 3)) 168 sm_dprintf("Adding %s: %s\n", 169 hdr, q->q_paddr); 170 addheader(hdr, q->q_paddr, 0, e); 171 } 172 } 173 } 174 } 175 176 /* 177 ** COLLECT_DFOPEN -- open the message data file 178 ** 179 ** Called by collect() after it has finished processing the header. 180 ** Queue selection occurs at this point, possibly based on the 181 ** envelope's recipient list and on header information. 182 ** 183 ** Parameters: 184 ** e -- envelope 185 ** 186 ** Results: 187 ** NULL, or a pointer to an open data file, 188 ** into which the message body will be written by collect(). 189 ** 190 ** Side Effects: 191 ** Calls syserr, sets EF_FATALERRS and returns NULL 192 ** if there is insufficient disk space. 193 ** Aborts process if data file could not be opened. 194 ** Otherwise, the queue is selected, 195 ** e->e_{dfino,dfdev,msgsize,flags} are updated, 196 ** and a pointer to an open data file is returned. 197 */ 198 199 static SM_FILE_T * 200 collect_dfopen(e) 201 ENVELOPE *e; 202 { 203 MODE_T oldumask = 0; 204 int dfd; 205 struct stat stbuf; 206 SM_FILE_T *df; 207 char *dfname; 208 209 if (!setnewqueue(e)) 210 return NULL; 211 212 dfname = queuename(e, DATAFL_LETTER); 213 if (bitset(S_IWGRP, QueueFileMode)) 214 oldumask = umask(002); 215 df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 216 SFF_OPENASROOT); 217 if (bitset(S_IWGRP, QueueFileMode)) 218 (void) umask(oldumask); 219 if (df == NULL) 220 { 221 syserr("@Cannot create %s", dfname); 222 e->e_flags |= EF_NO_BODY_RETN; 223 flush_errors(true); 224 finis(true, true, ExitStat); 225 /* NOTREACHED */ 226 } 227 dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 228 if (dfd < 0 || fstat(dfd, &stbuf) < 0) 229 e->e_dfino = -1; 230 else 231 { 232 e->e_dfdev = stbuf.st_dev; 233 e->e_dfino = stbuf.st_ino; 234 } 235 e->e_flags |= EF_HAS_DF; 236 return df; 237 } 238 239 /* 240 ** COLLECT -- read & parse message header & make temp file. 241 ** 242 ** Creates a temporary file name and copies the standard 243 ** input to that file. Leading UNIX-style "From" lines are 244 ** stripped off (after important information is extracted). 245 ** 246 ** Parameters: 247 ** fp -- file to read. 248 ** smtpmode -- if set, we are running SMTP: give an RFC821 249 ** style message to say we are ready to collect 250 ** input, and never ignore a single dot to mean 251 ** end of message. 252 ** hdrp -- the location to stash the header. 253 ** e -- the current envelope. 254 ** 255 ** Returns: 256 ** none. 257 ** 258 ** Side Effects: 259 ** If successful, 260 ** - Data file is created and filled, and e->e_dfp is set. 261 ** - The from person may be set. 262 ** If the "enough disk space" check fails, 263 ** - syserr is called. 264 ** - e->e_dfp is NULL. 265 ** - e->e_flags & EF_FATALERRS is set. 266 ** - collect() returns. 267 ** If data file cannot be created, the process is terminated. 268 */ 269 270 static jmp_buf CtxCollectTimeout; 271 static bool volatile CollectProgress; 272 static SM_EVENT *volatile CollectTimeout = NULL; 273 274 /* values for input state machine */ 275 #define IS_NORM 0 /* middle of line */ 276 #define IS_BOL 1 /* beginning of line */ 277 #define IS_DOT 2 /* read a dot at beginning of line */ 278 #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 279 #define IS_CR 4 /* read a carriage return */ 280 281 /* values for message state machine */ 282 #define MS_UFROM 0 /* reading Unix from line */ 283 #define MS_HEADER 1 /* reading message header */ 284 #define MS_BODY 2 /* reading message body */ 285 #define MS_DISCARD 3 /* discarding rest of message */ 286 287 void 288 collect(fp, smtpmode, hdrp, e) 289 SM_FILE_T *fp; 290 bool smtpmode; 291 HDR **hdrp; 292 register ENVELOPE *e; 293 { 294 register SM_FILE_T *volatile df; 295 volatile bool ignrdot; 296 volatile time_t dbto; 297 register char *volatile bp; 298 volatile int c; 299 volatile bool inputerr; 300 bool headeronly; 301 char *volatile buf; 302 volatile int buflen; 303 volatile int istate; 304 volatile int mstate; 305 volatile int hdrslen; 306 volatile int numhdrs; 307 volatile int afd; 308 unsigned char *volatile pbp; 309 unsigned char peekbuf[8]; 310 char bufbuf[MAXLINE]; 311 312 df = NULL; 313 ignrdot = smtpmode ? false : IgnrDot; 314 dbto = smtpmode ? TimeOuts.to_datablock : 0; 315 c = SM_IO_EOF; 316 inputerr = false; 317 headeronly = hdrp != NULL; 318 hdrslen = 0; 319 numhdrs = 0; 320 HasEightBits = false; 321 buf = bp = bufbuf; 322 buflen = sizeof bufbuf; 323 pbp = peekbuf; 324 istate = IS_BOL; 325 mstate = SaveFrom ? MS_HEADER : MS_UFROM; 326 CollectProgress = false; 327 328 /* 329 ** Tell ARPANET to go ahead. 330 */ 331 332 if (smtpmode) 333 message("354 Enter mail, end with \".\" on a line by itself"); 334 335 if (tTd(30, 2)) 336 sm_dprintf("collect\n"); 337 338 /* 339 ** Read the message. 340 ** 341 ** This is done using two interleaved state machines. 342 ** The input state machine is looking for things like 343 ** hidden dots; the message state machine is handling 344 ** the larger picture (e.g., header versus body). 345 */ 346 347 if (dbto != 0) 348 { 349 /* handle possible input timeout */ 350 if (setjmp(CtxCollectTimeout) != 0) 351 { 352 if (LogLevel > 2) 353 sm_syslog(LOG_NOTICE, e->e_id, 354 "timeout waiting for input from %s during message collect", 355 CURHOSTNAME); 356 errno = 0; 357 usrerr("451 4.4.1 timeout waiting for input during message collect"); 358 goto readerr; 359 } 360 CollectTimeout = sm_setevent(dbto, collecttimeout, dbto); 361 } 362 363 e->e_msgsize = 0; 364 for (;;) 365 { 366 if (tTd(30, 35)) 367 sm_dprintf("top, istate=%d, mstate=%d\n", istate, 368 mstate); 369 for (;;) 370 { 371 if (pbp > peekbuf) 372 c = *--pbp; 373 else 374 { 375 while (!sm_io_eof(fp) && !sm_io_error(fp)) 376 { 377 errno = 0; 378 c = sm_io_getc(fp, SM_TIME_DEFAULT); 379 if (c == SM_IO_EOF && errno == EINTR) 380 { 381 /* Interrupted, retry */ 382 sm_io_clearerr(fp); 383 continue; 384 } 385 break; 386 } 387 CollectProgress = true; 388 if (TrafficLogFile != NULL && !headeronly) 389 { 390 if (istate == IS_BOL) 391 (void) sm_io_fprintf(TrafficLogFile, 392 SM_TIME_DEFAULT, 393 "%05d <<< ", 394 (int) CurrentPid); 395 if (c == SM_IO_EOF) 396 (void) sm_io_fprintf(TrafficLogFile, 397 SM_TIME_DEFAULT, 398 "[EOF]\n"); 399 else 400 (void) sm_io_putc(TrafficLogFile, 401 SM_TIME_DEFAULT, 402 c); 403 } 404 if (c == SM_IO_EOF) 405 goto readerr; 406 if (SevenBitInput) 407 c &= 0x7f; 408 else 409 HasEightBits |= bitset(0x80, c); 410 } 411 if (tTd(30, 94)) 412 sm_dprintf("istate=%d, c=%c (0x%x)\n", 413 istate, (char) c, c); 414 switch (istate) 415 { 416 case IS_BOL: 417 if (c == '.') 418 { 419 istate = IS_DOT; 420 continue; 421 } 422 break; 423 424 case IS_DOT: 425 if (c == '\n' && !ignrdot && 426 !bitset(EF_NL_NOT_EOL, e->e_flags)) 427 goto readerr; 428 else if (c == '\r' && 429 !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 430 { 431 istate = IS_DOTCR; 432 continue; 433 } 434 else if (c != '.' || 435 (OpMode != MD_SMTP && 436 OpMode != MD_DAEMON && 437 OpMode != MD_ARPAFTP)) 438 { 439 *pbp++ = c; 440 c = '.'; 441 } 442 break; 443 444 case IS_DOTCR: 445 if (c == '\n' && !ignrdot) 446 goto readerr; 447 else 448 { 449 /* push back the ".\rx" */ 450 *pbp++ = c; 451 *pbp++ = '\r'; 452 c = '.'; 453 } 454 break; 455 456 case IS_CR: 457 if (c == '\n') 458 istate = IS_BOL; 459 else 460 { 461 (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 462 c); 463 c = '\r'; 464 istate = IS_NORM; 465 } 466 goto bufferchar; 467 } 468 469 if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 470 { 471 istate = IS_CR; 472 continue; 473 } 474 else if (c == '\n' && !bitset(EF_NL_NOT_EOL, 475 e->e_flags)) 476 istate = IS_BOL; 477 else 478 istate = IS_NORM; 479 480 bufferchar: 481 if (!headeronly) 482 { 483 /* no overflow? */ 484 if (e->e_msgsize >= 0) 485 { 486 e->e_msgsize++; 487 if (MaxMessageSize > 0 && 488 !bitset(EF_TOOBIG, e->e_flags) && 489 e->e_msgsize > MaxMessageSize) 490 e->e_flags |= EF_TOOBIG; 491 } 492 } 493 switch (mstate) 494 { 495 case MS_BODY: 496 /* just put the character out */ 497 if (!bitset(EF_TOOBIG, e->e_flags)) 498 (void) sm_io_putc(df, SM_TIME_DEFAULT, 499 c); 500 501 /* FALLTHROUGH */ 502 503 case MS_DISCARD: 504 continue; 505 } 506 507 /* header -- buffer up */ 508 if (bp >= &buf[buflen - 2]) 509 { 510 char *obuf; 511 512 if (mstate != MS_HEADER) 513 break; 514 515 /* out of space for header */ 516 obuf = buf; 517 if (buflen < MEMCHUNKSIZE) 518 buflen *= 2; 519 else 520 buflen += MEMCHUNKSIZE; 521 buf = xalloc(buflen); 522 memmove(buf, obuf, bp - obuf); 523 bp = &buf[bp - obuf]; 524 if (obuf != bufbuf) 525 sm_free(obuf); /* XXX */ 526 } 527 528 /* 529 ** XXX Notice: the logic here is broken. 530 ** An input to sendmail that doesn't contain a 531 ** header but starts immediately with the body whose 532 ** first line contain characters which match the 533 ** following "if" will cause problems: those 534 ** characters will NOT appear in the output... 535 ** Do we care? 536 */ 537 538 if (c >= 0200 && c <= 0237) 539 { 540 #if 0 /* causes complaints -- figure out something for 8.n+1 */ 541 usrerr("Illegal character 0x%x in header", c); 542 #else /* 0 */ 543 /* EMPTY */ 544 #endif /* 0 */ 545 } 546 else if (c != '\0') 547 { 548 *bp++ = c; 549 ++hdrslen; 550 if (!headeronly && 551 MaxHeadersLength > 0 && 552 hdrslen > MaxHeadersLength) 553 { 554 sm_syslog(LOG_NOTICE, e->e_id, 555 "headers too large (%d max) from %s during message collect", 556 MaxHeadersLength, 557 CURHOSTNAME); 558 errno = 0; 559 e->e_flags |= EF_CLRQUEUE; 560 e->e_status = "5.6.0"; 561 usrerrenh(e->e_status, 562 "552 Headers too large (%d max)", 563 MaxHeadersLength); 564 mstate = MS_DISCARD; 565 } 566 } 567 if (istate == IS_BOL) 568 break; 569 } 570 *bp = '\0'; 571 572 nextstate: 573 if (tTd(30, 35)) 574 sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 575 istate, mstate, buf); 576 switch (mstate) 577 { 578 case MS_UFROM: 579 mstate = MS_HEADER; 580 #ifndef NOTUNIX 581 if (strncmp(buf, "From ", 5) == 0) 582 { 583 bp = buf; 584 eatfrom(buf, e); 585 continue; 586 } 587 #endif /* ! NOTUNIX */ 588 /* FALLTHROUGH */ 589 590 case MS_HEADER: 591 if (!isheader(buf)) 592 { 593 mstate = MS_BODY; 594 goto nextstate; 595 } 596 597 /* check for possible continuation line */ 598 do 599 { 600 sm_io_clearerr(fp); 601 errno = 0; 602 c = sm_io_getc(fp, SM_TIME_DEFAULT); 603 } while (c == SM_IO_EOF && errno == EINTR); 604 if (c != SM_IO_EOF) 605 (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 606 if (c == ' ' || c == '\t') 607 { 608 /* yep -- defer this */ 609 continue; 610 } 611 612 /* trim off trailing CRLF or NL */ 613 if (*--bp != '\n' || *--bp != '\r') 614 bp++; 615 *bp = '\0'; 616 617 if (bitset(H_EOH, chompheader(buf, 618 CHHDR_CHECK | CHHDR_USER, 619 hdrp, e))) 620 { 621 mstate = MS_BODY; 622 goto nextstate; 623 } 624 numhdrs++; 625 break; 626 627 case MS_BODY: 628 if (tTd(30, 1)) 629 sm_dprintf("EOH\n"); 630 631 if (headeronly) 632 goto readerr; 633 634 df = collect_eoh(e, numhdrs, hdrslen); 635 if (df == NULL) 636 e->e_flags |= EF_TOOBIG; 637 638 bp = buf; 639 640 /* toss blank line */ 641 if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 642 bp[0] == '\r' && bp[1] == '\n') || 643 (!bitset(EF_NL_NOT_EOL, e->e_flags) && 644 bp[0] == '\n')) 645 { 646 break; 647 } 648 649 /* if not a blank separator, write it out */ 650 if (!bitset(EF_TOOBIG, e->e_flags)) 651 { 652 while (*bp != '\0') 653 (void) sm_io_putc(df, SM_TIME_DEFAULT, 654 *bp++); 655 } 656 break; 657 } 658 bp = buf; 659 } 660 661 readerr: 662 if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 663 { 664 const char *errmsg; 665 666 if (sm_io_eof(fp)) 667 errmsg = "unexpected close"; 668 else 669 errmsg = sm_errstring(errno); 670 if (tTd(30, 1)) 671 sm_dprintf("collect: premature EOM: %s\n", errmsg); 672 if (LogLevel > 1) 673 sm_syslog(LOG_WARNING, e->e_id, 674 "collect: premature EOM: %s", errmsg); 675 inputerr = true; 676 } 677 678 /* reset global timer */ 679 if (CollectTimeout != NULL) 680 sm_clrevent(CollectTimeout); 681 682 if (headeronly) 683 return; 684 685 if (mstate != MS_BODY) 686 { 687 /* no body or discard, so we never opened the data file */ 688 SM_ASSERT(df == NULL); 689 df = collect_eoh(e, numhdrs, hdrslen); 690 } 691 692 if (df == NULL) 693 { 694 /* skip next few clauses */ 695 /* EMPTY */ 696 } 697 else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 698 { 699 dferror(df, "sm_io_flush||sm_io_error", e); 700 flush_errors(true); 701 finis(true, true, ExitStat); 702 /* NOTREACHED */ 703 } 704 else if (SuperSafe != SAFE_REALLY) 705 { 706 /* skip next few clauses */ 707 /* EMPTY */ 708 } 709 else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) 710 { 711 int save_errno = errno; 712 713 if (save_errno == EEXIST) 714 { 715 char *dfile; 716 struct stat st; 717 int dfd; 718 719 dfile = queuename(e, DATAFL_LETTER); 720 if (stat(dfile, &st) < 0) 721 st.st_size = -1; 722 errno = EEXIST; 723 syserr("@collect: bfcommit(%s): already on disk, size = %ld", 724 dfile, (long) st.st_size); 725 dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 726 if (dfd >= 0) 727 dumpfd(dfd, true, true); 728 } 729 errno = save_errno; 730 dferror(df, "bfcommit", e); 731 flush_errors(true); 732 finis(save_errno != EEXIST, true, ExitStat); 733 } 734 else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 && 735 fsync(afd) < 0) 736 { 737 dferror(df, "fsync", e); 738 flush_errors(true); 739 finis(true, true, ExitStat); 740 /* NOTREACHED */ 741 } 742 else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 743 { 744 dferror(df, "sm_io_close", e); 745 flush_errors(true); 746 finis(true, true, ExitStat); 747 /* NOTREACHED */ 748 } 749 else 750 { 751 /* everything is happily flushed to disk */ 752 df = NULL; 753 754 /* remove from available space in filesystem */ 755 updfs(e, false, true); 756 } 757 758 /* An EOF when running SMTP is an error */ 759 if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 760 { 761 char *host; 762 char *problem; 763 764 host = RealHostName; 765 if (host == NULL) 766 host = "localhost"; 767 768 if (sm_io_eof(fp)) 769 problem = "unexpected close"; 770 else if (sm_io_error(fp)) 771 problem = "I/O error"; 772 else 773 problem = "read timeout"; 774 if (LogLevel > 0 && sm_io_eof(fp)) 775 sm_syslog(LOG_NOTICE, e->e_id, 776 "collect: %s on connection from %.100s, sender=%s", 777 problem, host, 778 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 779 if (sm_io_eof(fp)) 780 usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 781 problem, host, 782 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 783 else 784 syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 785 problem, host, 786 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 787 788 /* don't return an error indication */ 789 e->e_to = NULL; 790 e->e_flags &= ~EF_FATALERRS; 791 e->e_flags |= EF_CLRQUEUE; 792 793 finis(true, true, ExitStat); 794 /* NOTREACHED */ 795 } 796 797 /* Log collection information. */ 798 if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 799 { 800 logsender(e, e->e_msgid); 801 e->e_flags &= ~EF_LOGSENDER; 802 } 803 804 /* check for message too large */ 805 if (bitset(EF_TOOBIG, e->e_flags)) 806 { 807 e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 808 if (!bitset(EF_FATALERRS, e->e_flags)) 809 { 810 e->e_status = "5.2.3"; 811 usrerrenh(e->e_status, 812 "552 Message exceeds maximum fixed size (%ld)", 813 MaxMessageSize); 814 if (LogLevel > 6) 815 sm_syslog(LOG_NOTICE, e->e_id, 816 "message size (%ld) exceeds maximum (%ld)", 817 e->e_msgsize, MaxMessageSize); 818 } 819 } 820 821 /* check for illegal 8-bit data */ 822 if (HasEightBits) 823 { 824 e->e_flags |= EF_HAS8BIT; 825 if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 826 !bitset(EF_IS_MIME, e->e_flags)) 827 { 828 e->e_status = "5.6.1"; 829 usrerrenh(e->e_status, "554 Eight bit data not allowed"); 830 } 831 } 832 else 833 { 834 /* if it claimed to be 8 bits, well, it lied.... */ 835 if (e->e_bodytype != NULL && 836 sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 837 e->e_bodytype = "7BIT"; 838 } 839 840 if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 841 { 842 char *dfname = queuename(e, DATAFL_LETTER); 843 if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 844 SM_IO_RDONLY, NULL)) == NULL) 845 { 846 /* we haven't acked receipt yet, so just chuck this */ 847 syserr("@Cannot reopen %s", dfname); 848 finis(true, true, ExitStat); 849 /* NOTREACHED */ 850 } 851 } 852 else 853 e->e_dfp = df; 854 } 855 856 static void 857 collecttimeout(timeout) 858 time_t timeout; 859 { 860 int save_errno = errno; 861 862 /* 863 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 864 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 865 ** DOING. 866 */ 867 868 if (CollectProgress) 869 { 870 /* reset the timeout */ 871 CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout, 872 timeout); 873 CollectProgress = false; 874 } 875 else 876 { 877 /* event is done */ 878 CollectTimeout = NULL; 879 } 880 881 /* if no progress was made or problem resetting event, die now */ 882 if (CollectTimeout == NULL) 883 { 884 errno = ETIMEDOUT; 885 longjmp(CtxCollectTimeout, 1); 886 } 887 errno = save_errno; 888 } 889 /* 890 ** DFERROR -- signal error on writing the data file. 891 ** 892 ** Called by collect(). Collect() always terminates the process 893 ** immediately after calling dferror(), which means that the SMTP 894 ** session will be terminated, which means that any error message 895 ** issued by dferror must be a 421 error, as per RFC 821. 896 ** 897 ** Parameters: 898 ** df -- the file pointer for the data file. 899 ** msg -- detailed message. 900 ** e -- the current envelope. 901 ** 902 ** Returns: 903 ** none. 904 ** 905 ** Side Effects: 906 ** Gives an error message. 907 ** Arranges for following output to go elsewhere. 908 */ 909 910 static void 911 dferror(df, msg, e) 912 SM_FILE_T *volatile df; 913 char *msg; 914 register ENVELOPE *e; 915 { 916 char *dfname; 917 918 dfname = queuename(e, DATAFL_LETTER); 919 setstat(EX_IOERR); 920 if (errno == ENOSPC) 921 { 922 #if STAT64 > 0 923 struct stat64 st; 924 #else /* STAT64 > 0 */ 925 struct stat st; 926 #endif /* STAT64 > 0 */ 927 long avail; 928 long bsize; 929 930 e->e_flags |= EF_NO_BODY_RETN; 931 932 if ( 933 #if STAT64 > 0 934 fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 935 #else /* STAT64 > 0 */ 936 fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 937 #endif /* STAT64 > 0 */ 938 < 0) 939 st.st_size = 0; 940 (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 941 SM_IO_WRONLY, NULL, df); 942 if (st.st_size <= 0) 943 (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 944 "\n*** Mail could not be accepted"); 945 else 946 (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 947 "\n*** Mail of at least %llu bytes could not be accepted\n", 948 (ULONGLONG_T) st.st_size); 949 (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 950 "*** at %s due to lack of disk space for temp file.\n", 951 MyHostName); 952 avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 953 &bsize); 954 if (avail > 0) 955 { 956 if (bsize > 1024) 957 avail *= bsize / 1024; 958 else if (bsize < 1024) 959 avail /= 1024 / bsize; 960 (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 961 "*** Currently, %ld kilobytes are available for mail temp files.\n", 962 avail); 963 } 964 #if 0 965 /* Wrong response code; should be 421. */ 966 e->e_status = "4.3.1"; 967 usrerrenh(e->e_status, "452 Out of disk space for temp file"); 968 #else /* 0 */ 969 syserr("421 4.3.1 Out of disk space for temp file"); 970 #endif /* 0 */ 971 } 972 else 973 syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", 974 dfname, msg, geteuid(), getegid()); 975 if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 976 SM_IO_WRONLY, NULL, df) == NULL) 977 sm_syslog(LOG_ERR, e->e_id, 978 "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 979 sm_errstring(errno)); 980 } 981 /* 982 ** EATFROM -- chew up a UNIX style from line and process 983 ** 984 ** This does indeed make some assumptions about the format 985 ** of UNIX messages. 986 ** 987 ** Parameters: 988 ** fm -- the from line. 989 ** 990 ** Returns: 991 ** none. 992 ** 993 ** Side Effects: 994 ** extracts what information it can from the header, 995 ** such as the date. 996 */ 997 998 #ifndef NOTUNIX 999 1000 static char *DowList[] = 1001 { 1002 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 1003 }; 1004 1005 static char *MonthList[] = 1006 { 1007 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1008 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 1009 NULL 1010 }; 1011 1012 static void 1013 eatfrom(fm, e) 1014 char *volatile fm; 1015 register ENVELOPE *e; 1016 { 1017 register char *p; 1018 register char **dt; 1019 1020 if (tTd(30, 2)) 1021 sm_dprintf("eatfrom(%s)\n", fm); 1022 1023 /* find the date part */ 1024 p = fm; 1025 while (*p != '\0') 1026 { 1027 /* skip a word */ 1028 while (*p != '\0' && *p != ' ') 1029 p++; 1030 while (*p == ' ') 1031 p++; 1032 if (strlen(p) < 17) 1033 { 1034 /* no room for the date */ 1035 return; 1036 } 1037 if (!(isascii(*p) && isupper(*p)) || 1038 p[3] != ' ' || p[13] != ':' || p[16] != ':') 1039 continue; 1040 1041 /* we have a possible date */ 1042 for (dt = DowList; *dt != NULL; dt++) 1043 if (strncmp(*dt, p, 3) == 0) 1044 break; 1045 if (*dt == NULL) 1046 continue; 1047 1048 for (dt = MonthList; *dt != NULL; dt++) 1049 { 1050 if (strncmp(*dt, &p[4], 3) == 0) 1051 break; 1052 } 1053 if (*dt != NULL) 1054 break; 1055 } 1056 1057 if (*p != '\0') 1058 { 1059 char *q, buf[25]; 1060 1061 /* we have found a date */ 1062 (void) sm_strlcpy(buf, p, sizeof(buf)); 1063 q = arpadate(buf); 1064 macdefine(&e->e_macro, A_TEMP, 'a', q); 1065 } 1066 } 1067 #endif /* ! NOTUNIX */ 1068