1c2aa98e2SPeter Wemm /* 2605302a5SGregory Neil Shapiro * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 15c2aa98e2SPeter Wemm 1694c01205SGregory Neil Shapiro SM_RCSID("@(#)$Id: collect.c,v 8.242 2002/05/10 15:40:09 ca Exp $") 1706f25ae9SGregory Neil Shapiro 1806f25ae9SGregory Neil Shapiro static void collecttimeout __P((time_t)); 1940266059SGregory Neil Shapiro static void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *)); 2006f25ae9SGregory Neil Shapiro static void eatfrom __P((char *volatile, ENVELOPE *)); 2140266059SGregory Neil Shapiro static void collect_doheader __P((ENVELOPE *)); 2240266059SGregory Neil Shapiro static SM_FILE_T *collect_dfopen __P((ENVELOPE *)); 2340266059SGregory Neil Shapiro static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int)); 2406f25ae9SGregory Neil Shapiro 2540266059SGregory Neil Shapiro /* 2640266059SGregory Neil Shapiro ** COLLECT_EOH -- end-of-header processing in collect() 2740266059SGregory Neil Shapiro ** 2840266059SGregory Neil Shapiro ** Called by collect() when it encounters the blank line 2940266059SGregory Neil Shapiro ** separating the header from the message body, or when it 3040266059SGregory Neil Shapiro ** encounters EOF in a message that contains only a header. 3140266059SGregory Neil Shapiro ** 3240266059SGregory Neil Shapiro ** Parameters: 3340266059SGregory Neil Shapiro ** e -- envelope 3440266059SGregory Neil Shapiro ** numhdrs -- number of headers 3540266059SGregory Neil Shapiro ** hdrslen -- length of headers 3640266059SGregory Neil Shapiro ** 3740266059SGregory Neil Shapiro ** Results: 3840266059SGregory Neil Shapiro ** NULL, or handle to open data file 3940266059SGregory Neil Shapiro ** 4040266059SGregory Neil Shapiro ** Side Effects: 4140266059SGregory Neil Shapiro ** end-of-header check ruleset is invoked. 4240266059SGregory Neil Shapiro ** envelope state is updated. 4340266059SGregory Neil Shapiro ** headers may be added and deleted. 4440266059SGregory Neil Shapiro ** selects the queue. 4540266059SGregory Neil Shapiro ** opens the data file. 4640266059SGregory Neil Shapiro */ 4740266059SGregory Neil Shapiro 4840266059SGregory Neil Shapiro static SM_FILE_T * 4940266059SGregory Neil Shapiro collect_eoh(e, numhdrs, hdrslen) 5040266059SGregory Neil Shapiro ENVELOPE *e; 5140266059SGregory Neil Shapiro int numhdrs; 5240266059SGregory Neil Shapiro int hdrslen; 5340266059SGregory Neil Shapiro { 5440266059SGregory Neil Shapiro char hnum[16]; 5540266059SGregory Neil Shapiro char hsize[16]; 5640266059SGregory Neil Shapiro 5740266059SGregory Neil Shapiro /* call the end-of-header check ruleset */ 5840266059SGregory Neil Shapiro (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs); 5940266059SGregory Neil Shapiro (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen); 6040266059SGregory Neil Shapiro if (tTd(30, 10)) 6140266059SGregory Neil Shapiro sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 6240266059SGregory Neil Shapiro hnum, hsize); 6340266059SGregory Neil Shapiro (void) rscheck("check_eoh", hnum, hsize, e, false, true, 3, NULL, 6440266059SGregory Neil Shapiro e->e_id); 6540266059SGregory Neil Shapiro 6640266059SGregory Neil Shapiro /* 6740266059SGregory Neil Shapiro ** Process the header, 6840266059SGregory Neil Shapiro ** select the queue, open the data file. 6940266059SGregory Neil Shapiro */ 7040266059SGregory Neil Shapiro 7140266059SGregory Neil Shapiro collect_doheader(e); 7240266059SGregory Neil Shapiro return collect_dfopen(e); 7340266059SGregory Neil Shapiro } 7440266059SGregory Neil Shapiro 7540266059SGregory Neil Shapiro /* 7640266059SGregory Neil Shapiro ** COLLECT_DOHEADER -- process header in collect() 7740266059SGregory Neil Shapiro ** 7840266059SGregory Neil Shapiro ** Called by collect() after it has finished parsing the header, 7940266059SGregory Neil Shapiro ** but before it selects the queue and creates the data file. 8040266059SGregory Neil Shapiro ** The results of processing the header will affect queue selection. 8140266059SGregory Neil Shapiro ** 8240266059SGregory Neil Shapiro ** Parameters: 8340266059SGregory Neil Shapiro ** e -- envelope 8440266059SGregory Neil Shapiro ** 8540266059SGregory Neil Shapiro ** Results: 8640266059SGregory Neil Shapiro ** none. 8740266059SGregory Neil Shapiro ** 8840266059SGregory Neil Shapiro ** Side Effects: 8940266059SGregory Neil Shapiro ** envelope state is updated. 9040266059SGregory Neil Shapiro ** headers may be added and deleted. 9140266059SGregory Neil Shapiro */ 9240266059SGregory Neil Shapiro 9340266059SGregory Neil Shapiro static void 9440266059SGregory Neil Shapiro collect_doheader(e) 9540266059SGregory Neil Shapiro ENVELOPE *e; 9640266059SGregory Neil Shapiro { 9740266059SGregory Neil Shapiro /* 9840266059SGregory Neil Shapiro ** Find out some information from the headers. 9940266059SGregory Neil Shapiro ** Examples are who is the from person & the date. 10040266059SGregory Neil Shapiro */ 10140266059SGregory Neil Shapiro 10240266059SGregory Neil Shapiro eatheader(e, true, false); 10340266059SGregory Neil Shapiro 10440266059SGregory Neil Shapiro if (GrabTo && e->e_sendqueue == NULL) 10540266059SGregory Neil Shapiro usrerr("No recipient addresses found in header"); 10640266059SGregory Neil Shapiro 10740266059SGregory Neil Shapiro /* 10840266059SGregory Neil Shapiro ** If we have a Return-Receipt-To:, turn it into a DSN. 10940266059SGregory Neil Shapiro */ 11040266059SGregory Neil Shapiro 11140266059SGregory Neil Shapiro if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 11240266059SGregory Neil Shapiro { 11340266059SGregory Neil Shapiro ADDRESS *q; 11440266059SGregory Neil Shapiro 11540266059SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 11640266059SGregory Neil Shapiro if (!bitset(QHASNOTIFY, q->q_flags)) 11740266059SGregory Neil Shapiro q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 11840266059SGregory Neil Shapiro } 11940266059SGregory Neil Shapiro 12040266059SGregory Neil Shapiro /* 12140266059SGregory Neil Shapiro ** Add an appropriate recipient line if we have none. 12240266059SGregory Neil Shapiro */ 12340266059SGregory Neil Shapiro 12440266059SGregory Neil Shapiro if (hvalue("to", e->e_header) != NULL || 12540266059SGregory Neil Shapiro hvalue("cc", e->e_header) != NULL || 12640266059SGregory Neil Shapiro hvalue("apparently-to", e->e_header) != NULL) 12740266059SGregory Neil Shapiro { 12840266059SGregory Neil Shapiro /* have a valid recipient header -- delete Bcc: headers */ 12940266059SGregory Neil Shapiro e->e_flags |= EF_DELETE_BCC; 13040266059SGregory Neil Shapiro } 13140266059SGregory Neil Shapiro else if (hvalue("bcc", e->e_header) == NULL) 13240266059SGregory Neil Shapiro { 13340266059SGregory Neil Shapiro /* no valid recipient headers */ 13440266059SGregory Neil Shapiro register ADDRESS *q; 13540266059SGregory Neil Shapiro char *hdr = NULL; 13640266059SGregory Neil Shapiro 13740266059SGregory Neil Shapiro /* create a recipient field */ 13840266059SGregory Neil Shapiro switch (NoRecipientAction) 13940266059SGregory Neil Shapiro { 14040266059SGregory Neil Shapiro case NRA_ADD_APPARENTLY_TO: 14140266059SGregory Neil Shapiro hdr = "Apparently-To"; 14240266059SGregory Neil Shapiro break; 14340266059SGregory Neil Shapiro 14440266059SGregory Neil Shapiro case NRA_ADD_TO: 14540266059SGregory Neil Shapiro hdr = "To"; 14640266059SGregory Neil Shapiro break; 14740266059SGregory Neil Shapiro 14840266059SGregory Neil Shapiro case NRA_ADD_BCC: 14940266059SGregory Neil Shapiro addheader("Bcc", " ", 0, e); 15040266059SGregory Neil Shapiro break; 15140266059SGregory Neil Shapiro 15240266059SGregory Neil Shapiro case NRA_ADD_TO_UNDISCLOSED: 15340266059SGregory Neil Shapiro addheader("To", "undisclosed-recipients:;", 0, e); 15440266059SGregory Neil Shapiro break; 15540266059SGregory Neil Shapiro } 15640266059SGregory Neil Shapiro 15740266059SGregory Neil Shapiro if (hdr != NULL) 15840266059SGregory Neil Shapiro { 15940266059SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16040266059SGregory Neil Shapiro { 16140266059SGregory Neil Shapiro if (q->q_alias != NULL) 16240266059SGregory Neil Shapiro continue; 16340266059SGregory Neil Shapiro if (tTd(30, 3)) 16440266059SGregory Neil Shapiro sm_dprintf("Adding %s: %s\n", 16540266059SGregory Neil Shapiro hdr, q->q_paddr); 16640266059SGregory Neil Shapiro addheader(hdr, q->q_paddr, 0, e); 16740266059SGregory Neil Shapiro } 16840266059SGregory Neil Shapiro } 16940266059SGregory Neil Shapiro } 17040266059SGregory Neil Shapiro } 17140266059SGregory Neil Shapiro 17240266059SGregory Neil Shapiro /* 17340266059SGregory Neil Shapiro ** COLLECT_DFOPEN -- open the message data file 17440266059SGregory Neil Shapiro ** 17540266059SGregory Neil Shapiro ** Called by collect() after it has finished processing the header. 17640266059SGregory Neil Shapiro ** Queue selection occurs at this point, possibly based on the 17740266059SGregory Neil Shapiro ** envelope's recipient list and on header information. 17840266059SGregory Neil Shapiro ** 17940266059SGregory Neil Shapiro ** Parameters: 18040266059SGregory Neil Shapiro ** e -- envelope 18140266059SGregory Neil Shapiro ** 18240266059SGregory Neil Shapiro ** Results: 18340266059SGregory Neil Shapiro ** NULL, or a pointer to an open data file, 18440266059SGregory Neil Shapiro ** into which the message body will be written by collect(). 18540266059SGregory Neil Shapiro ** 18640266059SGregory Neil Shapiro ** Side Effects: 18740266059SGregory Neil Shapiro ** Calls syserr, sets EF_FATALERRS and returns NULL 18840266059SGregory Neil Shapiro ** if there is insufficient disk space. 18940266059SGregory Neil Shapiro ** Aborts process if data file could not be opened. 19040266059SGregory Neil Shapiro ** Otherwise, the queue is selected, 19140266059SGregory Neil Shapiro ** e->e_{dfino,dfdev,msgsize,flags} are updated, 19240266059SGregory Neil Shapiro ** and a pointer to an open data file is returned. 19340266059SGregory Neil Shapiro */ 19440266059SGregory Neil Shapiro 19540266059SGregory Neil Shapiro static SM_FILE_T * 19640266059SGregory Neil Shapiro collect_dfopen(e) 19740266059SGregory Neil Shapiro ENVELOPE *e; 19840266059SGregory Neil Shapiro { 19940266059SGregory Neil Shapiro MODE_T oldumask = 0; 20040266059SGregory Neil Shapiro int dfd; 20140266059SGregory Neil Shapiro struct stat stbuf; 20240266059SGregory Neil Shapiro SM_FILE_T *df; 20340266059SGregory Neil Shapiro char *dfname; 20440266059SGregory Neil Shapiro 20540266059SGregory Neil Shapiro if (!setnewqueue(e)) 20640266059SGregory Neil Shapiro return NULL; 20740266059SGregory Neil Shapiro 20840266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 20940266059SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 21040266059SGregory Neil Shapiro oldumask = umask(002); 21140266059SGregory Neil Shapiro df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 21240266059SGregory Neil Shapiro SFF_OPENASROOT); 21340266059SGregory Neil Shapiro if (bitset(S_IWGRP, QueueFileMode)) 21440266059SGregory Neil Shapiro (void) umask(oldumask); 21540266059SGregory Neil Shapiro if (df == NULL) 21640266059SGregory Neil Shapiro { 21740266059SGregory Neil Shapiro syserr("@Cannot create %s", dfname); 21840266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 21940266059SGregory Neil Shapiro flush_errors(true); 22040266059SGregory Neil Shapiro finis(true, true, ExitStat); 22140266059SGregory Neil Shapiro /* NOTREACHED */ 22240266059SGregory Neil Shapiro } 22340266059SGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 22440266059SGregory Neil Shapiro if (dfd < 0 || fstat(dfd, &stbuf) < 0) 22540266059SGregory Neil Shapiro e->e_dfino = -1; 22640266059SGregory Neil Shapiro else 22740266059SGregory Neil Shapiro { 22840266059SGregory Neil Shapiro e->e_dfdev = stbuf.st_dev; 22940266059SGregory Neil Shapiro e->e_dfino = stbuf.st_ino; 23040266059SGregory Neil Shapiro } 23140266059SGregory Neil Shapiro e->e_flags |= EF_HAS_DF; 23240266059SGregory Neil Shapiro return df; 23340266059SGregory Neil Shapiro } 23440266059SGregory Neil Shapiro 23540266059SGregory Neil Shapiro /* 236c2aa98e2SPeter Wemm ** COLLECT -- read & parse message header & make temp file. 237c2aa98e2SPeter Wemm ** 238c2aa98e2SPeter Wemm ** Creates a temporary file name and copies the standard 239c2aa98e2SPeter Wemm ** input to that file. Leading UNIX-style "From" lines are 240c2aa98e2SPeter Wemm ** stripped off (after important information is extracted). 241c2aa98e2SPeter Wemm ** 242c2aa98e2SPeter Wemm ** Parameters: 243c2aa98e2SPeter Wemm ** fp -- file to read. 244c2aa98e2SPeter Wemm ** smtpmode -- if set, we are running SMTP: give an RFC821 245c2aa98e2SPeter Wemm ** style message to say we are ready to collect 246c2aa98e2SPeter Wemm ** input, and never ignore a single dot to mean 247c2aa98e2SPeter Wemm ** end of message. 248c2aa98e2SPeter Wemm ** hdrp -- the location to stash the header. 249c2aa98e2SPeter Wemm ** e -- the current envelope. 250c2aa98e2SPeter Wemm ** 251c2aa98e2SPeter Wemm ** Returns: 252c2aa98e2SPeter Wemm ** none. 253c2aa98e2SPeter Wemm ** 254c2aa98e2SPeter Wemm ** Side Effects: 25540266059SGregory Neil Shapiro ** If successful, 25640266059SGregory Neil Shapiro ** - Data file is created and filled, and e->e_dfp is set. 25740266059SGregory Neil Shapiro ** - The from person may be set. 25840266059SGregory Neil Shapiro ** If the "enough disk space" check fails, 25940266059SGregory Neil Shapiro ** - syserr is called. 26040266059SGregory Neil Shapiro ** - e->e_dfp is NULL. 26140266059SGregory Neil Shapiro ** - e->e_flags & EF_FATALERRS is set. 26240266059SGregory Neil Shapiro ** - collect() returns. 26340266059SGregory Neil Shapiro ** If data file cannot be created, the process is terminated. 264c2aa98e2SPeter Wemm */ 265c2aa98e2SPeter Wemm 266c2aa98e2SPeter Wemm static jmp_buf CtxCollectTimeout; 2678774250cSGregory Neil Shapiro static bool volatile CollectProgress; 26840266059SGregory Neil Shapiro static SM_EVENT *volatile CollectTimeout = NULL; 269c2aa98e2SPeter Wemm 270c2aa98e2SPeter Wemm /* values for input state machine */ 271c2aa98e2SPeter Wemm #define IS_NORM 0 /* middle of line */ 272c2aa98e2SPeter Wemm #define IS_BOL 1 /* beginning of line */ 273c2aa98e2SPeter Wemm #define IS_DOT 2 /* read a dot at beginning of line */ 274c2aa98e2SPeter Wemm #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 275c2aa98e2SPeter Wemm #define IS_CR 4 /* read a carriage return */ 276c2aa98e2SPeter Wemm 277c2aa98e2SPeter Wemm /* values for message state machine */ 278c2aa98e2SPeter Wemm #define MS_UFROM 0 /* reading Unix from line */ 279c2aa98e2SPeter Wemm #define MS_HEADER 1 /* reading message header */ 280c2aa98e2SPeter Wemm #define MS_BODY 2 /* reading message body */ 28125bab6e9SPeter Wemm #define MS_DISCARD 3 /* discarding rest of message */ 282c2aa98e2SPeter Wemm 283c2aa98e2SPeter Wemm void 284c2aa98e2SPeter Wemm collect(fp, smtpmode, hdrp, e) 28540266059SGregory Neil Shapiro SM_FILE_T *fp; 286c2aa98e2SPeter Wemm bool smtpmode; 287c2aa98e2SPeter Wemm HDR **hdrp; 288c2aa98e2SPeter Wemm register ENVELOPE *e; 289c2aa98e2SPeter Wemm { 29040266059SGregory Neil Shapiro register SM_FILE_T *volatile df; 29140266059SGregory Neil Shapiro volatile bool ignrdot; 29240266059SGregory Neil Shapiro volatile time_t dbto; 293c2aa98e2SPeter Wemm register char *volatile bp; 29440266059SGregory Neil Shapiro volatile int c; 29540266059SGregory Neil Shapiro volatile bool inputerr; 296c2aa98e2SPeter Wemm bool headeronly; 297c2aa98e2SPeter Wemm char *volatile buf; 298c2aa98e2SPeter Wemm volatile int buflen; 299c2aa98e2SPeter Wemm volatile int istate; 300c2aa98e2SPeter Wemm volatile int mstate; 30140266059SGregory Neil Shapiro volatile int hdrslen; 30240266059SGregory Neil Shapiro volatile int numhdrs; 30340266059SGregory Neil Shapiro volatile int afd; 30440266059SGregory Neil Shapiro unsigned char *volatile pbp; 30540266059SGregory Neil Shapiro unsigned char peekbuf[8]; 306c2aa98e2SPeter Wemm char bufbuf[MAXLINE]; 307c2aa98e2SPeter Wemm 30840266059SGregory Neil Shapiro df = NULL; 30940266059SGregory Neil Shapiro ignrdot = smtpmode ? false : IgnrDot; 31040266059SGregory Neil Shapiro dbto = smtpmode ? TimeOuts.to_datablock : 0; 31140266059SGregory Neil Shapiro c = SM_IO_EOF; 31240266059SGregory Neil Shapiro inputerr = false; 313c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 31440266059SGregory Neil Shapiro hdrslen = 0; 31540266059SGregory Neil Shapiro numhdrs = 0; 31640266059SGregory Neil Shapiro HasEightBits = false; 31740266059SGregory Neil Shapiro buf = bp = bufbuf; 31840266059SGregory Neil Shapiro buflen = sizeof bufbuf; 31940266059SGregory Neil Shapiro pbp = peekbuf; 32040266059SGregory Neil Shapiro istate = IS_BOL; 32140266059SGregory Neil Shapiro mstate = SaveFrom ? MS_HEADER : MS_UFROM; 32240266059SGregory Neil Shapiro CollectProgress = false; 323c2aa98e2SPeter Wemm 324c2aa98e2SPeter Wemm /* 325c2aa98e2SPeter Wemm ** Tell ARPANET to go ahead. 326c2aa98e2SPeter Wemm */ 327c2aa98e2SPeter Wemm 328c2aa98e2SPeter Wemm if (smtpmode) 329c2aa98e2SPeter Wemm message("354 Enter mail, end with \".\" on a line by itself"); 330c2aa98e2SPeter Wemm 331c2aa98e2SPeter Wemm if (tTd(30, 2)) 33240266059SGregory Neil Shapiro sm_dprintf("collect\n"); 333c2aa98e2SPeter Wemm 334c2aa98e2SPeter Wemm /* 335c2aa98e2SPeter Wemm ** Read the message. 336c2aa98e2SPeter Wemm ** 337c2aa98e2SPeter Wemm ** This is done using two interleaved state machines. 338c2aa98e2SPeter Wemm ** The input state machine is looking for things like 339c2aa98e2SPeter Wemm ** hidden dots; the message state machine is handling 340c2aa98e2SPeter Wemm ** the larger picture (e.g., header versus body). 341c2aa98e2SPeter Wemm */ 342c2aa98e2SPeter Wemm 343c2aa98e2SPeter Wemm if (dbto != 0) 344c2aa98e2SPeter Wemm { 345c2aa98e2SPeter Wemm /* handle possible input timeout */ 346c2aa98e2SPeter Wemm if (setjmp(CtxCollectTimeout) != 0) 347c2aa98e2SPeter Wemm { 348c2aa98e2SPeter Wemm if (LogLevel > 2) 349c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 350c2aa98e2SPeter Wemm "timeout waiting for input from %s during message collect", 35140266059SGregory Neil Shapiro CURHOSTNAME); 352c2aa98e2SPeter Wemm errno = 0; 35306f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 timeout waiting for input during message collect"); 354c2aa98e2SPeter Wemm goto readerr; 355c2aa98e2SPeter Wemm } 35640266059SGregory Neil Shapiro CollectTimeout = sm_setevent(dbto, collecttimeout, dbto); 357c2aa98e2SPeter Wemm } 358c2aa98e2SPeter Wemm 35940266059SGregory Neil Shapiro e->e_msgsize = 0; 360c2aa98e2SPeter Wemm for (;;) 361c2aa98e2SPeter Wemm { 362c2aa98e2SPeter Wemm if (tTd(30, 35)) 36340266059SGregory Neil Shapiro sm_dprintf("top, istate=%d, mstate=%d\n", istate, 36440266059SGregory Neil Shapiro mstate); 365c2aa98e2SPeter Wemm for (;;) 366c2aa98e2SPeter Wemm { 367c2aa98e2SPeter Wemm if (pbp > peekbuf) 368c2aa98e2SPeter Wemm c = *--pbp; 369c2aa98e2SPeter Wemm else 370c2aa98e2SPeter Wemm { 37140266059SGregory Neil Shapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 372c2aa98e2SPeter Wemm { 373c2aa98e2SPeter Wemm errno = 0; 37440266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 37540266059SGregory Neil Shapiro if (c == SM_IO_EOF && errno == EINTR) 37642e5d165SGregory Neil Shapiro { 37742e5d165SGregory Neil Shapiro /* Interrupted, retry */ 37840266059SGregory Neil Shapiro sm_io_clearerr(fp); 37942e5d165SGregory Neil Shapiro continue; 38042e5d165SGregory Neil Shapiro } 38142e5d165SGregory Neil Shapiro break; 382c2aa98e2SPeter Wemm } 38340266059SGregory Neil Shapiro CollectProgress = true; 384c2aa98e2SPeter Wemm if (TrafficLogFile != NULL && !headeronly) 385c2aa98e2SPeter Wemm { 386c2aa98e2SPeter Wemm if (istate == IS_BOL) 38740266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 38840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 3898774250cSGregory Neil Shapiro "%05d <<< ", 39040266059SGregory Neil Shapiro (int) CurrentPid); 39140266059SGregory Neil Shapiro if (c == SM_IO_EOF) 39240266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 39340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 3948774250cSGregory Neil Shapiro "[EOF]\n"); 395c2aa98e2SPeter Wemm else 39640266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 39740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 39840266059SGregory Neil Shapiro c); 399c2aa98e2SPeter Wemm } 40040266059SGregory Neil Shapiro if (c == SM_IO_EOF) 401c2aa98e2SPeter Wemm goto readerr; 402c2aa98e2SPeter Wemm if (SevenBitInput) 403c2aa98e2SPeter Wemm c &= 0x7f; 404c2aa98e2SPeter Wemm else 405c2aa98e2SPeter Wemm HasEightBits |= bitset(0x80, c); 406c2aa98e2SPeter Wemm } 407c2aa98e2SPeter Wemm if (tTd(30, 94)) 40840266059SGregory Neil Shapiro sm_dprintf("istate=%d, c=%c (0x%x)\n", 40906f25ae9SGregory Neil Shapiro istate, (char) c, c); 410c2aa98e2SPeter Wemm switch (istate) 411c2aa98e2SPeter Wemm { 412c2aa98e2SPeter Wemm case IS_BOL: 413c2aa98e2SPeter Wemm if (c == '.') 414c2aa98e2SPeter Wemm { 415c2aa98e2SPeter Wemm istate = IS_DOT; 416c2aa98e2SPeter Wemm continue; 417c2aa98e2SPeter Wemm } 418c2aa98e2SPeter Wemm break; 419c2aa98e2SPeter Wemm 420c2aa98e2SPeter Wemm case IS_DOT: 421c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot && 422c2aa98e2SPeter Wemm !bitset(EF_NL_NOT_EOL, e->e_flags)) 423c2aa98e2SPeter Wemm goto readerr; 424c2aa98e2SPeter Wemm else if (c == '\r' && 425c2aa98e2SPeter Wemm !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 426c2aa98e2SPeter Wemm { 427c2aa98e2SPeter Wemm istate = IS_DOTCR; 428c2aa98e2SPeter Wemm continue; 429c2aa98e2SPeter Wemm } 430605302a5SGregory Neil Shapiro else if (ignrdot || 431605302a5SGregory Neil Shapiro (c != '.' && 432605302a5SGregory Neil Shapiro OpMode != MD_SMTP && 433c2aa98e2SPeter Wemm OpMode != MD_DAEMON && 434c2aa98e2SPeter Wemm OpMode != MD_ARPAFTP)) 435605302a5SGregory Neil Shapiro 436c2aa98e2SPeter Wemm { 437c2aa98e2SPeter Wemm *pbp++ = c; 438c2aa98e2SPeter Wemm c = '.'; 439c2aa98e2SPeter Wemm } 440c2aa98e2SPeter Wemm break; 441c2aa98e2SPeter Wemm 442c2aa98e2SPeter Wemm case IS_DOTCR: 443c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot) 444c2aa98e2SPeter Wemm goto readerr; 445c2aa98e2SPeter Wemm else 446c2aa98e2SPeter Wemm { 447c2aa98e2SPeter Wemm /* push back the ".\rx" */ 448c2aa98e2SPeter Wemm *pbp++ = c; 449605302a5SGregory Neil Shapiro if (OpMode != MD_SMTP && 450605302a5SGregory Neil Shapiro OpMode != MD_DAEMON && 451605302a5SGregory Neil Shapiro OpMode != MD_ARPAFTP) 452605302a5SGregory Neil Shapiro { 453c2aa98e2SPeter Wemm *pbp++ = '\r'; 454c2aa98e2SPeter Wemm c = '.'; 455c2aa98e2SPeter Wemm } 456605302a5SGregory Neil Shapiro else 457605302a5SGregory Neil Shapiro c = '\r'; 458605302a5SGregory Neil Shapiro } 459c2aa98e2SPeter Wemm break; 460c2aa98e2SPeter Wemm 461c2aa98e2SPeter Wemm case IS_CR: 462c2aa98e2SPeter Wemm if (c == '\n') 463c2aa98e2SPeter Wemm istate = IS_BOL; 464c2aa98e2SPeter Wemm else 465c2aa98e2SPeter Wemm { 46640266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 46740266059SGregory Neil Shapiro c); 468c2aa98e2SPeter Wemm c = '\r'; 469c2aa98e2SPeter Wemm istate = IS_NORM; 470c2aa98e2SPeter Wemm } 471c2aa98e2SPeter Wemm goto bufferchar; 472c2aa98e2SPeter Wemm } 473c2aa98e2SPeter Wemm 474c2aa98e2SPeter Wemm if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 475c2aa98e2SPeter Wemm { 476c2aa98e2SPeter Wemm istate = IS_CR; 477c2aa98e2SPeter Wemm continue; 478c2aa98e2SPeter Wemm } 47940266059SGregory Neil Shapiro else if (c == '\n' && !bitset(EF_NL_NOT_EOL, 48040266059SGregory Neil Shapiro e->e_flags)) 481c2aa98e2SPeter Wemm istate = IS_BOL; 482c2aa98e2SPeter Wemm else 483c2aa98e2SPeter Wemm istate = IS_NORM; 484c2aa98e2SPeter Wemm 485c2aa98e2SPeter Wemm bufferchar: 486c2aa98e2SPeter Wemm if (!headeronly) 48742e5d165SGregory Neil Shapiro { 48842e5d165SGregory Neil Shapiro /* no overflow? */ 48942e5d165SGregory Neil Shapiro if (e->e_msgsize >= 0) 49042e5d165SGregory Neil Shapiro { 491c2aa98e2SPeter Wemm e->e_msgsize++; 49242e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 && 49342e5d165SGregory Neil Shapiro !bitset(EF_TOOBIG, e->e_flags) && 49442e5d165SGregory Neil Shapiro e->e_msgsize > MaxMessageSize) 49542e5d165SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 49642e5d165SGregory Neil Shapiro } 49742e5d165SGregory Neil Shapiro } 49825bab6e9SPeter Wemm switch (mstate) 499c2aa98e2SPeter Wemm { 50025bab6e9SPeter Wemm case MS_BODY: 501c2aa98e2SPeter Wemm /* just put the character out */ 50242e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 50340266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 50440266059SGregory Neil Shapiro c); 50540266059SGregory Neil Shapiro 50606f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 50725bab6e9SPeter Wemm 50825bab6e9SPeter Wemm case MS_DISCARD: 509c2aa98e2SPeter Wemm continue; 510c2aa98e2SPeter Wemm } 511c2aa98e2SPeter Wemm 512c2aa98e2SPeter Wemm /* header -- buffer up */ 513c2aa98e2SPeter Wemm if (bp >= &buf[buflen - 2]) 514c2aa98e2SPeter Wemm { 515c2aa98e2SPeter Wemm char *obuf; 516c2aa98e2SPeter Wemm 517c2aa98e2SPeter Wemm if (mstate != MS_HEADER) 518c2aa98e2SPeter Wemm break; 519c2aa98e2SPeter Wemm 520c2aa98e2SPeter Wemm /* out of space for header */ 521c2aa98e2SPeter Wemm obuf = buf; 522c2aa98e2SPeter Wemm if (buflen < MEMCHUNKSIZE) 523c2aa98e2SPeter Wemm buflen *= 2; 524c2aa98e2SPeter Wemm else 525c2aa98e2SPeter Wemm buflen += MEMCHUNKSIZE; 526c2aa98e2SPeter Wemm buf = xalloc(buflen); 52706f25ae9SGregory Neil Shapiro memmove(buf, obuf, bp - obuf); 528c2aa98e2SPeter Wemm bp = &buf[bp - obuf]; 529c2aa98e2SPeter Wemm if (obuf != bufbuf) 53040266059SGregory Neil Shapiro sm_free(obuf); /* XXX */ 531c2aa98e2SPeter Wemm } 53240266059SGregory Neil Shapiro 53340266059SGregory Neil Shapiro /* 53440266059SGregory Neil Shapiro ** XXX Notice: the logic here is broken. 53540266059SGregory Neil Shapiro ** An input to sendmail that doesn't contain a 53640266059SGregory Neil Shapiro ** header but starts immediately with the body whose 53740266059SGregory Neil Shapiro ** first line contain characters which match the 53840266059SGregory Neil Shapiro ** following "if" will cause problems: those 53940266059SGregory Neil Shapiro ** characters will NOT appear in the output... 54040266059SGregory Neil Shapiro ** Do we care? 54140266059SGregory Neil Shapiro */ 54240266059SGregory Neil Shapiro 543c2aa98e2SPeter Wemm if (c >= 0200 && c <= 0237) 544c2aa98e2SPeter Wemm { 54540266059SGregory Neil Shapiro #if 0 /* causes complaints -- figure out something for 8.n+1 */ 546c2aa98e2SPeter Wemm usrerr("Illegal character 0x%x in header", c); 54706f25ae9SGregory Neil Shapiro #else /* 0 */ 54806f25ae9SGregory Neil Shapiro /* EMPTY */ 54906f25ae9SGregory Neil Shapiro #endif /* 0 */ 550c2aa98e2SPeter Wemm } 551c2aa98e2SPeter Wemm else if (c != '\0') 55225bab6e9SPeter Wemm { 553c2aa98e2SPeter Wemm *bp++ = c; 55440266059SGregory Neil Shapiro ++hdrslen; 55513058a91SGregory Neil Shapiro if (!headeronly && 55613058a91SGregory Neil Shapiro MaxHeadersLength > 0 && 557602a2b1bSGregory Neil Shapiro hdrslen > MaxHeadersLength) 55825bab6e9SPeter Wemm { 55925bab6e9SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 5602e43090eSPeter Wemm "headers too large (%d max) from %s during message collect", 5612e43090eSPeter Wemm MaxHeadersLength, 56240266059SGregory Neil Shapiro CURHOSTNAME); 56325bab6e9SPeter Wemm errno = 0; 56425bab6e9SPeter Wemm e->e_flags |= EF_CLRQUEUE; 56525bab6e9SPeter Wemm e->e_status = "5.6.0"; 56606f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 56706f25ae9SGregory Neil Shapiro "552 Headers too large (%d max)", 5682e43090eSPeter Wemm MaxHeadersLength); 56925bab6e9SPeter Wemm mstate = MS_DISCARD; 57025bab6e9SPeter Wemm } 57125bab6e9SPeter Wemm } 572c2aa98e2SPeter Wemm if (istate == IS_BOL) 573c2aa98e2SPeter Wemm break; 574c2aa98e2SPeter Wemm } 575c2aa98e2SPeter Wemm *bp = '\0'; 576c2aa98e2SPeter Wemm 577c2aa98e2SPeter Wemm nextstate: 578c2aa98e2SPeter Wemm if (tTd(30, 35)) 57940266059SGregory Neil Shapiro sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 580c2aa98e2SPeter Wemm istate, mstate, buf); 581c2aa98e2SPeter Wemm switch (mstate) 582c2aa98e2SPeter Wemm { 583c2aa98e2SPeter Wemm case MS_UFROM: 584c2aa98e2SPeter Wemm mstate = MS_HEADER; 585c2aa98e2SPeter Wemm #ifndef NOTUNIX 586c2aa98e2SPeter Wemm if (strncmp(buf, "From ", 5) == 0) 587c2aa98e2SPeter Wemm { 588c2aa98e2SPeter Wemm bp = buf; 589c2aa98e2SPeter Wemm eatfrom(buf, e); 590c2aa98e2SPeter Wemm continue; 591c2aa98e2SPeter Wemm } 59206f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 59306f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 594c2aa98e2SPeter Wemm 595c2aa98e2SPeter Wemm case MS_HEADER: 596c2aa98e2SPeter Wemm if (!isheader(buf)) 597c2aa98e2SPeter Wemm { 598c2aa98e2SPeter Wemm mstate = MS_BODY; 599c2aa98e2SPeter Wemm goto nextstate; 600c2aa98e2SPeter Wemm } 601c2aa98e2SPeter Wemm 602c2aa98e2SPeter Wemm /* check for possible continuation line */ 603c2aa98e2SPeter Wemm do 604c2aa98e2SPeter Wemm { 60540266059SGregory Neil Shapiro sm_io_clearerr(fp); 606c2aa98e2SPeter Wemm errno = 0; 60740266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 60840266059SGregory Neil Shapiro } while (c == SM_IO_EOF && errno == EINTR); 60940266059SGregory Neil Shapiro if (c != SM_IO_EOF) 61040266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 611c2aa98e2SPeter Wemm if (c == ' ' || c == '\t') 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm /* yep -- defer this */ 614c2aa98e2SPeter Wemm continue; 615c2aa98e2SPeter Wemm } 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm /* trim off trailing CRLF or NL */ 618c2aa98e2SPeter Wemm if (*--bp != '\n' || *--bp != '\r') 619c2aa98e2SPeter Wemm bp++; 620c2aa98e2SPeter Wemm *bp = '\0'; 62125bab6e9SPeter Wemm 62206f25ae9SGregory Neil Shapiro if (bitset(H_EOH, chompheader(buf, 62306f25ae9SGregory Neil Shapiro CHHDR_CHECK | CHHDR_USER, 62406f25ae9SGregory Neil Shapiro hdrp, e))) 625c2aa98e2SPeter Wemm { 626c2aa98e2SPeter Wemm mstate = MS_BODY; 627c2aa98e2SPeter Wemm goto nextstate; 628c2aa98e2SPeter Wemm } 62906f25ae9SGregory Neil Shapiro numhdrs++; 630c2aa98e2SPeter Wemm break; 631c2aa98e2SPeter Wemm 632c2aa98e2SPeter Wemm case MS_BODY: 633c2aa98e2SPeter Wemm if (tTd(30, 1)) 63440266059SGregory Neil Shapiro sm_dprintf("EOH\n"); 63506f25ae9SGregory Neil Shapiro 636c2aa98e2SPeter Wemm if (headeronly) 637c2aa98e2SPeter Wemm goto readerr; 63806f25ae9SGregory Neil Shapiro 63940266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 64040266059SGregory Neil Shapiro if (df == NULL) 64140266059SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 64206f25ae9SGregory Neil Shapiro 643c2aa98e2SPeter Wemm bp = buf; 644c2aa98e2SPeter Wemm 645c2aa98e2SPeter Wemm /* toss blank line */ 646c2aa98e2SPeter Wemm if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 647c2aa98e2SPeter Wemm bp[0] == '\r' && bp[1] == '\n') || 648c2aa98e2SPeter Wemm (!bitset(EF_NL_NOT_EOL, e->e_flags) && 649c2aa98e2SPeter Wemm bp[0] == '\n')) 650c2aa98e2SPeter Wemm { 651c2aa98e2SPeter Wemm break; 652c2aa98e2SPeter Wemm } 653c2aa98e2SPeter Wemm 654c2aa98e2SPeter Wemm /* if not a blank separator, write it out */ 65542e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 656c2aa98e2SPeter Wemm { 657c2aa98e2SPeter Wemm while (*bp != '\0') 65840266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 65940266059SGregory Neil Shapiro *bp++); 660c2aa98e2SPeter Wemm } 661c2aa98e2SPeter Wemm break; 662c2aa98e2SPeter Wemm } 663c2aa98e2SPeter Wemm bp = buf; 664c2aa98e2SPeter Wemm } 665c2aa98e2SPeter Wemm 666c2aa98e2SPeter Wemm readerr: 66740266059SGregory Neil Shapiro if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 668c2aa98e2SPeter Wemm { 66940266059SGregory Neil Shapiro const char *errmsg; 670c2aa98e2SPeter Wemm 67140266059SGregory Neil Shapiro if (sm_io_eof(fp)) 67240266059SGregory Neil Shapiro errmsg = "unexpected close"; 67340266059SGregory Neil Shapiro else 67440266059SGregory Neil Shapiro errmsg = sm_errstring(errno); 675c2aa98e2SPeter Wemm if (tTd(30, 1)) 67640266059SGregory Neil Shapiro sm_dprintf("collect: premature EOM: %s\n", errmsg); 67740266059SGregory Neil Shapiro if (LogLevel > 1) 678c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 679c2aa98e2SPeter Wemm "collect: premature EOM: %s", errmsg); 68040266059SGregory Neil Shapiro inputerr = true; 681c2aa98e2SPeter Wemm } 682c2aa98e2SPeter Wemm 683c2aa98e2SPeter Wemm /* reset global timer */ 6848774250cSGregory Neil Shapiro if (CollectTimeout != NULL) 68540266059SGregory Neil Shapiro sm_clrevent(CollectTimeout); 686c2aa98e2SPeter Wemm 687c2aa98e2SPeter Wemm if (headeronly) 688c2aa98e2SPeter Wemm return; 689c2aa98e2SPeter Wemm 69040266059SGregory Neil Shapiro if (mstate != MS_BODY) 69140266059SGregory Neil Shapiro { 69240266059SGregory Neil Shapiro /* no body or discard, so we never opened the data file */ 69340266059SGregory Neil Shapiro SM_ASSERT(df == NULL); 69440266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 69540266059SGregory Neil Shapiro } 69640266059SGregory Neil Shapiro 69706f25ae9SGregory Neil Shapiro if (df == NULL) 698c2aa98e2SPeter Wemm { 69906f25ae9SGregory Neil Shapiro /* skip next few clauses */ 70006f25ae9SGregory Neil Shapiro /* EMPTY */ 70106f25ae9SGregory Neil Shapiro } 70240266059SGregory Neil Shapiro else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 70306f25ae9SGregory Neil Shapiro { 70440266059SGregory Neil Shapiro dferror(df, "sm_io_flush||sm_io_error", e); 70540266059SGregory Neil Shapiro flush_errors(true); 70640266059SGregory Neil Shapiro finis(true, true, ExitStat); 70706f25ae9SGregory Neil Shapiro /* NOTREACHED */ 70806f25ae9SGregory Neil Shapiro } 70940266059SGregory Neil Shapiro else if (SuperSafe != SAFE_REALLY) 71006f25ae9SGregory Neil Shapiro { 71106f25ae9SGregory Neil Shapiro /* skip next few clauses */ 71206f25ae9SGregory Neil Shapiro /* EMPTY */ 71306f25ae9SGregory Neil Shapiro } 71440266059SGregory Neil Shapiro else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) 71506f25ae9SGregory Neil Shapiro { 71606f25ae9SGregory Neil Shapiro int save_errno = errno; 71706f25ae9SGregory Neil Shapiro 71806f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 71906f25ae9SGregory Neil Shapiro { 72006f25ae9SGregory Neil Shapiro char *dfile; 72106f25ae9SGregory Neil Shapiro struct stat st; 72240266059SGregory Neil Shapiro int dfd; 72306f25ae9SGregory Neil Shapiro 72440266059SGregory Neil Shapiro dfile = queuename(e, DATAFL_LETTER); 72506f25ae9SGregory Neil Shapiro if (stat(dfile, &st) < 0) 72606f25ae9SGregory Neil Shapiro st.st_size = -1; 72706f25ae9SGregory Neil Shapiro errno = EEXIST; 72840266059SGregory Neil Shapiro syserr("@collect: bfcommit(%s): already on disk, size = %ld", 72942e5d165SGregory Neil Shapiro dfile, (long) st.st_size); 73040266059SGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 73106f25ae9SGregory Neil Shapiro if (dfd >= 0) 73240266059SGregory Neil Shapiro dumpfd(dfd, true, true); 73306f25ae9SGregory Neil Shapiro } 73406f25ae9SGregory Neil Shapiro errno = save_errno; 73506f25ae9SGregory Neil Shapiro dferror(df, "bfcommit", e); 73640266059SGregory Neil Shapiro flush_errors(true); 73740266059SGregory Neil Shapiro finis(save_errno != EEXIST, true, ExitStat); 73806f25ae9SGregory Neil Shapiro } 73940266059SGregory Neil Shapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 && 74040266059SGregory Neil Shapiro fsync(afd) < 0) 741602a2b1bSGregory Neil Shapiro { 74240266059SGregory Neil Shapiro dferror(df, "fsync", e); 74340266059SGregory Neil Shapiro flush_errors(true); 74440266059SGregory Neil Shapiro finis(true, true, ExitStat); 745602a2b1bSGregory Neil Shapiro /* NOTREACHED */ 746602a2b1bSGregory Neil Shapiro } 74740266059SGregory Neil Shapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 74806f25ae9SGregory Neil Shapiro { 74940266059SGregory Neil Shapiro dferror(df, "sm_io_close", e); 75040266059SGregory Neil Shapiro flush_errors(true); 75140266059SGregory Neil Shapiro finis(true, true, ExitStat); 75206f25ae9SGregory Neil Shapiro /* NOTREACHED */ 75306f25ae9SGregory Neil Shapiro } 75406f25ae9SGregory Neil Shapiro else 75506f25ae9SGregory Neil Shapiro { 75606f25ae9SGregory Neil Shapiro /* everything is happily flushed to disk */ 75706f25ae9SGregory Neil Shapiro df = NULL; 75840266059SGregory Neil Shapiro 75940266059SGregory Neil Shapiro /* remove from available space in filesystem */ 76040266059SGregory Neil Shapiro updfs(e, false, true); 761c2aa98e2SPeter Wemm } 762c2aa98e2SPeter Wemm 763c2aa98e2SPeter Wemm /* An EOF when running SMTP is an error */ 764c2aa98e2SPeter Wemm if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 765c2aa98e2SPeter Wemm { 766c2aa98e2SPeter Wemm char *host; 767c2aa98e2SPeter Wemm char *problem; 768c2aa98e2SPeter Wemm 769c2aa98e2SPeter Wemm host = RealHostName; 770c2aa98e2SPeter Wemm if (host == NULL) 771c2aa98e2SPeter Wemm host = "localhost"; 772c2aa98e2SPeter Wemm 77340266059SGregory Neil Shapiro if (sm_io_eof(fp)) 774c2aa98e2SPeter Wemm problem = "unexpected close"; 77540266059SGregory Neil Shapiro else if (sm_io_error(fp)) 776c2aa98e2SPeter Wemm problem = "I/O error"; 777c2aa98e2SPeter Wemm else 778c2aa98e2SPeter Wemm problem = "read timeout"; 77940266059SGregory Neil Shapiro if (LogLevel > 0 && sm_io_eof(fp)) 780c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 78140266059SGregory Neil Shapiro "collect: %s on connection from %.100s, sender=%s", 782c2aa98e2SPeter Wemm problem, host, 78340266059SGregory Neil Shapiro shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 78440266059SGregory Neil Shapiro if (sm_io_eof(fp)) 78506f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 786c2aa98e2SPeter Wemm problem, host, 787c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 788c2aa98e2SPeter Wemm else 78906f25ae9SGregory Neil Shapiro syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 790c2aa98e2SPeter Wemm problem, host, 791c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 792c2aa98e2SPeter Wemm 793c2aa98e2SPeter Wemm /* don't return an error indication */ 794c2aa98e2SPeter Wemm e->e_to = NULL; 795c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 796c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 797c2aa98e2SPeter Wemm 79840266059SGregory Neil Shapiro finis(true, true, ExitStat); 79906f25ae9SGregory Neil Shapiro /* NOTREACHED */ 800c2aa98e2SPeter Wemm } 801c2aa98e2SPeter Wemm 80240266059SGregory Neil Shapiro /* Log collection information. */ 80340266059SGregory Neil Shapiro if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 804c2aa98e2SPeter Wemm { 80540266059SGregory Neil Shapiro logsender(e, e->e_msgid); 80640266059SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER; 807c2aa98e2SPeter Wemm } 808c2aa98e2SPeter Wemm 809c2aa98e2SPeter Wemm /* check for message too large */ 81042e5d165SGregory Neil Shapiro if (bitset(EF_TOOBIG, e->e_flags)) 811c2aa98e2SPeter Wemm { 812c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 81340266059SGregory Neil Shapiro if (!bitset(EF_FATALERRS, e->e_flags)) 81440266059SGregory Neil Shapiro { 815c2aa98e2SPeter Wemm e->e_status = "5.2.3"; 81606f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 81706f25ae9SGregory Neil Shapiro "552 Message exceeds maximum fixed size (%ld)", 818c2aa98e2SPeter Wemm MaxMessageSize); 819c2aa98e2SPeter Wemm if (LogLevel > 6) 820c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 821c2aa98e2SPeter Wemm "message size (%ld) exceeds maximum (%ld)", 822c2aa98e2SPeter Wemm e->e_msgsize, MaxMessageSize); 823c2aa98e2SPeter Wemm } 82440266059SGregory Neil Shapiro } 825c2aa98e2SPeter Wemm 826c2aa98e2SPeter Wemm /* check for illegal 8-bit data */ 827c2aa98e2SPeter Wemm if (HasEightBits) 828c2aa98e2SPeter Wemm { 829c2aa98e2SPeter Wemm e->e_flags |= EF_HAS8BIT; 830c2aa98e2SPeter Wemm if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 831c2aa98e2SPeter Wemm !bitset(EF_IS_MIME, e->e_flags)) 832c2aa98e2SPeter Wemm { 833c2aa98e2SPeter Wemm e->e_status = "5.6.1"; 83406f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 835c2aa98e2SPeter Wemm } 836c2aa98e2SPeter Wemm } 837c2aa98e2SPeter Wemm else 838c2aa98e2SPeter Wemm { 839c2aa98e2SPeter Wemm /* if it claimed to be 8 bits, well, it lied.... */ 840c2aa98e2SPeter Wemm if (e->e_bodytype != NULL && 84140266059SGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 842c2aa98e2SPeter Wemm e->e_bodytype = "7BIT"; 843c2aa98e2SPeter Wemm } 844c2aa98e2SPeter Wemm 84540266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 84606f25ae9SGregory Neil Shapiro { 84740266059SGregory Neil Shapiro char *dfname = queuename(e, DATAFL_LETTER); 84840266059SGregory Neil Shapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 84940266059SGregory Neil Shapiro SM_IO_RDONLY, NULL)) == NULL) 850c2aa98e2SPeter Wemm { 851c2aa98e2SPeter Wemm /* we haven't acked receipt yet, so just chuck this */ 85240266059SGregory Neil Shapiro syserr("@Cannot reopen %s", dfname); 85340266059SGregory Neil Shapiro finis(true, true, ExitStat); 85406f25ae9SGregory Neil Shapiro /* NOTREACHED */ 855c2aa98e2SPeter Wemm } 856c2aa98e2SPeter Wemm } 85706f25ae9SGregory Neil Shapiro else 85806f25ae9SGregory Neil Shapiro e->e_dfp = df; 859605302a5SGregory Neil Shapiro 860605302a5SGregory Neil Shapiro /* collect statistics */ 861605302a5SGregory Neil Shapiro if (OpMode != MD_VERIFY) 862605302a5SGregory Neil Shapiro markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 86306f25ae9SGregory Neil Shapiro } 864c2aa98e2SPeter Wemm 865c2aa98e2SPeter Wemm static void 866c2aa98e2SPeter Wemm collecttimeout(timeout) 867c2aa98e2SPeter Wemm time_t timeout; 868c2aa98e2SPeter Wemm { 8698774250cSGregory Neil Shapiro int save_errno = errno; 870c2aa98e2SPeter Wemm 8718774250cSGregory Neil Shapiro /* 8728774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 8738774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 8748774250cSGregory Neil Shapiro ** DOING. 8758774250cSGregory Neil Shapiro */ 8768774250cSGregory Neil Shapiro 8778774250cSGregory Neil Shapiro if (CollectProgress) 8788774250cSGregory Neil Shapiro { 8798774250cSGregory Neil Shapiro /* reset the timeout */ 88040266059SGregory Neil Shapiro CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout, 8818774250cSGregory Neil Shapiro timeout); 88240266059SGregory Neil Shapiro CollectProgress = false; 883c2aa98e2SPeter Wemm } 8848774250cSGregory Neil Shapiro else 8858774250cSGregory Neil Shapiro { 8868774250cSGregory Neil Shapiro /* event is done */ 8878774250cSGregory Neil Shapiro CollectTimeout = NULL; 8888774250cSGregory Neil Shapiro } 8898774250cSGregory Neil Shapiro 8908774250cSGregory Neil Shapiro /* if no progress was made or problem resetting event, die now */ 8918774250cSGregory Neil Shapiro if (CollectTimeout == NULL) 8928774250cSGregory Neil Shapiro { 8938774250cSGregory Neil Shapiro errno = ETIMEDOUT; 8948774250cSGregory Neil Shapiro longjmp(CtxCollectTimeout, 1); 8958774250cSGregory Neil Shapiro } 8968774250cSGregory Neil Shapiro errno = save_errno; 8978774250cSGregory Neil Shapiro } 89840266059SGregory Neil Shapiro /* 89906f25ae9SGregory Neil Shapiro ** DFERROR -- signal error on writing the data file. 900c2aa98e2SPeter Wemm ** 90140266059SGregory Neil Shapiro ** Called by collect(). Collect() always terminates the process 90240266059SGregory Neil Shapiro ** immediately after calling dferror(), which means that the SMTP 90340266059SGregory Neil Shapiro ** session will be terminated, which means that any error message 90440266059SGregory Neil Shapiro ** issued by dferror must be a 421 error, as per RFC 821. 90540266059SGregory Neil Shapiro ** 906c2aa98e2SPeter Wemm ** Parameters: 90706f25ae9SGregory Neil Shapiro ** df -- the file pointer for the data file. 90806f25ae9SGregory Neil Shapiro ** msg -- detailed message. 909c2aa98e2SPeter Wemm ** e -- the current envelope. 910c2aa98e2SPeter Wemm ** 911c2aa98e2SPeter Wemm ** Returns: 912c2aa98e2SPeter Wemm ** none. 913c2aa98e2SPeter Wemm ** 914c2aa98e2SPeter Wemm ** Side Effects: 915c2aa98e2SPeter Wemm ** Gives an error message. 916c2aa98e2SPeter Wemm ** Arranges for following output to go elsewhere. 917c2aa98e2SPeter Wemm */ 918c2aa98e2SPeter Wemm 91906f25ae9SGregory Neil Shapiro static void 92006f25ae9SGregory Neil Shapiro dferror(df, msg, e) 92140266059SGregory Neil Shapiro SM_FILE_T *volatile df; 92206f25ae9SGregory Neil Shapiro char *msg; 923c2aa98e2SPeter Wemm register ENVELOPE *e; 924c2aa98e2SPeter Wemm { 92506f25ae9SGregory Neil Shapiro char *dfname; 92606f25ae9SGregory Neil Shapiro 92740266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 928c2aa98e2SPeter Wemm setstat(EX_IOERR); 929c2aa98e2SPeter Wemm if (errno == ENOSPC) 930c2aa98e2SPeter Wemm { 931c2aa98e2SPeter Wemm #if STAT64 > 0 932c2aa98e2SPeter Wemm struct stat64 st; 93306f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 934c2aa98e2SPeter Wemm struct stat st; 93506f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 936c2aa98e2SPeter Wemm long avail; 937c2aa98e2SPeter Wemm long bsize; 938c2aa98e2SPeter Wemm 939c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 940c2aa98e2SPeter Wemm 941c2aa98e2SPeter Wemm if ( 942c2aa98e2SPeter Wemm #if STAT64 > 0 94340266059SGregory Neil Shapiro fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 94406f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 94540266059SGregory Neil Shapiro fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 94606f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 947c2aa98e2SPeter Wemm < 0) 948c2aa98e2SPeter Wemm st.st_size = 0; 94940266059SGregory Neil Shapiro (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 95040266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df); 951c2aa98e2SPeter Wemm if (st.st_size <= 0) 95240266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 95340266059SGregory Neil Shapiro "\n*** Mail could not be accepted"); 954c2aa98e2SPeter Wemm else 95540266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 95640266059SGregory Neil Shapiro "\n*** Mail of at least %llu bytes could not be accepted\n", 95740266059SGregory Neil Shapiro (ULONGLONG_T) st.st_size); 95840266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 95940266059SGregory Neil Shapiro "*** at %s due to lack of disk space for temp file.\n", 960c2aa98e2SPeter Wemm MyHostName); 96140266059SGregory Neil Shapiro avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 96240266059SGregory Neil Shapiro &bsize); 963c2aa98e2SPeter Wemm if (avail > 0) 964c2aa98e2SPeter Wemm { 965c2aa98e2SPeter Wemm if (bsize > 1024) 966c2aa98e2SPeter Wemm avail *= bsize / 1024; 967c2aa98e2SPeter Wemm else if (bsize < 1024) 968c2aa98e2SPeter Wemm avail /= 1024 / bsize; 96940266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 97040266059SGregory Neil Shapiro "*** Currently, %ld kilobytes are available for mail temp files.\n", 971c2aa98e2SPeter Wemm avail); 972c2aa98e2SPeter Wemm } 97340266059SGregory Neil Shapiro #if 0 97440266059SGregory Neil Shapiro /* Wrong response code; should be 421. */ 975c2aa98e2SPeter Wemm e->e_status = "4.3.1"; 97606f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 97740266059SGregory Neil Shapiro #else /* 0 */ 97840266059SGregory Neil Shapiro syserr("421 4.3.1 Out of disk space for temp file"); 97940266059SGregory Neil Shapiro #endif /* 0 */ 980c2aa98e2SPeter Wemm } 981c2aa98e2SPeter Wemm else 98240266059SGregory Neil Shapiro syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", 98394c01205SGregory Neil Shapiro dfname, msg, (int) geteuid(), (int) getegid()); 98440266059SGregory Neil Shapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 98540266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df) == NULL) 986c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 98740266059SGregory Neil Shapiro "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 98840266059SGregory Neil Shapiro sm_errstring(errno)); 989c2aa98e2SPeter Wemm } 99040266059SGregory Neil Shapiro /* 991c2aa98e2SPeter Wemm ** EATFROM -- chew up a UNIX style from line and process 992c2aa98e2SPeter Wemm ** 993c2aa98e2SPeter Wemm ** This does indeed make some assumptions about the format 994c2aa98e2SPeter Wemm ** of UNIX messages. 995c2aa98e2SPeter Wemm ** 996c2aa98e2SPeter Wemm ** Parameters: 997c2aa98e2SPeter Wemm ** fm -- the from line. 998c2aa98e2SPeter Wemm ** 999c2aa98e2SPeter Wemm ** Returns: 1000c2aa98e2SPeter Wemm ** none. 1001c2aa98e2SPeter Wemm ** 1002c2aa98e2SPeter Wemm ** Side Effects: 1003c2aa98e2SPeter Wemm ** extracts what information it can from the header, 1004c2aa98e2SPeter Wemm ** such as the date. 1005c2aa98e2SPeter Wemm */ 1006c2aa98e2SPeter Wemm 1007c2aa98e2SPeter Wemm #ifndef NOTUNIX 1008c2aa98e2SPeter Wemm 100906f25ae9SGregory Neil Shapiro static char *DowList[] = 1010c2aa98e2SPeter Wemm { 1011c2aa98e2SPeter Wemm "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 1012c2aa98e2SPeter Wemm }; 1013c2aa98e2SPeter Wemm 101406f25ae9SGregory Neil Shapiro static char *MonthList[] = 1015c2aa98e2SPeter Wemm { 1016c2aa98e2SPeter Wemm "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1017c2aa98e2SPeter Wemm "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 1018c2aa98e2SPeter Wemm NULL 1019c2aa98e2SPeter Wemm }; 1020c2aa98e2SPeter Wemm 102106f25ae9SGregory Neil Shapiro static void 1022c2aa98e2SPeter Wemm eatfrom(fm, e) 1023c2aa98e2SPeter Wemm char *volatile fm; 1024c2aa98e2SPeter Wemm register ENVELOPE *e; 1025c2aa98e2SPeter Wemm { 1026c2aa98e2SPeter Wemm register char *p; 1027c2aa98e2SPeter Wemm register char **dt; 1028c2aa98e2SPeter Wemm 1029c2aa98e2SPeter Wemm if (tTd(30, 2)) 103040266059SGregory Neil Shapiro sm_dprintf("eatfrom(%s)\n", fm); 1031c2aa98e2SPeter Wemm 1032c2aa98e2SPeter Wemm /* find the date part */ 1033c2aa98e2SPeter Wemm p = fm; 1034c2aa98e2SPeter Wemm while (*p != '\0') 1035c2aa98e2SPeter Wemm { 1036c2aa98e2SPeter Wemm /* skip a word */ 1037c2aa98e2SPeter Wemm while (*p != '\0' && *p != ' ') 1038c2aa98e2SPeter Wemm p++; 1039c2aa98e2SPeter Wemm while (*p == ' ') 1040c2aa98e2SPeter Wemm p++; 1041193538b7SGregory Neil Shapiro if (strlen(p) < 17) 1042193538b7SGregory Neil Shapiro { 1043193538b7SGregory Neil Shapiro /* no room for the date */ 1044193538b7SGregory Neil Shapiro return; 1045193538b7SGregory Neil Shapiro } 1046c2aa98e2SPeter Wemm if (!(isascii(*p) && isupper(*p)) || 1047c2aa98e2SPeter Wemm p[3] != ' ' || p[13] != ':' || p[16] != ':') 1048c2aa98e2SPeter Wemm continue; 1049c2aa98e2SPeter Wemm 1050c2aa98e2SPeter Wemm /* we have a possible date */ 1051c2aa98e2SPeter Wemm for (dt = DowList; *dt != NULL; dt++) 1052c2aa98e2SPeter Wemm if (strncmp(*dt, p, 3) == 0) 1053c2aa98e2SPeter Wemm break; 1054c2aa98e2SPeter Wemm if (*dt == NULL) 1055c2aa98e2SPeter Wemm continue; 1056c2aa98e2SPeter Wemm 1057c2aa98e2SPeter Wemm for (dt = MonthList; *dt != NULL; dt++) 1058193538b7SGregory Neil Shapiro { 1059c2aa98e2SPeter Wemm if (strncmp(*dt, &p[4], 3) == 0) 1060c2aa98e2SPeter Wemm break; 1061193538b7SGregory Neil Shapiro } 1062c2aa98e2SPeter Wemm if (*dt != NULL) 1063c2aa98e2SPeter Wemm break; 1064c2aa98e2SPeter Wemm } 1065c2aa98e2SPeter Wemm 1066c2aa98e2SPeter Wemm if (*p != '\0') 1067c2aa98e2SPeter Wemm { 106840266059SGregory Neil Shapiro char *q, buf[25]; 1069c2aa98e2SPeter Wemm 1070c2aa98e2SPeter Wemm /* we have found a date */ 107140266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p, sizeof(buf)); 107240266059SGregory Neil Shapiro q = arpadate(buf); 107340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'a', q); 1074c2aa98e2SPeter Wemm } 1075c2aa98e2SPeter Wemm } 107606f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 1077