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 1613bd1963SGregory Neil Shapiro SM_RCSID("@(#)$Id: collect.c,v 8.242.2.3 2002/12/03 17:06:30 gshapiro 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); 63959366dcSGregory Neil Shapiro (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT, 64959366dcSGregory Neil Shapiro 3, NULL, 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; 35313bd1963SGregory Neil Shapiro if (smtpmode) 35413bd1963SGregory Neil Shapiro { 35513bd1963SGregory Neil Shapiro /* 35613bd1963SGregory Neil Shapiro ** Override e_message in usrerr() as this 35713bd1963SGregory Neil Shapiro ** is the reason for failure that should 35813bd1963SGregory Neil Shapiro ** be logged for undelivered recipients. 35913bd1963SGregory Neil Shapiro */ 36013bd1963SGregory Neil Shapiro 36113bd1963SGregory Neil Shapiro e->e_message = NULL; 36213bd1963SGregory Neil Shapiro } 36306f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 timeout waiting for input during message collect"); 364c2aa98e2SPeter Wemm goto readerr; 365c2aa98e2SPeter Wemm } 36640266059SGregory Neil Shapiro CollectTimeout = sm_setevent(dbto, collecttimeout, dbto); 367c2aa98e2SPeter Wemm } 368c2aa98e2SPeter Wemm 36940266059SGregory Neil Shapiro e->e_msgsize = 0; 370c2aa98e2SPeter Wemm for (;;) 371c2aa98e2SPeter Wemm { 372c2aa98e2SPeter Wemm if (tTd(30, 35)) 37340266059SGregory Neil Shapiro sm_dprintf("top, istate=%d, mstate=%d\n", istate, 37440266059SGregory Neil Shapiro mstate); 375c2aa98e2SPeter Wemm for (;;) 376c2aa98e2SPeter Wemm { 377c2aa98e2SPeter Wemm if (pbp > peekbuf) 378c2aa98e2SPeter Wemm c = *--pbp; 379c2aa98e2SPeter Wemm else 380c2aa98e2SPeter Wemm { 38140266059SGregory Neil Shapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 382c2aa98e2SPeter Wemm { 383c2aa98e2SPeter Wemm errno = 0; 38440266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 38540266059SGregory Neil Shapiro if (c == SM_IO_EOF && errno == EINTR) 38642e5d165SGregory Neil Shapiro { 38742e5d165SGregory Neil Shapiro /* Interrupted, retry */ 38840266059SGregory Neil Shapiro sm_io_clearerr(fp); 38942e5d165SGregory Neil Shapiro continue; 39042e5d165SGregory Neil Shapiro } 39142e5d165SGregory Neil Shapiro break; 392c2aa98e2SPeter Wemm } 39340266059SGregory Neil Shapiro CollectProgress = true; 394c2aa98e2SPeter Wemm if (TrafficLogFile != NULL && !headeronly) 395c2aa98e2SPeter Wemm { 396c2aa98e2SPeter Wemm if (istate == IS_BOL) 39740266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 39840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 3998774250cSGregory Neil Shapiro "%05d <<< ", 40040266059SGregory Neil Shapiro (int) CurrentPid); 40140266059SGregory Neil Shapiro if (c == SM_IO_EOF) 40240266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 40340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 4048774250cSGregory Neil Shapiro "[EOF]\n"); 405c2aa98e2SPeter Wemm else 40640266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 40740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 40840266059SGregory Neil Shapiro c); 409c2aa98e2SPeter Wemm } 41040266059SGregory Neil Shapiro if (c == SM_IO_EOF) 411c2aa98e2SPeter Wemm goto readerr; 412c2aa98e2SPeter Wemm if (SevenBitInput) 413c2aa98e2SPeter Wemm c &= 0x7f; 414c2aa98e2SPeter Wemm else 415c2aa98e2SPeter Wemm HasEightBits |= bitset(0x80, c); 416c2aa98e2SPeter Wemm } 417c2aa98e2SPeter Wemm if (tTd(30, 94)) 41840266059SGregory Neil Shapiro sm_dprintf("istate=%d, c=%c (0x%x)\n", 41906f25ae9SGregory Neil Shapiro istate, (char) c, c); 420c2aa98e2SPeter Wemm switch (istate) 421c2aa98e2SPeter Wemm { 422c2aa98e2SPeter Wemm case IS_BOL: 423c2aa98e2SPeter Wemm if (c == '.') 424c2aa98e2SPeter Wemm { 425c2aa98e2SPeter Wemm istate = IS_DOT; 426c2aa98e2SPeter Wemm continue; 427c2aa98e2SPeter Wemm } 428c2aa98e2SPeter Wemm break; 429c2aa98e2SPeter Wemm 430c2aa98e2SPeter Wemm case IS_DOT: 431c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot && 432c2aa98e2SPeter Wemm !bitset(EF_NL_NOT_EOL, e->e_flags)) 433c2aa98e2SPeter Wemm goto readerr; 434c2aa98e2SPeter Wemm else if (c == '\r' && 435c2aa98e2SPeter Wemm !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 436c2aa98e2SPeter Wemm { 437c2aa98e2SPeter Wemm istate = IS_DOTCR; 438c2aa98e2SPeter Wemm continue; 439c2aa98e2SPeter Wemm } 440605302a5SGregory Neil Shapiro else if (ignrdot || 441605302a5SGregory Neil Shapiro (c != '.' && 442605302a5SGregory Neil Shapiro OpMode != MD_SMTP && 443c2aa98e2SPeter Wemm OpMode != MD_DAEMON && 444c2aa98e2SPeter Wemm OpMode != MD_ARPAFTP)) 445605302a5SGregory Neil Shapiro 446c2aa98e2SPeter Wemm { 447c2aa98e2SPeter Wemm *pbp++ = c; 448c2aa98e2SPeter Wemm c = '.'; 449c2aa98e2SPeter Wemm } 450c2aa98e2SPeter Wemm break; 451c2aa98e2SPeter Wemm 452c2aa98e2SPeter Wemm case IS_DOTCR: 453c2aa98e2SPeter Wemm if (c == '\n' && !ignrdot) 454c2aa98e2SPeter Wemm goto readerr; 455c2aa98e2SPeter Wemm else 456c2aa98e2SPeter Wemm { 457c2aa98e2SPeter Wemm /* push back the ".\rx" */ 458c2aa98e2SPeter Wemm *pbp++ = c; 459605302a5SGregory Neil Shapiro if (OpMode != MD_SMTP && 460605302a5SGregory Neil Shapiro OpMode != MD_DAEMON && 461605302a5SGregory Neil Shapiro OpMode != MD_ARPAFTP) 462605302a5SGregory Neil Shapiro { 463c2aa98e2SPeter Wemm *pbp++ = '\r'; 464c2aa98e2SPeter Wemm c = '.'; 465c2aa98e2SPeter Wemm } 466605302a5SGregory Neil Shapiro else 467605302a5SGregory Neil Shapiro c = '\r'; 468605302a5SGregory Neil Shapiro } 469c2aa98e2SPeter Wemm break; 470c2aa98e2SPeter Wemm 471c2aa98e2SPeter Wemm case IS_CR: 472c2aa98e2SPeter Wemm if (c == '\n') 473c2aa98e2SPeter Wemm istate = IS_BOL; 474c2aa98e2SPeter Wemm else 475c2aa98e2SPeter Wemm { 47640266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 47740266059SGregory Neil Shapiro c); 478c2aa98e2SPeter Wemm c = '\r'; 479c2aa98e2SPeter Wemm istate = IS_NORM; 480c2aa98e2SPeter Wemm } 481c2aa98e2SPeter Wemm goto bufferchar; 482c2aa98e2SPeter Wemm } 483c2aa98e2SPeter Wemm 484c2aa98e2SPeter Wemm if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 485c2aa98e2SPeter Wemm { 486c2aa98e2SPeter Wemm istate = IS_CR; 487c2aa98e2SPeter Wemm continue; 488c2aa98e2SPeter Wemm } 48940266059SGregory Neil Shapiro else if (c == '\n' && !bitset(EF_NL_NOT_EOL, 49040266059SGregory Neil Shapiro e->e_flags)) 491c2aa98e2SPeter Wemm istate = IS_BOL; 492c2aa98e2SPeter Wemm else 493c2aa98e2SPeter Wemm istate = IS_NORM; 494c2aa98e2SPeter Wemm 495c2aa98e2SPeter Wemm bufferchar: 496c2aa98e2SPeter Wemm if (!headeronly) 49742e5d165SGregory Neil Shapiro { 49842e5d165SGregory Neil Shapiro /* no overflow? */ 49942e5d165SGregory Neil Shapiro if (e->e_msgsize >= 0) 50042e5d165SGregory Neil Shapiro { 501c2aa98e2SPeter Wemm e->e_msgsize++; 50242e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 && 50342e5d165SGregory Neil Shapiro !bitset(EF_TOOBIG, e->e_flags) && 50442e5d165SGregory Neil Shapiro e->e_msgsize > MaxMessageSize) 50542e5d165SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 50642e5d165SGregory Neil Shapiro } 50742e5d165SGregory Neil Shapiro } 50825bab6e9SPeter Wemm switch (mstate) 509c2aa98e2SPeter Wemm { 51025bab6e9SPeter Wemm case MS_BODY: 511c2aa98e2SPeter Wemm /* just put the character out */ 51242e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 51340266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 51440266059SGregory Neil Shapiro c); 51540266059SGregory Neil Shapiro 51606f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 51725bab6e9SPeter Wemm 51825bab6e9SPeter Wemm case MS_DISCARD: 519c2aa98e2SPeter Wemm continue; 520c2aa98e2SPeter Wemm } 521c2aa98e2SPeter Wemm 522c2aa98e2SPeter Wemm /* header -- buffer up */ 523c2aa98e2SPeter Wemm if (bp >= &buf[buflen - 2]) 524c2aa98e2SPeter Wemm { 525c2aa98e2SPeter Wemm char *obuf; 526c2aa98e2SPeter Wemm 527c2aa98e2SPeter Wemm if (mstate != MS_HEADER) 528c2aa98e2SPeter Wemm break; 529c2aa98e2SPeter Wemm 530c2aa98e2SPeter Wemm /* out of space for header */ 531c2aa98e2SPeter Wemm obuf = buf; 532c2aa98e2SPeter Wemm if (buflen < MEMCHUNKSIZE) 533c2aa98e2SPeter Wemm buflen *= 2; 534c2aa98e2SPeter Wemm else 535c2aa98e2SPeter Wemm buflen += MEMCHUNKSIZE; 536c2aa98e2SPeter Wemm buf = xalloc(buflen); 53706f25ae9SGregory Neil Shapiro memmove(buf, obuf, bp - obuf); 538c2aa98e2SPeter Wemm bp = &buf[bp - obuf]; 539c2aa98e2SPeter Wemm if (obuf != bufbuf) 54040266059SGregory Neil Shapiro sm_free(obuf); /* XXX */ 541c2aa98e2SPeter Wemm } 54240266059SGregory Neil Shapiro 54340266059SGregory Neil Shapiro /* 54440266059SGregory Neil Shapiro ** XXX Notice: the logic here is broken. 54540266059SGregory Neil Shapiro ** An input to sendmail that doesn't contain a 54640266059SGregory Neil Shapiro ** header but starts immediately with the body whose 54740266059SGregory Neil Shapiro ** first line contain characters which match the 54840266059SGregory Neil Shapiro ** following "if" will cause problems: those 54940266059SGregory Neil Shapiro ** characters will NOT appear in the output... 55040266059SGregory Neil Shapiro ** Do we care? 55140266059SGregory Neil Shapiro */ 55240266059SGregory Neil Shapiro 553c2aa98e2SPeter Wemm if (c >= 0200 && c <= 0237) 554c2aa98e2SPeter Wemm { 55540266059SGregory Neil Shapiro #if 0 /* causes complaints -- figure out something for 8.n+1 */ 556c2aa98e2SPeter Wemm usrerr("Illegal character 0x%x in header", c); 55706f25ae9SGregory Neil Shapiro #else /* 0 */ 55806f25ae9SGregory Neil Shapiro /* EMPTY */ 55906f25ae9SGregory Neil Shapiro #endif /* 0 */ 560c2aa98e2SPeter Wemm } 561c2aa98e2SPeter Wemm else if (c != '\0') 56225bab6e9SPeter Wemm { 563c2aa98e2SPeter Wemm *bp++ = c; 56440266059SGregory Neil Shapiro ++hdrslen; 56513058a91SGregory Neil Shapiro if (!headeronly && 56613058a91SGregory Neil Shapiro MaxHeadersLength > 0 && 567602a2b1bSGregory Neil Shapiro hdrslen > MaxHeadersLength) 56825bab6e9SPeter Wemm { 56925bab6e9SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 5702e43090eSPeter Wemm "headers too large (%d max) from %s during message collect", 5712e43090eSPeter Wemm MaxHeadersLength, 57240266059SGregory Neil Shapiro CURHOSTNAME); 57325bab6e9SPeter Wemm errno = 0; 57425bab6e9SPeter Wemm e->e_flags |= EF_CLRQUEUE; 57525bab6e9SPeter Wemm e->e_status = "5.6.0"; 57606f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 57706f25ae9SGregory Neil Shapiro "552 Headers too large (%d max)", 5782e43090eSPeter Wemm MaxHeadersLength); 57925bab6e9SPeter Wemm mstate = MS_DISCARD; 58025bab6e9SPeter Wemm } 58125bab6e9SPeter Wemm } 582c2aa98e2SPeter Wemm if (istate == IS_BOL) 583c2aa98e2SPeter Wemm break; 584c2aa98e2SPeter Wemm } 585c2aa98e2SPeter Wemm *bp = '\0'; 586c2aa98e2SPeter Wemm 587c2aa98e2SPeter Wemm nextstate: 588c2aa98e2SPeter Wemm if (tTd(30, 35)) 58940266059SGregory Neil Shapiro sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 590c2aa98e2SPeter Wemm istate, mstate, buf); 591c2aa98e2SPeter Wemm switch (mstate) 592c2aa98e2SPeter Wemm { 593c2aa98e2SPeter Wemm case MS_UFROM: 594c2aa98e2SPeter Wemm mstate = MS_HEADER; 595c2aa98e2SPeter Wemm #ifndef NOTUNIX 596c2aa98e2SPeter Wemm if (strncmp(buf, "From ", 5) == 0) 597c2aa98e2SPeter Wemm { 598c2aa98e2SPeter Wemm bp = buf; 599c2aa98e2SPeter Wemm eatfrom(buf, e); 600c2aa98e2SPeter Wemm continue; 601c2aa98e2SPeter Wemm } 60206f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 60306f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 604c2aa98e2SPeter Wemm 605c2aa98e2SPeter Wemm case MS_HEADER: 606c2aa98e2SPeter Wemm if (!isheader(buf)) 607c2aa98e2SPeter Wemm { 608c2aa98e2SPeter Wemm mstate = MS_BODY; 609c2aa98e2SPeter Wemm goto nextstate; 610c2aa98e2SPeter Wemm } 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm /* check for possible continuation line */ 613c2aa98e2SPeter Wemm do 614c2aa98e2SPeter Wemm { 61540266059SGregory Neil Shapiro sm_io_clearerr(fp); 616c2aa98e2SPeter Wemm errno = 0; 61740266059SGregory Neil Shapiro c = sm_io_getc(fp, SM_TIME_DEFAULT); 61840266059SGregory Neil Shapiro } while (c == SM_IO_EOF && errno == EINTR); 61940266059SGregory Neil Shapiro if (c != SM_IO_EOF) 62040266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 621c2aa98e2SPeter Wemm if (c == ' ' || c == '\t') 622c2aa98e2SPeter Wemm { 623c2aa98e2SPeter Wemm /* yep -- defer this */ 624c2aa98e2SPeter Wemm continue; 625c2aa98e2SPeter Wemm } 626c2aa98e2SPeter Wemm 627c2aa98e2SPeter Wemm /* trim off trailing CRLF or NL */ 628c2aa98e2SPeter Wemm if (*--bp != '\n' || *--bp != '\r') 629c2aa98e2SPeter Wemm bp++; 630c2aa98e2SPeter Wemm *bp = '\0'; 63125bab6e9SPeter Wemm 63206f25ae9SGregory Neil Shapiro if (bitset(H_EOH, chompheader(buf, 63306f25ae9SGregory Neil Shapiro CHHDR_CHECK | CHHDR_USER, 63406f25ae9SGregory Neil Shapiro hdrp, e))) 635c2aa98e2SPeter Wemm { 636c2aa98e2SPeter Wemm mstate = MS_BODY; 637c2aa98e2SPeter Wemm goto nextstate; 638c2aa98e2SPeter Wemm } 63906f25ae9SGregory Neil Shapiro numhdrs++; 640c2aa98e2SPeter Wemm break; 641c2aa98e2SPeter Wemm 642c2aa98e2SPeter Wemm case MS_BODY: 643c2aa98e2SPeter Wemm if (tTd(30, 1)) 64440266059SGregory Neil Shapiro sm_dprintf("EOH\n"); 64506f25ae9SGregory Neil Shapiro 646c2aa98e2SPeter Wemm if (headeronly) 647c2aa98e2SPeter Wemm goto readerr; 64806f25ae9SGregory Neil Shapiro 64940266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 65040266059SGregory Neil Shapiro if (df == NULL) 65140266059SGregory Neil Shapiro e->e_flags |= EF_TOOBIG; 65206f25ae9SGregory Neil Shapiro 653c2aa98e2SPeter Wemm bp = buf; 654c2aa98e2SPeter Wemm 655c2aa98e2SPeter Wemm /* toss blank line */ 656c2aa98e2SPeter Wemm if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 657c2aa98e2SPeter Wemm bp[0] == '\r' && bp[1] == '\n') || 658c2aa98e2SPeter Wemm (!bitset(EF_NL_NOT_EOL, e->e_flags) && 659c2aa98e2SPeter Wemm bp[0] == '\n')) 660c2aa98e2SPeter Wemm { 661c2aa98e2SPeter Wemm break; 662c2aa98e2SPeter Wemm } 663c2aa98e2SPeter Wemm 664c2aa98e2SPeter Wemm /* if not a blank separator, write it out */ 66542e5d165SGregory Neil Shapiro if (!bitset(EF_TOOBIG, e->e_flags)) 666c2aa98e2SPeter Wemm { 667c2aa98e2SPeter Wemm while (*bp != '\0') 66840266059SGregory Neil Shapiro (void) sm_io_putc(df, SM_TIME_DEFAULT, 66940266059SGregory Neil Shapiro *bp++); 670c2aa98e2SPeter Wemm } 671c2aa98e2SPeter Wemm break; 672c2aa98e2SPeter Wemm } 673c2aa98e2SPeter Wemm bp = buf; 674c2aa98e2SPeter Wemm } 675c2aa98e2SPeter Wemm 676c2aa98e2SPeter Wemm readerr: 67740266059SGregory Neil Shapiro if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) 678c2aa98e2SPeter Wemm { 67940266059SGregory Neil Shapiro const char *errmsg; 680c2aa98e2SPeter Wemm 68140266059SGregory Neil Shapiro if (sm_io_eof(fp)) 68240266059SGregory Neil Shapiro errmsg = "unexpected close"; 68340266059SGregory Neil Shapiro else 68440266059SGregory Neil Shapiro errmsg = sm_errstring(errno); 685c2aa98e2SPeter Wemm if (tTd(30, 1)) 68640266059SGregory Neil Shapiro sm_dprintf("collect: premature EOM: %s\n", errmsg); 68740266059SGregory Neil Shapiro if (LogLevel > 1) 688c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 689c2aa98e2SPeter Wemm "collect: premature EOM: %s", errmsg); 69040266059SGregory Neil Shapiro inputerr = true; 691c2aa98e2SPeter Wemm } 692c2aa98e2SPeter Wemm 693c2aa98e2SPeter Wemm /* reset global timer */ 6948774250cSGregory Neil Shapiro if (CollectTimeout != NULL) 69540266059SGregory Neil Shapiro sm_clrevent(CollectTimeout); 696c2aa98e2SPeter Wemm 697c2aa98e2SPeter Wemm if (headeronly) 698c2aa98e2SPeter Wemm return; 699c2aa98e2SPeter Wemm 70040266059SGregory Neil Shapiro if (mstate != MS_BODY) 70140266059SGregory Neil Shapiro { 70240266059SGregory Neil Shapiro /* no body or discard, so we never opened the data file */ 70340266059SGregory Neil Shapiro SM_ASSERT(df == NULL); 70440266059SGregory Neil Shapiro df = collect_eoh(e, numhdrs, hdrslen); 70540266059SGregory Neil Shapiro } 70640266059SGregory Neil Shapiro 70706f25ae9SGregory Neil Shapiro if (df == NULL) 708c2aa98e2SPeter Wemm { 70906f25ae9SGregory Neil Shapiro /* skip next few clauses */ 71006f25ae9SGregory Neil Shapiro /* EMPTY */ 71106f25ae9SGregory Neil Shapiro } 71240266059SGregory Neil Shapiro else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df)) 71306f25ae9SGregory Neil Shapiro { 71440266059SGregory Neil Shapiro dferror(df, "sm_io_flush||sm_io_error", e); 71540266059SGregory Neil Shapiro flush_errors(true); 71640266059SGregory Neil Shapiro finis(true, true, ExitStat); 71706f25ae9SGregory Neil Shapiro /* NOTREACHED */ 71806f25ae9SGregory Neil Shapiro } 71940266059SGregory Neil Shapiro else if (SuperSafe != SAFE_REALLY) 72006f25ae9SGregory Neil Shapiro { 72106f25ae9SGregory Neil Shapiro /* skip next few clauses */ 72206f25ae9SGregory Neil Shapiro /* EMPTY */ 72306f25ae9SGregory Neil Shapiro } 72440266059SGregory Neil Shapiro else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) 72506f25ae9SGregory Neil Shapiro { 72606f25ae9SGregory Neil Shapiro int save_errno = errno; 72706f25ae9SGregory Neil Shapiro 72806f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 72906f25ae9SGregory Neil Shapiro { 73006f25ae9SGregory Neil Shapiro char *dfile; 73106f25ae9SGregory Neil Shapiro struct stat st; 73240266059SGregory Neil Shapiro int dfd; 73306f25ae9SGregory Neil Shapiro 73440266059SGregory Neil Shapiro dfile = queuename(e, DATAFL_LETTER); 73506f25ae9SGregory Neil Shapiro if (stat(dfile, &st) < 0) 73606f25ae9SGregory Neil Shapiro st.st_size = -1; 73706f25ae9SGregory Neil Shapiro errno = EEXIST; 73840266059SGregory Neil Shapiro syserr("@collect: bfcommit(%s): already on disk, size = %ld", 73942e5d165SGregory Neil Shapiro dfile, (long) st.st_size); 74040266059SGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 74106f25ae9SGregory Neil Shapiro if (dfd >= 0) 74240266059SGregory Neil Shapiro dumpfd(dfd, true, true); 74306f25ae9SGregory Neil Shapiro } 74406f25ae9SGregory Neil Shapiro errno = save_errno; 74506f25ae9SGregory Neil Shapiro dferror(df, "bfcommit", e); 74640266059SGregory Neil Shapiro flush_errors(true); 74740266059SGregory Neil Shapiro finis(save_errno != EEXIST, true, ExitStat); 74806f25ae9SGregory Neil Shapiro } 74940266059SGregory Neil Shapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 && 75040266059SGregory Neil Shapiro fsync(afd) < 0) 751602a2b1bSGregory Neil Shapiro { 75240266059SGregory Neil Shapiro dferror(df, "fsync", e); 75340266059SGregory Neil Shapiro flush_errors(true); 75440266059SGregory Neil Shapiro finis(true, true, ExitStat); 755602a2b1bSGregory Neil Shapiro /* NOTREACHED */ 756602a2b1bSGregory Neil Shapiro } 75740266059SGregory Neil Shapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 75806f25ae9SGregory Neil Shapiro { 75940266059SGregory Neil Shapiro dferror(df, "sm_io_close", e); 76040266059SGregory Neil Shapiro flush_errors(true); 76140266059SGregory Neil Shapiro finis(true, true, ExitStat); 76206f25ae9SGregory Neil Shapiro /* NOTREACHED */ 76306f25ae9SGregory Neil Shapiro } 76406f25ae9SGregory Neil Shapiro else 76506f25ae9SGregory Neil Shapiro { 76606f25ae9SGregory Neil Shapiro /* everything is happily flushed to disk */ 76706f25ae9SGregory Neil Shapiro df = NULL; 76840266059SGregory Neil Shapiro 76940266059SGregory Neil Shapiro /* remove from available space in filesystem */ 77040266059SGregory Neil Shapiro updfs(e, false, true); 771c2aa98e2SPeter Wemm } 772c2aa98e2SPeter Wemm 773c2aa98e2SPeter Wemm /* An EOF when running SMTP is an error */ 774c2aa98e2SPeter Wemm if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 775c2aa98e2SPeter Wemm { 776c2aa98e2SPeter Wemm char *host; 777c2aa98e2SPeter Wemm char *problem; 778959366dcSGregory Neil Shapiro ADDRESS *q; 779c2aa98e2SPeter Wemm 780c2aa98e2SPeter Wemm host = RealHostName; 781c2aa98e2SPeter Wemm if (host == NULL) 782c2aa98e2SPeter Wemm host = "localhost"; 783c2aa98e2SPeter Wemm 78440266059SGregory Neil Shapiro if (sm_io_eof(fp)) 785c2aa98e2SPeter Wemm problem = "unexpected close"; 78640266059SGregory Neil Shapiro else if (sm_io_error(fp)) 787c2aa98e2SPeter Wemm problem = "I/O error"; 788c2aa98e2SPeter Wemm else 789c2aa98e2SPeter Wemm problem = "read timeout"; 79040266059SGregory Neil Shapiro if (LogLevel > 0 && sm_io_eof(fp)) 791c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 79240266059SGregory Neil Shapiro "collect: %s on connection from %.100s, sender=%s", 793c2aa98e2SPeter Wemm problem, host, 79440266059SGregory Neil Shapiro shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 79540266059SGregory Neil Shapiro if (sm_io_eof(fp)) 79606f25ae9SGregory Neil Shapiro usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 797c2aa98e2SPeter Wemm problem, host, 798c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 799c2aa98e2SPeter Wemm else 80006f25ae9SGregory Neil Shapiro syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 801c2aa98e2SPeter Wemm problem, host, 802c2aa98e2SPeter Wemm shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 803c2aa98e2SPeter Wemm 804c2aa98e2SPeter Wemm /* don't return an error indication */ 805c2aa98e2SPeter Wemm e->e_to = NULL; 806c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 807c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 808c2aa98e2SPeter Wemm 809959366dcSGregory Neil Shapiro /* Don't send any message notification to sender */ 810959366dcSGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 811959366dcSGregory Neil Shapiro { 812959366dcSGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 813959366dcSGregory Neil Shapiro continue; 814959366dcSGregory Neil Shapiro q->q_state = QS_FATALERR; 815959366dcSGregory Neil Shapiro } 816959366dcSGregory Neil Shapiro 81740266059SGregory Neil Shapiro finis(true, true, ExitStat); 81806f25ae9SGregory Neil Shapiro /* NOTREACHED */ 819c2aa98e2SPeter Wemm } 820c2aa98e2SPeter Wemm 82140266059SGregory Neil Shapiro /* Log collection information. */ 82240266059SGregory Neil Shapiro if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 823c2aa98e2SPeter Wemm { 82440266059SGregory Neil Shapiro logsender(e, e->e_msgid); 82540266059SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER; 826c2aa98e2SPeter Wemm } 827c2aa98e2SPeter Wemm 828c2aa98e2SPeter Wemm /* check for message too large */ 82942e5d165SGregory Neil Shapiro if (bitset(EF_TOOBIG, e->e_flags)) 830c2aa98e2SPeter Wemm { 831c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 83240266059SGregory Neil Shapiro if (!bitset(EF_FATALERRS, e->e_flags)) 83340266059SGregory Neil Shapiro { 834c2aa98e2SPeter Wemm e->e_status = "5.2.3"; 83506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 83606f25ae9SGregory Neil Shapiro "552 Message exceeds maximum fixed size (%ld)", 837c2aa98e2SPeter Wemm MaxMessageSize); 838c2aa98e2SPeter Wemm if (LogLevel > 6) 839c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 840c2aa98e2SPeter Wemm "message size (%ld) exceeds maximum (%ld)", 841c2aa98e2SPeter Wemm e->e_msgsize, MaxMessageSize); 842c2aa98e2SPeter Wemm } 84340266059SGregory Neil Shapiro } 844c2aa98e2SPeter Wemm 845c2aa98e2SPeter Wemm /* check for illegal 8-bit data */ 846c2aa98e2SPeter Wemm if (HasEightBits) 847c2aa98e2SPeter Wemm { 848c2aa98e2SPeter Wemm e->e_flags |= EF_HAS8BIT; 849c2aa98e2SPeter Wemm if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 850c2aa98e2SPeter Wemm !bitset(EF_IS_MIME, e->e_flags)) 851c2aa98e2SPeter Wemm { 852c2aa98e2SPeter Wemm e->e_status = "5.6.1"; 85306f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "554 Eight bit data not allowed"); 854c2aa98e2SPeter Wemm } 855c2aa98e2SPeter Wemm } 856c2aa98e2SPeter Wemm else 857c2aa98e2SPeter Wemm { 858c2aa98e2SPeter Wemm /* if it claimed to be 8 bits, well, it lied.... */ 859c2aa98e2SPeter Wemm if (e->e_bodytype != NULL && 86040266059SGregory Neil Shapiro sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) 861c2aa98e2SPeter Wemm e->e_bodytype = "7BIT"; 862c2aa98e2SPeter Wemm } 863c2aa98e2SPeter Wemm 86440266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags)) 86506f25ae9SGregory Neil Shapiro { 86640266059SGregory Neil Shapiro char *dfname = queuename(e, DATAFL_LETTER); 86740266059SGregory Neil Shapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 86840266059SGregory Neil Shapiro SM_IO_RDONLY, NULL)) == NULL) 869c2aa98e2SPeter Wemm { 870c2aa98e2SPeter Wemm /* we haven't acked receipt yet, so just chuck this */ 87140266059SGregory Neil Shapiro syserr("@Cannot reopen %s", dfname); 87240266059SGregory Neil Shapiro finis(true, true, ExitStat); 87306f25ae9SGregory Neil Shapiro /* NOTREACHED */ 874c2aa98e2SPeter Wemm } 875c2aa98e2SPeter Wemm } 87606f25ae9SGregory Neil Shapiro else 87706f25ae9SGregory Neil Shapiro e->e_dfp = df; 878605302a5SGregory Neil Shapiro 879605302a5SGregory Neil Shapiro /* collect statistics */ 880605302a5SGregory Neil Shapiro if (OpMode != MD_VERIFY) 881605302a5SGregory Neil Shapiro markstats(e, (ADDRESS *) NULL, STATS_NORMAL); 88206f25ae9SGregory Neil Shapiro } 883c2aa98e2SPeter Wemm 884c2aa98e2SPeter Wemm static void 885c2aa98e2SPeter Wemm collecttimeout(timeout) 886c2aa98e2SPeter Wemm time_t timeout; 887c2aa98e2SPeter Wemm { 8888774250cSGregory Neil Shapiro int save_errno = errno; 889c2aa98e2SPeter Wemm 8908774250cSGregory Neil Shapiro /* 8918774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 8928774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 8938774250cSGregory Neil Shapiro ** DOING. 8948774250cSGregory Neil Shapiro */ 8958774250cSGregory Neil Shapiro 8968774250cSGregory Neil Shapiro if (CollectProgress) 8978774250cSGregory Neil Shapiro { 8988774250cSGregory Neil Shapiro /* reset the timeout */ 89940266059SGregory Neil Shapiro CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout, 9008774250cSGregory Neil Shapiro timeout); 90140266059SGregory Neil Shapiro CollectProgress = false; 902c2aa98e2SPeter Wemm } 9038774250cSGregory Neil Shapiro else 9048774250cSGregory Neil Shapiro { 9058774250cSGregory Neil Shapiro /* event is done */ 9068774250cSGregory Neil Shapiro CollectTimeout = NULL; 9078774250cSGregory Neil Shapiro } 9088774250cSGregory Neil Shapiro 9098774250cSGregory Neil Shapiro /* if no progress was made or problem resetting event, die now */ 9108774250cSGregory Neil Shapiro if (CollectTimeout == NULL) 9118774250cSGregory Neil Shapiro { 9128774250cSGregory Neil Shapiro errno = ETIMEDOUT; 9138774250cSGregory Neil Shapiro longjmp(CtxCollectTimeout, 1); 9148774250cSGregory Neil Shapiro } 9158774250cSGregory Neil Shapiro errno = save_errno; 9168774250cSGregory Neil Shapiro } 91740266059SGregory Neil Shapiro /* 91806f25ae9SGregory Neil Shapiro ** DFERROR -- signal error on writing the data file. 919c2aa98e2SPeter Wemm ** 92040266059SGregory Neil Shapiro ** Called by collect(). Collect() always terminates the process 92140266059SGregory Neil Shapiro ** immediately after calling dferror(), which means that the SMTP 92240266059SGregory Neil Shapiro ** session will be terminated, which means that any error message 92340266059SGregory Neil Shapiro ** issued by dferror must be a 421 error, as per RFC 821. 92440266059SGregory Neil Shapiro ** 925c2aa98e2SPeter Wemm ** Parameters: 92606f25ae9SGregory Neil Shapiro ** df -- the file pointer for the data file. 92706f25ae9SGregory Neil Shapiro ** msg -- detailed message. 928c2aa98e2SPeter Wemm ** e -- the current envelope. 929c2aa98e2SPeter Wemm ** 930c2aa98e2SPeter Wemm ** Returns: 931c2aa98e2SPeter Wemm ** none. 932c2aa98e2SPeter Wemm ** 933c2aa98e2SPeter Wemm ** Side Effects: 934c2aa98e2SPeter Wemm ** Gives an error message. 935c2aa98e2SPeter Wemm ** Arranges for following output to go elsewhere. 936c2aa98e2SPeter Wemm */ 937c2aa98e2SPeter Wemm 93806f25ae9SGregory Neil Shapiro static void 93906f25ae9SGregory Neil Shapiro dferror(df, msg, e) 94040266059SGregory Neil Shapiro SM_FILE_T *volatile df; 94106f25ae9SGregory Neil Shapiro char *msg; 942c2aa98e2SPeter Wemm register ENVELOPE *e; 943c2aa98e2SPeter Wemm { 94406f25ae9SGregory Neil Shapiro char *dfname; 94506f25ae9SGregory Neil Shapiro 94640266059SGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER); 947c2aa98e2SPeter Wemm setstat(EX_IOERR); 948c2aa98e2SPeter Wemm if (errno == ENOSPC) 949c2aa98e2SPeter Wemm { 950c2aa98e2SPeter Wemm #if STAT64 > 0 951c2aa98e2SPeter Wemm struct stat64 st; 95206f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 953c2aa98e2SPeter Wemm struct stat st; 95406f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 955c2aa98e2SPeter Wemm long avail; 956c2aa98e2SPeter Wemm long bsize; 957c2aa98e2SPeter Wemm 958c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 959c2aa98e2SPeter Wemm 960c2aa98e2SPeter Wemm if ( 961c2aa98e2SPeter Wemm #if STAT64 > 0 96240266059SGregory Neil Shapiro fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 96306f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 96440266059SGregory Neil Shapiro fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st) 96506f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 966c2aa98e2SPeter Wemm < 0) 967c2aa98e2SPeter Wemm st.st_size = 0; 96840266059SGregory Neil Shapiro (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, 96940266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df); 970c2aa98e2SPeter Wemm if (st.st_size <= 0) 97140266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 97240266059SGregory Neil Shapiro "\n*** Mail could not be accepted"); 973c2aa98e2SPeter Wemm else 97440266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 97540266059SGregory Neil Shapiro "\n*** Mail of at least %llu bytes could not be accepted\n", 97640266059SGregory Neil Shapiro (ULONGLONG_T) st.st_size); 97740266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 97840266059SGregory Neil Shapiro "*** at %s due to lack of disk space for temp file.\n", 979c2aa98e2SPeter Wemm MyHostName); 98040266059SGregory Neil Shapiro avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir), 98140266059SGregory Neil Shapiro &bsize); 982c2aa98e2SPeter Wemm if (avail > 0) 983c2aa98e2SPeter Wemm { 984c2aa98e2SPeter Wemm if (bsize > 1024) 985c2aa98e2SPeter Wemm avail *= bsize / 1024; 986c2aa98e2SPeter Wemm else if (bsize < 1024) 987c2aa98e2SPeter Wemm avail /= 1024 / bsize; 98840266059SGregory Neil Shapiro (void) sm_io_fprintf(df, SM_TIME_DEFAULT, 98940266059SGregory Neil Shapiro "*** Currently, %ld kilobytes are available for mail temp files.\n", 990c2aa98e2SPeter Wemm avail); 991c2aa98e2SPeter Wemm } 99240266059SGregory Neil Shapiro #if 0 99340266059SGregory Neil Shapiro /* Wrong response code; should be 421. */ 994c2aa98e2SPeter Wemm e->e_status = "4.3.1"; 99506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, "452 Out of disk space for temp file"); 99640266059SGregory Neil Shapiro #else /* 0 */ 99740266059SGregory Neil Shapiro syserr("421 4.3.1 Out of disk space for temp file"); 99840266059SGregory Neil Shapiro #endif /* 0 */ 999c2aa98e2SPeter Wemm } 1000c2aa98e2SPeter Wemm else 100140266059SGregory Neil Shapiro syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", 100294c01205SGregory Neil Shapiro dfname, msg, (int) geteuid(), (int) getegid()); 100340266059SGregory Neil Shapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 100440266059SGregory Neil Shapiro SM_IO_WRONLY, NULL, df) == NULL) 1005c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 100640266059SGregory Neil Shapiro "dferror: sm_io_reopen(\"/dev/null\") failed: %s", 100740266059SGregory Neil Shapiro sm_errstring(errno)); 1008c2aa98e2SPeter Wemm } 100940266059SGregory Neil Shapiro /* 1010c2aa98e2SPeter Wemm ** EATFROM -- chew up a UNIX style from line and process 1011c2aa98e2SPeter Wemm ** 1012c2aa98e2SPeter Wemm ** This does indeed make some assumptions about the format 1013c2aa98e2SPeter Wemm ** of UNIX messages. 1014c2aa98e2SPeter Wemm ** 1015c2aa98e2SPeter Wemm ** Parameters: 1016c2aa98e2SPeter Wemm ** fm -- the from line. 1017c2aa98e2SPeter Wemm ** 1018c2aa98e2SPeter Wemm ** Returns: 1019c2aa98e2SPeter Wemm ** none. 1020c2aa98e2SPeter Wemm ** 1021c2aa98e2SPeter Wemm ** Side Effects: 1022c2aa98e2SPeter Wemm ** extracts what information it can from the header, 1023c2aa98e2SPeter Wemm ** such as the date. 1024c2aa98e2SPeter Wemm */ 1025c2aa98e2SPeter Wemm 1026c2aa98e2SPeter Wemm #ifndef NOTUNIX 1027c2aa98e2SPeter Wemm 102806f25ae9SGregory Neil Shapiro static char *DowList[] = 1029c2aa98e2SPeter Wemm { 1030c2aa98e2SPeter Wemm "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 1031c2aa98e2SPeter Wemm }; 1032c2aa98e2SPeter Wemm 103306f25ae9SGregory Neil Shapiro static char *MonthList[] = 1034c2aa98e2SPeter Wemm { 1035c2aa98e2SPeter Wemm "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1036c2aa98e2SPeter Wemm "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 1037c2aa98e2SPeter Wemm NULL 1038c2aa98e2SPeter Wemm }; 1039c2aa98e2SPeter Wemm 104006f25ae9SGregory Neil Shapiro static void 1041c2aa98e2SPeter Wemm eatfrom(fm, e) 1042c2aa98e2SPeter Wemm char *volatile fm; 1043c2aa98e2SPeter Wemm register ENVELOPE *e; 1044c2aa98e2SPeter Wemm { 1045c2aa98e2SPeter Wemm register char *p; 1046c2aa98e2SPeter Wemm register char **dt; 1047c2aa98e2SPeter Wemm 1048c2aa98e2SPeter Wemm if (tTd(30, 2)) 104940266059SGregory Neil Shapiro sm_dprintf("eatfrom(%s)\n", fm); 1050c2aa98e2SPeter Wemm 1051c2aa98e2SPeter Wemm /* find the date part */ 1052c2aa98e2SPeter Wemm p = fm; 1053c2aa98e2SPeter Wemm while (*p != '\0') 1054c2aa98e2SPeter Wemm { 1055c2aa98e2SPeter Wemm /* skip a word */ 1056c2aa98e2SPeter Wemm while (*p != '\0' && *p != ' ') 1057c2aa98e2SPeter Wemm p++; 1058c2aa98e2SPeter Wemm while (*p == ' ') 1059c2aa98e2SPeter Wemm p++; 1060193538b7SGregory Neil Shapiro if (strlen(p) < 17) 1061193538b7SGregory Neil Shapiro { 1062193538b7SGregory Neil Shapiro /* no room for the date */ 1063193538b7SGregory Neil Shapiro return; 1064193538b7SGregory Neil Shapiro } 1065c2aa98e2SPeter Wemm if (!(isascii(*p) && isupper(*p)) || 1066c2aa98e2SPeter Wemm p[3] != ' ' || p[13] != ':' || p[16] != ':') 1067c2aa98e2SPeter Wemm continue; 1068c2aa98e2SPeter Wemm 1069c2aa98e2SPeter Wemm /* we have a possible date */ 1070c2aa98e2SPeter Wemm for (dt = DowList; *dt != NULL; dt++) 1071c2aa98e2SPeter Wemm if (strncmp(*dt, p, 3) == 0) 1072c2aa98e2SPeter Wemm break; 1073c2aa98e2SPeter Wemm if (*dt == NULL) 1074c2aa98e2SPeter Wemm continue; 1075c2aa98e2SPeter Wemm 1076c2aa98e2SPeter Wemm for (dt = MonthList; *dt != NULL; dt++) 1077193538b7SGregory Neil Shapiro { 1078c2aa98e2SPeter Wemm if (strncmp(*dt, &p[4], 3) == 0) 1079c2aa98e2SPeter Wemm break; 1080193538b7SGregory Neil Shapiro } 1081c2aa98e2SPeter Wemm if (*dt != NULL) 1082c2aa98e2SPeter Wemm break; 1083c2aa98e2SPeter Wemm } 1084c2aa98e2SPeter Wemm 1085c2aa98e2SPeter Wemm if (*p != '\0') 1086c2aa98e2SPeter Wemm { 108740266059SGregory Neil Shapiro char *q, buf[25]; 1088c2aa98e2SPeter Wemm 1089c2aa98e2SPeter Wemm /* we have found a date */ 109040266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p, sizeof(buf)); 109140266059SGregory Neil Shapiro q = arpadate(buf); 109240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'a', q); 1093c2aa98e2SPeter Wemm } 1094c2aa98e2SPeter Wemm } 109506f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */ 1096