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