collect.c revision 73188
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#ifndef lint 15static char id[] = "@(#)$Id: collect.c,v 8.136.4.15 2001/02/21 01:05:59 gshapiro Exp $"; 16#endif /* ! lint */ 17 18#include <sendmail.h> 19 20 21static void collecttimeout __P((time_t)); 22static void dferror __P((FILE *volatile, char *, ENVELOPE *)); 23static void eatfrom __P((char *volatile, ENVELOPE *)); 24 25/* 26** COLLECT -- read & parse message header & make temp file. 27** 28** Creates a temporary file name and copies the standard 29** input to that file. Leading UNIX-style "From" lines are 30** stripped off (after important information is extracted). 31** 32** Parameters: 33** fp -- file to read. 34** smtpmode -- if set, we are running SMTP: give an RFC821 35** style message to say we are ready to collect 36** input, and never ignore a single dot to mean 37** end of message. 38** hdrp -- the location to stash the header. 39** e -- the current envelope. 40** 41** Returns: 42** none. 43** 44** Side Effects: 45** Temp file is created and filled. 46** The from person may be set. 47*/ 48 49static jmp_buf CtxCollectTimeout; 50static bool CollectProgress; 51static EVENT *CollectTimeout; 52 53/* values for input state machine */ 54#define IS_NORM 0 /* middle of line */ 55#define IS_BOL 1 /* beginning of line */ 56#define IS_DOT 2 /* read a dot at beginning of line */ 57#define IS_DOTCR 3 /* read ".\r" at beginning of line */ 58#define IS_CR 4 /* read a carriage return */ 59 60/* values for message state machine */ 61#define MS_UFROM 0 /* reading Unix from line */ 62#define MS_HEADER 1 /* reading message header */ 63#define MS_BODY 2 /* reading message body */ 64#define MS_DISCARD 3 /* discarding rest of message */ 65 66void 67collect(fp, smtpmode, hdrp, e) 68 FILE *fp; 69 bool smtpmode; 70 HDR **hdrp; 71 register ENVELOPE *e; 72{ 73 register FILE *volatile df; 74 volatile bool ignrdot = smtpmode ? FALSE : IgnrDot; 75 volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; 76 register char *volatile bp; 77 volatile int c = EOF; 78 volatile bool inputerr = FALSE; 79 bool headeronly; 80 char *volatile buf; 81 volatile int buflen; 82 volatile int istate; 83 volatile int mstate; 84 volatile int hdrslen = 0; 85 volatile int numhdrs = 0; 86 volatile int dfd; 87 volatile int rstat = EX_OK; 88 u_char *volatile pbp; 89 u_char peekbuf[8]; 90 char hsize[16]; 91 char hnum[16]; 92 char dfname[MAXPATHLEN]; 93 char bufbuf[MAXLINE]; 94 95 headeronly = hdrp != NULL; 96 97 /* 98 ** Create the temp file name and create the file. 99 */ 100 101 if (!headeronly) 102 { 103 struct stat stbuf; 104 long sff = SFF_OPENASROOT; 105 106 107 (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); 108#if _FFR_QUEUE_FILE_MODE 109 { 110 MODE_T oldumask; 111 112 if (bitset(S_IWGRP, QueueFileMode)) 113 oldumask = umask(002); 114 df = bfopen(dfname, QueueFileMode, 115 DataFileBufferSize, sff); 116 if (bitset(S_IWGRP, QueueFileMode)) 117 (void) umask(oldumask); 118 } 119#else /* _FFR_QUEUE_FILE_MODE */ 120 df = bfopen(dfname, FileMode, DataFileBufferSize, sff); 121#endif /* _FFR_QUEUE_FILE_MODE */ 122 if (df == NULL) 123 { 124 HoldErrs = FALSE; 125 if (smtpmode) 126 syserr("421 4.3.5 Unable to create data file"); 127 else 128 syserr("Cannot create %s", dfname); 129 e->e_flags |= EF_NO_BODY_RETN; 130 finis(TRUE, ExitStat); 131 /* NOTREACHED */ 132 } 133 dfd = fileno(df); 134 if (dfd < 0 || fstat(dfd, &stbuf) < 0) 135 e->e_dfino = -1; 136 else 137 { 138 e->e_dfdev = stbuf.st_dev; 139 e->e_dfino = stbuf.st_ino; 140 } 141 HasEightBits = FALSE; 142 e->e_msgsize = 0; 143 e->e_flags |= EF_HAS_DF; 144 } 145 146 /* 147 ** Tell ARPANET to go ahead. 148 */ 149 150 if (smtpmode) 151 message("354 Enter mail, end with \".\" on a line by itself"); 152 153 if (tTd(30, 2)) 154 dprintf("collect\n"); 155 156 /* 157 ** Read the message. 158 ** 159 ** This is done using two interleaved state machines. 160 ** The input state machine is looking for things like 161 ** hidden dots; the message state machine is handling 162 ** the larger picture (e.g., header versus body). 163 */ 164 165 buf = bp = bufbuf; 166 buflen = sizeof bufbuf; 167 pbp = peekbuf; 168 istate = IS_BOL; 169 mstate = SaveFrom ? MS_HEADER : MS_UFROM; 170 CollectProgress = FALSE; 171 172 if (dbto != 0) 173 { 174 /* handle possible input timeout */ 175 if (setjmp(CtxCollectTimeout) != 0) 176 { 177 if (LogLevel > 2) 178 sm_syslog(LOG_NOTICE, e->e_id, 179 "timeout waiting for input from %s during message collect", 180 CurHostName ? CurHostName : "<local machine>"); 181 errno = 0; 182 usrerr("451 4.4.1 timeout waiting for input during message collect"); 183 goto readerr; 184 } 185 CollectTimeout = setevent(dbto, collecttimeout, dbto); 186 } 187 188 for (;;) 189 { 190 if (tTd(30, 35)) 191 dprintf("top, istate=%d, mstate=%d\n", istate, mstate); 192 for (;;) 193 { 194 if (pbp > peekbuf) 195 c = *--pbp; 196 else 197 { 198 while (!feof(fp) && !ferror(fp)) 199 { 200 errno = 0; 201 c = getc(fp); 202 203 if (c == EOF && errno == EINTR) 204 { 205 /* Interrupted, retry */ 206 clearerr(fp); 207 continue; 208 } 209 break; 210 } 211 CollectProgress = TRUE; 212 if (TrafficLogFile != NULL && !headeronly) 213 { 214 if (istate == IS_BOL) 215 (void) fprintf(TrafficLogFile, "%05d <<< ", 216 (int) getpid()); 217 if (c == EOF) 218 (void) fprintf(TrafficLogFile, "[EOF]\n"); 219 else 220 (void) putc(c, TrafficLogFile); 221 } 222 if (c == EOF) 223 goto readerr; 224 if (SevenBitInput) 225 c &= 0x7f; 226 else 227 HasEightBits |= bitset(0x80, c); 228 } 229 if (tTd(30, 94)) 230 dprintf("istate=%d, c=%c (0x%x)\n", 231 istate, (char) c, c); 232 switch (istate) 233 { 234 case IS_BOL: 235 if (c == '.') 236 { 237 istate = IS_DOT; 238 continue; 239 } 240 break; 241 242 case IS_DOT: 243 if (c == '\n' && !ignrdot && 244 !bitset(EF_NL_NOT_EOL, e->e_flags)) 245 goto readerr; 246 else if (c == '\r' && 247 !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 248 { 249 istate = IS_DOTCR; 250 continue; 251 } 252 else if (c != '.' || 253 (OpMode != MD_SMTP && 254 OpMode != MD_DAEMON && 255 OpMode != MD_ARPAFTP)) 256 { 257 *pbp++ = c; 258 c = '.'; 259 } 260 break; 261 262 case IS_DOTCR: 263 if (c == '\n' && !ignrdot) 264 goto readerr; 265 else 266 { 267 /* push back the ".\rx" */ 268 *pbp++ = c; 269 *pbp++ = '\r'; 270 c = '.'; 271 } 272 break; 273 274 case IS_CR: 275 if (c == '\n') 276 istate = IS_BOL; 277 else 278 { 279 (void) ungetc(c, fp); 280 c = '\r'; 281 istate = IS_NORM; 282 } 283 goto bufferchar; 284 } 285 286 if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 287 { 288 istate = IS_CR; 289 continue; 290 } 291 else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 292 istate = IS_BOL; 293 else 294 istate = IS_NORM; 295 296bufferchar: 297 if (!headeronly) 298 { 299 /* no overflow? */ 300 if (e->e_msgsize >= 0) 301 { 302 e->e_msgsize++; 303 if (MaxMessageSize > 0 && 304 !bitset(EF_TOOBIG, e->e_flags) && 305 e->e_msgsize > MaxMessageSize) 306 e->e_flags |= EF_TOOBIG; 307 } 308 } 309 switch (mstate) 310 { 311 case MS_BODY: 312 /* just put the character out */ 313 if (!bitset(EF_TOOBIG, e->e_flags)) 314 (void) putc(c, df); 315 316 /* FALLTHROUGH */ 317 318 case MS_DISCARD: 319 continue; 320 } 321 322 /* header -- buffer up */ 323 if (bp >= &buf[buflen - 2]) 324 { 325 char *obuf; 326 327 if (mstate != MS_HEADER) 328 break; 329 330 /* out of space for header */ 331 obuf = buf; 332 if (buflen < MEMCHUNKSIZE) 333 buflen *= 2; 334 else 335 buflen += MEMCHUNKSIZE; 336 buf = xalloc(buflen); 337 memmove(buf, obuf, bp - obuf); 338 bp = &buf[bp - obuf]; 339 if (obuf != bufbuf) 340 free(obuf); 341 } 342 if (c >= 0200 && c <= 0237) 343 { 344#if 0 /* causes complaints -- figure out something for 8.11 */ 345 usrerr("Illegal character 0x%x in header", c); 346#else /* 0 */ 347 /* EMPTY */ 348#endif /* 0 */ 349 } 350 else if (c != '\0') 351 { 352 *bp++ = c; 353 hdrslen++; 354 if (MaxHeadersLength > 0 && 355 hdrslen > MaxHeadersLength) 356 { 357 sm_syslog(LOG_NOTICE, e->e_id, 358 "headers too large (%d max) from %s during message collect", 359 MaxHeadersLength, 360 CurHostName != NULL ? CurHostName : "localhost"); 361 errno = 0; 362 e->e_flags |= EF_CLRQUEUE; 363 e->e_status = "5.6.0"; 364 usrerrenh(e->e_status, 365 "552 Headers too large (%d max)", 366 MaxHeadersLength); 367 mstate = MS_DISCARD; 368 } 369 } 370 if (istate == IS_BOL) 371 break; 372 } 373 *bp = '\0'; 374 375nextstate: 376 if (tTd(30, 35)) 377 dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 378 istate, mstate, buf); 379 switch (mstate) 380 { 381 case MS_UFROM: 382 mstate = MS_HEADER; 383#ifndef NOTUNIX 384 if (strncmp(buf, "From ", 5) == 0) 385 { 386 bp = buf; 387 eatfrom(buf, e); 388 continue; 389 } 390#endif /* ! NOTUNIX */ 391 /* FALLTHROUGH */ 392 393 case MS_HEADER: 394 if (!isheader(buf)) 395 { 396 mstate = MS_BODY; 397 goto nextstate; 398 } 399 400 /* check for possible continuation line */ 401 do 402 { 403 clearerr(fp); 404 errno = 0; 405 c = getc(fp); 406 } while (c == EOF && errno == EINTR); 407 if (c != EOF) 408 (void) ungetc(c, fp); 409 if (c == ' ' || c == '\t') 410 { 411 /* yep -- defer this */ 412 continue; 413 } 414 415 /* trim off trailing CRLF or NL */ 416 if (*--bp != '\n' || *--bp != '\r') 417 bp++; 418 *bp = '\0'; 419 420 if (bitset(H_EOH, chompheader(buf, 421 CHHDR_CHECK | CHHDR_USER, 422 hdrp, e))) 423 { 424 mstate = MS_BODY; 425 goto nextstate; 426 } 427 numhdrs++; 428 break; 429 430 case MS_BODY: 431 if (tTd(30, 1)) 432 dprintf("EOH\n"); 433 434 if (headeronly) 435 goto readerr; 436 437 /* call the end-of-header check ruleset */ 438 snprintf(hnum, sizeof hnum, "%d", numhdrs); 439 snprintf(hsize, sizeof hsize, "%d", hdrslen); 440 if (tTd(30, 10)) 441 dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 442 hnum, hsize); 443 rstat = rscheck("check_eoh", hnum, hsize, e, FALSE, 444 TRUE, 4, NULL); 445 446 bp = buf; 447 448 /* toss blank line */ 449 if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 450 bp[0] == '\r' && bp[1] == '\n') || 451 (!bitset(EF_NL_NOT_EOL, e->e_flags) && 452 bp[0] == '\n')) 453 { 454 break; 455 } 456 457 /* if not a blank separator, write it out */ 458 if (!bitset(EF_TOOBIG, e->e_flags)) 459 { 460 while (*bp != '\0') 461 (void) putc(*bp++, df); 462 } 463 break; 464 } 465 bp = buf; 466 } 467 468readerr: 469 if ((feof(fp) && smtpmode) || ferror(fp)) 470 { 471 const char *errmsg = errstring(errno); 472 473 if (tTd(30, 1)) 474 dprintf("collect: premature EOM: %s\n", errmsg); 475 if (LogLevel >= 2) 476 sm_syslog(LOG_WARNING, e->e_id, 477 "collect: premature EOM: %s", errmsg); 478 inputerr = TRUE; 479 } 480 481 /* reset global timer */ 482 clrevent(CollectTimeout); 483 484 if (headeronly) 485 return; 486 487 if (df == NULL) 488 { 489 /* skip next few clauses */ 490 /* EMPTY */ 491 } 492 else if (fflush(df) != 0 || ferror(df)) 493 { 494 dferror(df, "fflush||ferror", e); 495 flush_errors(TRUE); 496 finis(TRUE, ExitStat); 497 /* NOTREACHED */ 498 } 499 else if (!SuperSafe) 500 { 501 /* skip next few clauses */ 502 /* EMPTY */ 503 } 504 else if (bfcommit(df) < 0) 505 { 506 int save_errno = errno; 507 508 if (save_errno == EEXIST) 509 { 510 char *dfile; 511 struct stat st; 512 513 dfile = queuename(e, 'd'); 514 if (stat(dfile, &st) < 0) 515 st.st_size = -1; 516 errno = EEXIST; 517 syserr("collect: bfcommit(%s): already on disk, size = %ld", 518 dfile, (long) st.st_size); 519 dfd = fileno(df); 520 if (dfd >= 0) 521 dumpfd(dfd, TRUE, TRUE); 522 } 523 errno = save_errno; 524 dferror(df, "bfcommit", e); 525 flush_errors(TRUE); 526 finis(save_errno != EEXIST, ExitStat); 527 } 528 else if (bffsync(df) < 0) 529 { 530 dferror(df, "bffsync", e); 531 flush_errors(TRUE); 532 finis(TRUE, ExitStat); 533 /* NOTREACHED */ 534 } 535 else if (bfclose(df) < 0) 536 { 537 dferror(df, "bfclose", e); 538 flush_errors(TRUE); 539 finis(TRUE, ExitStat); 540 /* NOTREACHED */ 541 } 542 else 543 { 544 /* everything is happily flushed to disk */ 545 df = NULL; 546 } 547 548 /* An EOF when running SMTP is an error */ 549 if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 550 { 551 char *host; 552 char *problem; 553 554 host = RealHostName; 555 if (host == NULL) 556 host = "localhost"; 557 558 if (feof(fp)) 559 problem = "unexpected close"; 560 else if (ferror(fp)) 561 problem = "I/O error"; 562 else 563 problem = "read timeout"; 564 if (LogLevel > 0 && feof(fp)) 565 sm_syslog(LOG_NOTICE, e->e_id, 566 "collect: %s on connection from %.100s, sender=%s: %s", 567 problem, host, 568 shortenstring(e->e_from.q_paddr, MAXSHORTSTR), 569 errstring(errno)); 570 if (feof(fp)) 571 usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 572 problem, host, 573 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 574 else 575 syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 576 problem, host, 577 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 578 579 /* don't return an error indication */ 580 e->e_to = NULL; 581 e->e_flags &= ~EF_FATALERRS; 582 e->e_flags |= EF_CLRQUEUE; 583 584 /* and don't try to deliver the partial message either */ 585 if (InChild) 586 ExitStat = EX_QUIT; 587 finis(TRUE, ExitStat); 588 /* NOTREACHED */ 589 } 590 591 /* 592 ** Find out some information from the headers. 593 ** Examples are who is the from person & the date. 594 */ 595 596 eatheader(e, TRUE); 597 598 if (GrabTo && e->e_sendqueue == NULL) 599 usrerr("No recipient addresses found in header"); 600 601 /* collect statistics */ 602 if (OpMode != MD_VERIFY) 603 markstats(e, (ADDRESS *) NULL, FALSE); 604 605 /* 606 ** If we have a Return-Receipt-To:, turn it into a DSN. 607 */ 608 609 if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 610 { 611 ADDRESS *q; 612 613 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 614 if (!bitset(QHASNOTIFY, q->q_flags)) 615 q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 616 } 617 618 /* 619 ** Add an Apparently-To: line if we have no recipient lines. 620 */ 621 622 if (hvalue("to", e->e_header) != NULL || 623 hvalue("cc", e->e_header) != NULL || 624 hvalue("apparently-to", e->e_header) != NULL) 625 { 626 /* have a valid recipient header -- delete Bcc: headers */ 627 e->e_flags |= EF_DELETE_BCC; 628 } 629 else if (hvalue("bcc", e->e_header) == NULL) 630 { 631 /* no valid recipient headers */ 632 register ADDRESS *q; 633 char *hdr = NULL; 634 635 /* create an Apparently-To: field */ 636 /* that or reject the message.... */ 637 switch (NoRecipientAction) 638 { 639 case NRA_ADD_APPARENTLY_TO: 640 hdr = "Apparently-To"; 641 break; 642 643 case NRA_ADD_TO: 644 hdr = "To"; 645 break; 646 647 case NRA_ADD_BCC: 648 addheader("Bcc", " ", 0, &e->e_header); 649 break; 650 651 case NRA_ADD_TO_UNDISCLOSED: 652 addheader("To", "undisclosed-recipients:;", 0, &e->e_header); 653 break; 654 } 655 656 if (hdr != NULL) 657 { 658 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 659 { 660 if (q->q_alias != NULL) 661 continue; 662 if (tTd(30, 3)) 663 dprintf("Adding %s: %s\n", 664 hdr, q->q_paddr); 665 addheader(hdr, q->q_paddr, 0, &e->e_header); 666 } 667 } 668 } 669 670 /* check for message too large */ 671 if (bitset(EF_TOOBIG, e->e_flags)) 672 { 673 e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 674 e->e_status = "5.2.3"; 675 usrerrenh(e->e_status, 676 "552 Message exceeds maximum fixed size (%ld)", 677 MaxMessageSize); 678 if (LogLevel > 6) 679 sm_syslog(LOG_NOTICE, e->e_id, 680 "message size (%ld) exceeds maximum (%ld)", 681 e->e_msgsize, MaxMessageSize); 682 } 683 684 /* check for illegal 8-bit data */ 685 if (HasEightBits) 686 { 687 e->e_flags |= EF_HAS8BIT; 688 if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 689 !bitset(EF_IS_MIME, e->e_flags)) 690 { 691 e->e_status = "5.6.1"; 692 usrerrenh(e->e_status, "554 Eight bit data not allowed"); 693 } 694 } 695 else 696 { 697 /* if it claimed to be 8 bits, well, it lied.... */ 698 if (e->e_bodytype != NULL && 699 strcasecmp(e->e_bodytype, "8BITMIME") == 0) 700 e->e_bodytype = "7BIT"; 701 } 702 703 if (SuperSafe) 704 { 705 if ((e->e_dfp = fopen(dfname, "r")) == NULL) 706 { 707 /* we haven't acked receipt yet, so just chuck this */ 708 syserr("Cannot reopen %s", dfname); 709 finis(TRUE, ExitStat); 710 /* NOTREACHED */ 711 } 712 } 713 else 714 e->e_dfp = df; 715 if (e->e_dfp == NULL) 716 syserr("!collect: no e_dfp"); 717} 718 719 720static void 721collecttimeout(timeout) 722 time_t timeout; 723{ 724 /* if no progress was made, die now */ 725 if (!CollectProgress) 726 longjmp(CtxCollectTimeout, 1); 727 728 /* otherwise reset the timeout */ 729 CollectTimeout = setevent(timeout, collecttimeout, timeout); 730 CollectProgress = FALSE; 731} 732/* 733** DFERROR -- signal error on writing the data file. 734** 735** Parameters: 736** df -- the file pointer for the data file. 737** msg -- detailed message. 738** e -- the current envelope. 739** 740** Returns: 741** none. 742** 743** Side Effects: 744** Gives an error message. 745** Arranges for following output to go elsewhere. 746*/ 747 748static void 749dferror(df, msg, e) 750 FILE *volatile df; 751 char *msg; 752 register ENVELOPE *e; 753{ 754 char *dfname; 755 756 dfname = queuename(e, 'd'); 757 setstat(EX_IOERR); 758 if (errno == ENOSPC) 759 { 760#if STAT64 > 0 761 struct stat64 st; 762#else /* STAT64 > 0 */ 763 struct stat st; 764#endif /* STAT64 > 0 */ 765 long avail; 766 long bsize; 767 768 e->e_flags |= EF_NO_BODY_RETN; 769 770 if ( 771#if STAT64 > 0 772 fstat64(fileno(df), &st) 773#else /* STAT64 > 0 */ 774 fstat(fileno(df), &st) 775#endif /* STAT64 > 0 */ 776 < 0) 777 st.st_size = 0; 778 (void) freopen(dfname, "w", df); 779 if (st.st_size <= 0) 780 fprintf(df, "\n*** Mail could not be accepted"); 781 /*CONSTCOND*/ 782 else if (sizeof st.st_size > sizeof (long)) 783 fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n", 784 quad_to_string(st.st_size)); 785 else 786 fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n", 787 (unsigned long) st.st_size); 788 fprintf(df, "*** at %s due to lack of disk space for temp file.\n", 789 MyHostName); 790 avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize); 791 if (avail > 0) 792 { 793 if (bsize > 1024) 794 avail *= bsize / 1024; 795 else if (bsize < 1024) 796 avail /= 1024 / bsize; 797 fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n", 798 avail); 799 } 800 e->e_status = "4.3.1"; 801 usrerrenh(e->e_status, "452 Out of disk space for temp file"); 802 } 803 else 804 syserr("collect: Cannot write %s (%s, uid=%d)", 805 dfname, msg, geteuid()); 806 if (freopen("/dev/null", "w", df) == NULL) 807 sm_syslog(LOG_ERR, e->e_id, 808 "dferror: freopen(\"/dev/null\") failed: %s", 809 errstring(errno)); 810} 811/* 812** EATFROM -- chew up a UNIX style from line and process 813** 814** This does indeed make some assumptions about the format 815** of UNIX messages. 816** 817** Parameters: 818** fm -- the from line. 819** 820** Returns: 821** none. 822** 823** Side Effects: 824** extracts what information it can from the header, 825** such as the date. 826*/ 827 828#ifndef NOTUNIX 829 830static char *DowList[] = 831{ 832 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 833}; 834 835static char *MonthList[] = 836{ 837 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 838 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 839 NULL 840}; 841 842static void 843eatfrom(fm, e) 844 char *volatile fm; 845 register ENVELOPE *e; 846{ 847 register char *p; 848 register char **dt; 849 850 if (tTd(30, 2)) 851 dprintf("eatfrom(%s)\n", fm); 852 853 /* find the date part */ 854 p = fm; 855 while (*p != '\0') 856 { 857 /* skip a word */ 858 while (*p != '\0' && *p != ' ') 859 p++; 860 while (*p == ' ') 861 p++; 862 if (strlen(p) < 17) 863 { 864 /* no room for the date */ 865 return; 866 } 867 if (!(isascii(*p) && isupper(*p)) || 868 p[3] != ' ' || p[13] != ':' || p[16] != ':') 869 continue; 870 871 /* we have a possible date */ 872 for (dt = DowList; *dt != NULL; dt++) 873 if (strncmp(*dt, p, 3) == 0) 874 break; 875 if (*dt == NULL) 876 continue; 877 878 for (dt = MonthList; *dt != NULL; dt++) 879 { 880 if (strncmp(*dt, &p[4], 3) == 0) 881 break; 882 } 883 if (*dt != NULL) 884 break; 885 } 886 887 if (*p != '\0') 888 { 889 char *q; 890 891 /* we have found a date */ 892 q = xalloc(25); 893 (void) strlcpy(q, p, 25); 894 q = arpadate(q); 895 define('a', newstr(q), e); 896 } 897} 898#endif /* ! NOTUNIX */ 899