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