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