headers.c revision 132946
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 * $FreeBSD: head/contrib/sendmail/src/headers.c 132946 2004-08-01 01:16:16Z gshapiro $
13 */
14
15#include <sendmail.h>
16
17SM_RCSID("@(#)$Id: headers.c,v 8.286 2004/07/08 17:57:32 ca Exp $")
18
19static HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *));
20static size_t	fix_mime_header __P((HDR *, ENVELOPE *));
21static int	priencode __P((char *));
22static void	put_vanilla_header __P((HDR *, char *, MCI *));
23
24/*
25**  SETUPHEADERS -- initialize headers in symbol table
26**
27**	Parameters:
28**		none
29**
30**	Returns:
31**		none
32*/
33
34void
35setupheaders()
36{
37	struct hdrinfo *hi;
38	STAB *s;
39
40	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
41	{
42		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
43		s->s_header.hi_flags = hi->hi_flags;
44		s->s_header.hi_ruleset = NULL;
45	}
46}
47/*
48**  CHOMPHEADER -- process and save a header line.
49**
50**	Called by collect, readcf, and readqf to deal with header lines.
51**
52**	Parameters:
53**		line -- header as a text line.
54**		pflag -- flags for chompheader() (from sendmail.h)
55**		hdrp -- a pointer to the place to save the header.
56**		e -- the envelope including this header.
57**
58**	Returns:
59**		flags for this header.
60**
61**	Side Effects:
62**		The header is saved on the header list.
63**		Contents of 'line' are destroyed.
64*/
65
66static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
67
68unsigned long
69chompheader(line, pflag, hdrp, e)
70	char *line;
71	int pflag;
72	HDR **hdrp;
73	register ENVELOPE *e;
74{
75	unsigned char mid = '\0';
76	register char *p;
77	register HDR *h;
78	HDR **hp;
79	char *fname;
80	char *fvalue;
81	bool cond = false;
82	bool dropfrom;
83	bool headeronly;
84	STAB *s;
85	struct hdrinfo *hi;
86	bool nullheader = false;
87	BITMAP256 mopts;
88
89	if (tTd(31, 6))
90	{
91		sm_dprintf("chompheader: ");
92		xputs(sm_debug_file(), line);
93		sm_dprintf("\n");
94	}
95
96	headeronly = hdrp != NULL;
97	if (!headeronly)
98		hdrp = &e->e_header;
99
100	/* strip off options */
101	clrbitmap(mopts);
102	p = line;
103	if (!bitset(pflag, CHHDR_USER) && *p == '?')
104	{
105		int c;
106		register char *q;
107
108		q = strchr(++p, '?');
109		if (q == NULL)
110			goto hse;
111
112		*q = '\0';
113		c = *p & 0377;
114
115		/* possibly macro conditional */
116		if (c == MACROEXPAND)
117		{
118			/* catch ?$? */
119			if (*++p == '\0')
120			{
121				*q = '?';
122				goto hse;
123			}
124
125			mid = (unsigned char) *p++;
126
127			/* catch ?$abc? */
128			if (*p != '\0')
129			{
130				*q = '?';
131				goto hse;
132			}
133		}
134		else if (*p == '$')
135		{
136			/* catch ?$? */
137			if (*++p == '\0')
138			{
139				*q = '?';
140				goto hse;
141			}
142
143			mid = (unsigned char) macid(p);
144			if (bitset(0200, mid))
145			{
146				p += strlen(macname(mid)) + 2;
147				SM_ASSERT(p <= q);
148			}
149			else
150				p++;
151
152			/* catch ?$abc? */
153			if (*p != '\0')
154			{
155				*q = '?';
156				goto hse;
157			}
158		}
159		else
160		{
161			while (*p != '\0')
162			{
163				if (!isascii(*p))
164				{
165					*q = '?';
166					goto hse;
167				}
168
169				setbitn(bitidx(*p), mopts);
170				cond = true;
171				p++;
172			}
173		}
174		p = q + 1;
175	}
176
177	/* find canonical name */
178	fname = p;
179	while (isascii(*p) && isgraph(*p) && *p != ':')
180		p++;
181	fvalue = p;
182	while (isascii(*p) && isspace(*p))
183		p++;
184	if (*p++ != ':' || fname == fvalue)
185	{
186hse:
187		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
188		return 0;
189	}
190	*fvalue = '\0';
191
192	/* strip field value on front */
193	if (*p == ' ')
194		p++;
195	fvalue = p;
196
197	/* if the field is null, go ahead and use the default */
198	while (isascii(*p) && isspace(*p))
199		p++;
200	if (*p == '\0')
201		nullheader = true;
202
203	/* security scan: long field names are end-of-header */
204	if (strlen(fname) > 100)
205		return H_EOH;
206
207	/* check to see if it represents a ruleset call */
208	if (bitset(pflag, CHHDR_DEF))
209	{
210		char hbuf[50];
211
212		(void) expand(fvalue, hbuf, sizeof hbuf, e);
213		for (p = hbuf; isascii(*p) && isspace(*p); )
214			p++;
215		if ((*p++ & 0377) == CALLSUBR)
216		{
217			auto char *endp;
218			bool strc;
219
220			strc = *p == '+';	/* strip comments? */
221			if (strc)
222				++p;
223			if (strtorwset(p, &endp, ST_ENTER) > 0)
224			{
225				*endp = '\0';
226				s = stab(fname, ST_HEADER, ST_ENTER);
227				if (LogLevel > 9 &&
228				    s->s_header.hi_ruleset != NULL)
229					sm_syslog(LOG_WARNING, NOQID,
230						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
231						  fname,
232						  s->s_header.hi_ruleset, p);
233				s->s_header.hi_ruleset = newstr(p);
234				if (!strc)
235					s->s_header.hi_flags |= H_STRIPCOMM;
236			}
237			return 0;
238		}
239	}
240
241	/* see if it is a known type */
242	s = stab(fname, ST_HEADER, ST_FIND);
243	if (s != NULL)
244		hi = &s->s_header;
245	else
246		hi = &NormalHeader;
247
248	if (tTd(31, 9))
249	{
250		if (s == NULL)
251			sm_dprintf("no header flags match\n");
252		else
253			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
254				   hi->hi_flags,
255				   hi->hi_ruleset == NULL ? "<NULL>"
256							  : hi->hi_ruleset);
257	}
258
259	/* see if this is a resent message */
260	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
261	    bitset(H_RESENT, hi->hi_flags))
262		e->e_flags |= EF_RESENT;
263
264	/* if this is an Errors-To: header keep track of it now */
265	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
266	    bitset(H_ERRORSTO, hi->hi_flags))
267		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
268
269	/* if this means "end of header" quit now */
270	if (!headeronly && bitset(H_EOH, hi->hi_flags))
271		return hi->hi_flags;
272
273	/*
274	**  Horrible hack to work around problem with Lotus Notes SMTP
275	**  mail gateway, which generates From: headers with newlines in
276	**  them and the <address> on the second line.  Although this is
277	**  legal RFC 822, many MUAs don't handle this properly and thus
278	**  never find the actual address.
279	*/
280
281	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
282	{
283		while ((p = strchr(fvalue, '\n')) != NULL)
284			*p = ' ';
285	}
286
287	/*
288	**  If there is a check ruleset, verify it against the header.
289	*/
290
291	if (bitset(pflag, CHHDR_CHECK))
292	{
293		int rscheckflags;
294		char *rs;
295
296		rscheckflags = RSF_COUNT;
297		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
298			rscheckflags |= RSF_UNSTRUCTURED;
299
300		/* no ruleset? look for default */
301		rs = hi->hi_ruleset;
302		if (rs == NULL)
303		{
304			s = stab("*", ST_HEADER, ST_FIND);
305			if (s != NULL)
306			{
307				rs = (&s->s_header)->hi_ruleset;
308				if (bitset((&s->s_header)->hi_flags,
309					   H_STRIPCOMM))
310					rscheckflags |= RSF_RMCOMM;
311			}
312		}
313		else if (bitset(hi->hi_flags, H_STRIPCOMM))
314			rscheckflags |= RSF_RMCOMM;
315		if (rs != NULL)
316		{
317			int l, k;
318			char qval[MAXNAME];
319
320			l = 0;
321			qval[l++] = '"';
322
323			/* - 3 to avoid problems with " at the end */
324			/* should be sizeof(qval), not MAXNAME */
325			for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
326			{
327				switch (fvalue[k])
328				{
329				  /* XXX other control chars? */
330				  case '\011': /* ht */
331				  case '\012': /* nl */
332				  case '\013': /* vt */
333				  case '\014': /* np */
334				  case '\015': /* cr */
335					qval[l++] = ' ';
336					break;
337				  case '"':
338					qval[l++] = '\\';
339					/* FALLTHROUGH */
340				  default:
341					qval[l++] = fvalue[k];
342					break;
343				}
344			}
345			qval[l++] = '"';
346			qval[l] = '\0';
347			k += strlen(fvalue + k);
348			if (k >= MAXNAME)
349			{
350				if (LogLevel > 9)
351					sm_syslog(LOG_WARNING, e->e_id,
352						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
353						  fname, rs, k, MAXNAME - 1);
354			}
355			macdefine(&e->e_macro, A_TEMP,
356				macid("{currHeader}"), qval);
357			macdefine(&e->e_macro, A_TEMP,
358				macid("{hdr_name}"), fname);
359
360			(void) sm_snprintf(qval, sizeof qval, "%d", k);
361			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
362#if _FFR_HDR_TYPE
363			if (bitset(H_FROM, hi->hi_flags))
364				macdefine(&e->e_macro, A_PERM,
365					macid("{addr_type}"), "h s");
366			else if (bitset(H_RCPT, hi->hi_flags))
367				macdefine(&e->e_macro, A_PERM,
368					macid("{addr_type}"), "h r");
369			else
370#endif /* _FFR_HDR_TYPE */
371				macdefine(&e->e_macro, A_PERM,
372					macid("{addr_type}"), "h");
373			(void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
374				       NULL, e->e_id);
375		}
376	}
377
378	/*
379	**  Drop explicit From: if same as what we would generate.
380	**  This is to make MH (which doesn't always give a full name)
381	**  insert the full name information in all circumstances.
382	*/
383
384	dropfrom = false;
385	p = "resent-from";
386	if (!bitset(EF_RESENT, e->e_flags))
387		p += 7;
388	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
389	    !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
390	{
391		if (tTd(31, 2))
392		{
393			sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
394				fvalue, e->e_from.q_paddr, e->e_from.q_user);
395		}
396		if (e->e_from.q_paddr != NULL &&
397		    e->e_from.q_mailer != NULL &&
398		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
399		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
400		     strcmp(fvalue, e->e_from.q_user) == 0))
401			dropfrom = true;
402	}
403
404	/* delete default value for this header */
405	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
406	{
407		if (sm_strcasecmp(fname, h->h_field) == 0 &&
408		    !bitset(H_USER, h->h_flags) &&
409		    !bitset(H_FORCE, h->h_flags))
410		{
411			if (nullheader)
412			{
413				/* user-supplied value was null */
414				return 0;
415			}
416			if (dropfrom)
417			{
418				/* make this look like the user entered it */
419				h->h_flags |= H_USER;
420				return hi->hi_flags;
421			}
422			h->h_value = NULL;
423			if (!cond)
424			{
425				/* copy conditions from default case */
426				memmove((char *) mopts, (char *) h->h_mflags,
427					sizeof mopts);
428			}
429			h->h_macro = mid;
430		}
431	}
432
433	/* create a new node */
434	h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
435	h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
436	h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
437	h->h_link = NULL;
438	memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
439	h->h_macro = mid;
440	*hp = h;
441	h->h_flags = hi->hi_flags;
442	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
443		h->h_flags |= H_USER;
444
445	/* strip EOH flag if parsing MIME headers */
446	if (headeronly)
447		h->h_flags &= ~H_EOH;
448	if (bitset(pflag, CHHDR_DEF))
449		h->h_flags |= H_DEFAULT;
450	if (cond || mid != '\0')
451		h->h_flags |= H_CHECK;
452
453	/* hack to see if this is a new format message */
454	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
455	    bitset(H_RCPT|H_FROM, h->h_flags) &&
456	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
457	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
458	{
459		e->e_flags &= ~EF_OLDSTYLE;
460	}
461
462	return h->h_flags;
463}
464/*
465**  ALLOCHEADER -- allocate a header entry
466**
467**	Parameters:
468**		field -- the name of the header field.
469**		value -- the value of the field.
470**		flags -- flags to add to h_flags.
471**		rp -- resource pool for allocations
472**
473**	Returns:
474**		Pointer to a newly allocated and populated HDR.
475*/
476
477static HDR *
478allocheader(field, value, flags, rp)
479	char *field;
480	char *value;
481	int flags;
482	SM_RPOOL_T *rp;
483{
484	HDR *h;
485	STAB *s;
486
487	/* find info struct */
488	s = stab(field, ST_HEADER, ST_FIND);
489
490	/* allocate space for new header */
491	h = (HDR *) sm_rpool_malloc_x(rp, sizeof *h);
492	h->h_field = field;
493	h->h_value = sm_rpool_strdup_x(rp, value);
494	h->h_flags = flags;
495	if (s != NULL)
496		h->h_flags |= s->s_header.hi_flags;
497	clrbitmap(h->h_mflags);
498	h->h_macro = '\0';
499
500	return h;
501}
502/*
503**  ADDHEADER -- add a header entry to the end of the queue.
504**
505**	This bypasses the special checking of chompheader.
506**
507**	Parameters:
508**		field -- the name of the header field.
509**		value -- the value of the field.
510**		flags -- flags to add to h_flags.
511**		e -- envelope.
512**
513**	Returns:
514**		none.
515**
516**	Side Effects:
517**		adds the field on the list of headers for this envelope.
518*/
519
520void
521addheader(field, value, flags, e)
522	char *field;
523	char *value;
524	int flags;
525	ENVELOPE *e;
526{
527	register HDR *h;
528	HDR **hp;
529	HDR **hdrlist = &e->e_header;
530
531	/* find current place in list -- keep back pointer? */
532	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
533	{
534		if (sm_strcasecmp(field, h->h_field) == 0)
535			break;
536	}
537
538	/* allocate space for new header */
539	h = allocheader(field, value, flags, e->e_rpool);
540	h->h_link = *hp;
541	*hp = h;
542}
543/*
544**  INSHEADER -- insert a header entry at the specified index
545**
546**	This bypasses the special checking of chompheader.
547**
548**	Parameters:
549**		idx -- index into the header list at which to insert
550**		field -- the name of the header field.
551**		value -- the value of the field.
552**		flags -- flags to add to h_flags.
553**		e -- envelope.
554**
555**	Returns:
556**		none.
557**
558**	Side Effects:
559**		inserts the field on the list of headers for this envelope.
560*/
561
562void
563insheader(idx, field, value, flags, e)
564	int idx;
565	char *field;
566	char *value;
567	int flags;
568	ENVELOPE *e;
569{
570	HDR *h, *srch, *last = NULL;
571
572	/* allocate space for new header */
573	h = allocheader(field, value, flags, e->e_rpool);
574
575	/* find insertion position */
576	for (srch = e->e_header; srch != NULL && idx > 0;
577	     srch = srch->h_link, idx--)
578		last = srch;
579
580	if (e->e_header == NULL)
581	{
582		e->e_header = h;
583		h->h_link = NULL;
584	}
585	else if (srch == NULL)
586	{
587		SM_ASSERT(last != NULL);
588		last->h_link = h;
589		h->h_link = NULL;
590	}
591	else
592	{
593		h->h_link = srch->h_link;
594		srch->h_link = h;
595	}
596}
597/*
598**  HVALUE -- return value of a header.
599**
600**	Only "real" fields (i.e., ones that have not been supplied
601**	as a default) are used.
602**
603**	Parameters:
604**		field -- the field name.
605**		header -- the header list.
606**
607**	Returns:
608**		pointer to the value part.
609**		NULL if not found.
610**
611**	Side Effects:
612**		none.
613*/
614
615char *
616hvalue(field, header)
617	char *field;
618	HDR *header;
619{
620	register HDR *h;
621
622	for (h = header; h != NULL; h = h->h_link)
623	{
624		if (!bitset(H_DEFAULT, h->h_flags) &&
625		    sm_strcasecmp(h->h_field, field) == 0)
626			return h->h_value;
627	}
628	return NULL;
629}
630/*
631**  ISHEADER -- predicate telling if argument is a header.
632**
633**	A line is a header if it has a single word followed by
634**	optional white space followed by a colon.
635**
636**	Header fields beginning with two dashes, although technically
637**	permitted by RFC822, are automatically rejected in order
638**	to make MIME work out.  Without this we could have a technically
639**	legal header such as ``--"foo:bar"'' that would also be a legal
640**	MIME separator.
641**
642**	Parameters:
643**		h -- string to check for possible headerness.
644**
645**	Returns:
646**		true if h is a header.
647**		false otherwise.
648**
649**	Side Effects:
650**		none.
651*/
652
653bool
654isheader(h)
655	char *h;
656{
657	register char *s = h;
658
659	if (s[0] == '-' && s[1] == '-')
660		return false;
661
662	while (*s > ' ' && *s != ':' && *s != '\0')
663		s++;
664
665	if (h == s)
666		return false;
667
668	/* following technically violates RFC822 */
669	while (isascii(*s) && isspace(*s))
670		s++;
671
672	return (*s == ':');
673}
674/*
675**  EATHEADER -- run through the stored header and extract info.
676**
677**	Parameters:
678**		e -- the envelope to process.
679**		full -- if set, do full processing (e.g., compute
680**			message priority).  This should not be set
681**			when reading a queue file because some info
682**			needed to compute the priority is wrong.
683**		log -- call logsender()?
684**
685**	Returns:
686**		none.
687**
688**	Side Effects:
689**		Sets a bunch of global variables from information
690**			in the collected header.
691*/
692
693void
694eatheader(e, full, log)
695	register ENVELOPE *e;
696	bool full;
697	bool log;
698{
699	register HDR *h;
700	register char *p;
701	int hopcnt = 0;
702	char buf[MAXLINE];
703
704	/*
705	**  Set up macros for possible expansion in headers.
706	*/
707
708	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
709	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
710	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
711		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
712	else
713		macdefine(&e->e_macro, A_PERM, 'u', NULL);
714
715	/* full name of from person */
716	p = hvalue("full-name", e->e_header);
717	if (p != NULL)
718	{
719		if (!rfc822_string(p))
720		{
721			/*
722			**  Quote a full name with special characters
723			**  as a comment so crackaddr() doesn't destroy
724			**  the name portion of the address.
725			*/
726
727			p = addquotes(p, e->e_rpool);
728		}
729		macdefine(&e->e_macro, A_PERM, 'x', p);
730	}
731
732	if (tTd(32, 1))
733		sm_dprintf("----- collected header -----\n");
734	e->e_msgid = NULL;
735	for (h = e->e_header; h != NULL; h = h->h_link)
736	{
737		if (tTd(32, 1))
738			sm_dprintf("%s: ", h->h_field);
739		if (h->h_value == NULL)
740		{
741			if (tTd(32, 1))
742				sm_dprintf("<NULL>\n");
743			continue;
744		}
745
746		/* do early binding */
747		if (bitset(H_DEFAULT, h->h_flags) &&
748		    !bitset(H_BINDLATE, h->h_flags))
749		{
750			if (tTd(32, 1))
751			{
752				sm_dprintf("(");
753				xputs(sm_debug_file(), h->h_value);
754				sm_dprintf(") ");
755			}
756			expand(h->h_value, buf, sizeof buf, e);
757			if (buf[0] != '\0')
758			{
759				if (bitset(H_FROM, h->h_flags))
760					expand(crackaddr(buf, e),
761					       buf, sizeof buf, e);
762				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
763				h->h_flags &= ~H_DEFAULT;
764			}
765		}
766		if (tTd(32, 1))
767		{
768			xputs(sm_debug_file(), h->h_value);
769			sm_dprintf("\n");
770		}
771
772		/* count the number of times it has been processed */
773		if (bitset(H_TRACE, h->h_flags))
774			hopcnt++;
775
776		/* send to this person if we so desire */
777		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
778		    !bitset(H_DEFAULT, h->h_flags) &&
779		    (!bitset(EF_RESENT, e->e_flags) ||
780		     bitset(H_RESENT, h->h_flags)))
781		{
782#if 0
783			int saveflags = e->e_flags;
784#endif /* 0 */
785
786			(void) sendtolist(denlstring(h->h_value, true, false),
787					  NULLADDR, &e->e_sendqueue, 0, e);
788
789#if 0
790			/*
791			**  Change functionality so a fatal error on an
792			**  address doesn't affect the entire envelope.
793			*/
794
795			/* delete fatal errors generated by this address */
796			if (!bitset(EF_FATALERRS, saveflags))
797				e->e_flags &= ~EF_FATALERRS;
798#endif /* 0 */
799		}
800
801		/* save the message-id for logging */
802		p = "resent-message-id";
803		if (!bitset(EF_RESENT, e->e_flags))
804			p += 7;
805		if (sm_strcasecmp(h->h_field, p) == 0)
806		{
807			e->e_msgid = h->h_value;
808			while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
809				e->e_msgid++;
810			macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
811				  e->e_msgid);
812		}
813	}
814	if (tTd(32, 1))
815		sm_dprintf("----------------------------\n");
816
817	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
818	if (OpMode == MD_VERIFY)
819		return;
820
821	/* store hop count */
822	if (hopcnt > e->e_hopcount)
823	{
824		e->e_hopcount = hopcnt;
825		(void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
826		macdefine(&e->e_macro, A_TEMP, 'c', buf);
827	}
828
829	/* message priority */
830	p = hvalue("precedence", e->e_header);
831	if (p != NULL)
832		e->e_class = priencode(p);
833	if (e->e_class < 0)
834		e->e_timeoutclass = TOC_NONURGENT;
835	else if (e->e_class > 0)
836		e->e_timeoutclass = TOC_URGENT;
837	if (full)
838	{
839		e->e_msgpriority = e->e_msgsize
840				 - e->e_class * WkClassFact
841				 + e->e_nrcpts * WkRecipFact;
842	}
843
844	/* check for DSN to properly set e_timeoutclass */
845	p = hvalue("content-type", e->e_header);
846	if (p != NULL)
847	{
848		bool oldsupr;
849		char **pvp;
850		char pvpbuf[MAXLINE];
851		extern unsigned char MimeTokenTab[256];
852
853		/* tokenize header */
854		oldsupr = SuprErrs;
855		SuprErrs = true;
856		pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
857			      MimeTokenTab, false);
858		SuprErrs = oldsupr;
859
860		/* Check if multipart/report */
861		if (pvp != NULL && pvp[0] != NULL &&
862		    pvp[1] != NULL && pvp[2] != NULL &&
863		    sm_strcasecmp(*pvp++, "multipart") == 0 &&
864		    strcmp(*pvp++, "/") == 0 &&
865		    sm_strcasecmp(*pvp++, "report") == 0)
866		{
867			/* Look for report-type=delivery-status */
868			while (*pvp != NULL)
869			{
870				/* skip to semicolon separator */
871				while (*pvp != NULL && strcmp(*pvp, ";") != 0)
872					pvp++;
873
874				/* skip semicolon */
875				if (*pvp++ == NULL || *pvp == NULL)
876					break;
877
878				/* look for report-type */
879				if (sm_strcasecmp(*pvp++, "report-type") != 0)
880					continue;
881
882				/* skip equal */
883				if (*pvp == NULL || strcmp(*pvp, "=") != 0)
884					continue;
885
886				/* check value */
887				if (*++pvp != NULL &&
888				    sm_strcasecmp(*pvp,
889						  "delivery-status") == 0)
890					e->e_timeoutclass = TOC_DSN;
891
892				/* found report-type, no need to continue */
893				break;
894			}
895		}
896	}
897
898	/* message timeout priority */
899	p = hvalue("priority", e->e_header);
900	if (p != NULL)
901	{
902		/* (this should be in the configuration file) */
903		if (sm_strcasecmp(p, "urgent") == 0)
904			e->e_timeoutclass = TOC_URGENT;
905		else if (sm_strcasecmp(p, "normal") == 0)
906			e->e_timeoutclass = TOC_NORMAL;
907		else if (sm_strcasecmp(p, "non-urgent") == 0)
908			e->e_timeoutclass = TOC_NONURGENT;
909		else if (bitset(EF_RESPONSE, e->e_flags))
910			e->e_timeoutclass = TOC_DSN;
911	}
912	else if (bitset(EF_RESPONSE, e->e_flags))
913		e->e_timeoutclass = TOC_DSN;
914
915	/* date message originated */
916	p = hvalue("posted-date", e->e_header);
917	if (p == NULL)
918		p = hvalue("date", e->e_header);
919	if (p != NULL)
920		macdefine(&e->e_macro, A_PERM, 'a', p);
921
922	/* check to see if this is a MIME message */
923	if ((e->e_bodytype != NULL &&
924	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
925	    hvalue("MIME-Version", e->e_header) != NULL)
926	{
927		e->e_flags |= EF_IS_MIME;
928		if (HasEightBits)
929			e->e_bodytype = "8BITMIME";
930	}
931	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
932	{
933		/* this may be an RFC 1049 message */
934		p = strpbrk(p, ";/");
935		if (p == NULL || *p == ';')
936		{
937			/* yep, it is */
938			e->e_flags |= EF_DONT_MIME;
939		}
940	}
941
942	/*
943	**  From person in antiquated ARPANET mode
944	**	required by UK Grey Book e-mail gateways (sigh)
945	*/
946
947	if (OpMode == MD_ARPAFTP)
948	{
949		register struct hdrinfo *hi;
950
951		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
952		{
953			if (bitset(H_FROM, hi->hi_flags) &&
954			    (!bitset(H_RESENT, hi->hi_flags) ||
955			     bitset(EF_RESENT, e->e_flags)) &&
956			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
957				break;
958		}
959		if (hi->hi_field != NULL)
960		{
961			if (tTd(32, 2))
962				sm_dprintf("eatheader: setsender(*%s == %s)\n",
963					hi->hi_field, p);
964			setsender(p, e, NULL, '\0', true);
965		}
966	}
967
968	/*
969	**  Log collection information.
970	*/
971
972	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
973	{
974		logsender(e, e->e_msgid);
975		e->e_flags &= ~EF_LOGSENDER;
976	}
977}
978/*
979**  LOGSENDER -- log sender information
980**
981**	Parameters:
982**		e -- the envelope to log
983**		msgid -- the message id
984**
985**	Returns:
986**		none
987*/
988
989void
990logsender(e, msgid)
991	register ENVELOPE *e;
992	char *msgid;
993{
994	char *name;
995	register char *sbp;
996	register char *p;
997	int l;
998	char hbuf[MAXNAME + 1];
999	char sbuf[MAXLINE + 1];
1000	char mbuf[MAXNAME + 1];
1001
1002	/* don't allow newlines in the message-id */
1003	/* XXX do we still need this? sm_syslog() replaces control chars */
1004	if (msgid != NULL)
1005	{
1006		l = strlen(msgid);
1007		if (l > sizeof mbuf - 1)
1008			l = sizeof mbuf - 1;
1009		memmove(mbuf, msgid, l);
1010		mbuf[l] = '\0';
1011		p = mbuf;
1012		while ((p = strchr(p, '\n')) != NULL)
1013			*p++ = ' ';
1014	}
1015
1016	if (bitset(EF_RESPONSE, e->e_flags))
1017		name = "[RESPONSE]";
1018	else if ((name = macvalue('_', e)) != NULL)
1019		/* EMPTY */
1020		;
1021	else if (RealHostName == NULL)
1022		name = "localhost";
1023	else if (RealHostName[0] == '[')
1024		name = RealHostName;
1025	else
1026	{
1027		name = hbuf;
1028		(void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
1029		if (RealHostAddr.sa.sa_family != 0)
1030		{
1031			p = &hbuf[strlen(hbuf)];
1032			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
1033					   " (%.100s)",
1034					   anynet_ntoa(&RealHostAddr));
1035		}
1036	}
1037
1038	/* some versions of syslog only take 5 printf args */
1039#if (SYSLOG_BUFSIZE) >= 256
1040	sbp = sbuf;
1041	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1042		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
1043		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
1044		e->e_msgsize, e->e_class, e->e_nrcpts);
1045	sbp += strlen(sbp);
1046	if (msgid != NULL)
1047	{
1048		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1049				", msgid=%.100s", mbuf);
1050		sbp += strlen(sbp);
1051	}
1052	if (e->e_bodytype != NULL)
1053	{
1054		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1055				", bodytype=%.20s", e->e_bodytype);
1056		sbp += strlen(sbp);
1057	}
1058	p = macvalue('r', e);
1059	if (p != NULL)
1060	{
1061		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1062				", proto=%.20s", p);
1063		sbp += strlen(sbp);
1064	}
1065	p = macvalue(macid("{daemon_name}"), e);
1066	if (p != NULL)
1067	{
1068		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1069				", daemon=%.20s", p);
1070		sbp += strlen(sbp);
1071	}
1072	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
1073
1074#else /* (SYSLOG_BUFSIZE) >= 256 */
1075
1076	sm_syslog(LOG_INFO, e->e_id,
1077		  "from=%s",
1078		  e->e_from.q_paddr == NULL ? "<NONE>"
1079					    : shortenstring(e->e_from.q_paddr,
1080							    83));
1081	sm_syslog(LOG_INFO, e->e_id,
1082		  "size=%ld, class=%ld, nrcpts=%d",
1083		  e->e_msgsize, e->e_class, e->e_nrcpts);
1084	if (msgid != NULL)
1085		sm_syslog(LOG_INFO, e->e_id,
1086			  "msgid=%s",
1087			  shortenstring(mbuf, 83));
1088	sbp = sbuf;
1089	*sbp = '\0';
1090	if (e->e_bodytype != NULL)
1091	{
1092		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1093				"bodytype=%.20s, ", e->e_bodytype);
1094		sbp += strlen(sbp);
1095	}
1096	p = macvalue('r', e);
1097	if (p != NULL)
1098	{
1099		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1100				"proto=%.20s, ", p);
1101		sbp += strlen(sbp);
1102	}
1103	sm_syslog(LOG_INFO, e->e_id,
1104		  "%.400srelay=%s", sbuf, name);
1105#endif /* (SYSLOG_BUFSIZE) >= 256 */
1106}
1107/*
1108**  PRIENCODE -- encode external priority names into internal values.
1109**
1110**	Parameters:
1111**		p -- priority in ascii.
1112**
1113**	Returns:
1114**		priority as a numeric level.
1115**
1116**	Side Effects:
1117**		none.
1118*/
1119
1120static int
1121priencode(p)
1122	char *p;
1123{
1124	register int i;
1125
1126	for (i = 0; i < NumPriorities; i++)
1127	{
1128		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
1129			return Priorities[i].pri_val;
1130	}
1131
1132	/* unknown priority */
1133	return 0;
1134}
1135/*
1136**  CRACKADDR -- parse an address and turn it into a macro
1137**
1138**	This doesn't actually parse the address -- it just extracts
1139**	it and replaces it with "$g".  The parse is totally ad hoc
1140**	and isn't even guaranteed to leave something syntactically
1141**	identical to what it started with.  However, it does leave
1142**	something semantically identical if possible, else at least
1143**	syntactically correct.
1144**
1145**	For example, it changes "Real Name <real@example.com> (Comment)"
1146**	to "Real Name <$g> (Comment)".
1147**
1148**	This algorithm has been cleaned up to handle a wider range
1149**	of cases -- notably quoted and backslash escaped strings.
1150**	This modification makes it substantially better at preserving
1151**	the original syntax.
1152**
1153**	Parameters:
1154**		addr -- the address to be cracked.
1155**		e -- the current envelope.
1156**
1157**	Returns:
1158**		a pointer to the new version.
1159**
1160**	Side Effects:
1161**		none.
1162**
1163**	Warning:
1164**		The return value is saved in local storage and should
1165**		be copied if it is to be reused.
1166*/
1167
1168#define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1169
1170/*
1171**  Append a character to bp if we have room.
1172**  If not, punt and return $g.
1173*/
1174
1175#define SM_APPEND_CHAR(c)					\
1176	do							\
1177	{							\
1178		if (SM_HAVE_ROOM)				\
1179			*bp++ = (c);				\
1180		else						\
1181			goto returng;				\
1182	} while (0)
1183
1184#if MAXNAME < 10
1185ERROR MAXNAME must be at least 10
1186#endif /* MAXNAME < 10 */
1187
1188char *
1189crackaddr(addr, e)
1190	register char *addr;
1191	ENVELOPE *e;
1192{
1193	register char *p;
1194	register char c;
1195	int cmtlev;			/* comment level in input string */
1196	int realcmtlev;			/* comment level in output string */
1197	int anglelev;			/* angle level in input string */
1198	int copylev;			/* 0 == in address, >0 copying */
1199	int bracklev;			/* bracket level for IPv6 addr check */
1200	bool addangle;			/* put closing angle in output */
1201	bool qmode;			/* quoting in original string? */
1202	bool realqmode;			/* quoting in output string? */
1203	bool putgmac = false;		/* already wrote $g */
1204	bool quoteit = false;		/* need to quote next character */
1205	bool gotangle = false;		/* found first '<' */
1206	bool gotcolon = false;		/* found a ':' */
1207	register char *bp;
1208	char *buflim;
1209	char *bufhead;
1210	char *addrhead;
1211	char *bufend;
1212	static char buf[MAXNAME + 1];
1213
1214	if (tTd(33, 1))
1215		sm_dprintf("crackaddr(%s)\n", addr);
1216
1217	/* strip leading spaces */
1218	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1219		addr++;
1220
1221	/*
1222	**  Start by assuming we have no angle brackets.  This will be
1223	**  adjusted later if we find them.
1224	*/
1225
1226	buflim = bufend = &buf[sizeof(buf) - 1];
1227	bp = bufhead = buf;
1228	p = addrhead = addr;
1229	copylev = anglelev = cmtlev = realcmtlev = 0;
1230	bracklev = 0;
1231	qmode = realqmode = addangle = false;
1232
1233	while ((c = *p++) != '\0')
1234	{
1235		/*
1236		**  Try to keep legal syntax using spare buffer space
1237		**  (maintained by buflim).
1238		*/
1239
1240		if (copylev > 0)
1241			SM_APPEND_CHAR(c);
1242
1243		/* check for backslash escapes */
1244		if (c == '\\')
1245		{
1246			/* arrange to quote the address */
1247			if (cmtlev <= 0 && !qmode)
1248				quoteit = true;
1249
1250			if ((c = *p++) == '\0')
1251			{
1252				/* too far */
1253				p--;
1254				goto putg;
1255			}
1256			if (copylev > 0)
1257				SM_APPEND_CHAR(c);
1258			goto putg;
1259		}
1260
1261		/* check for quoted strings */
1262		if (c == '"' && cmtlev <= 0)
1263		{
1264			qmode = !qmode;
1265			if (copylev > 0 && SM_HAVE_ROOM)
1266			{
1267				if (realqmode)
1268					buflim--;
1269				else
1270					buflim++;
1271				realqmode = !realqmode;
1272			}
1273			continue;
1274		}
1275		if (qmode)
1276			goto putg;
1277
1278		/* check for comments */
1279		if (c == '(')
1280		{
1281			cmtlev++;
1282
1283			/* allow space for closing paren */
1284			if (SM_HAVE_ROOM)
1285			{
1286				buflim--;
1287				realcmtlev++;
1288				if (copylev++ <= 0)
1289				{
1290					if (bp != bufhead)
1291						SM_APPEND_CHAR(' ');
1292					SM_APPEND_CHAR(c);
1293				}
1294			}
1295		}
1296		if (cmtlev > 0)
1297		{
1298			if (c == ')')
1299			{
1300				cmtlev--;
1301				copylev--;
1302				if (SM_HAVE_ROOM)
1303				{
1304					realcmtlev--;
1305					buflim++;
1306				}
1307			}
1308			continue;
1309		}
1310		else if (c == ')')
1311		{
1312			/* syntax error: unmatched ) */
1313			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1314				bp--;
1315		}
1316
1317		/* count nesting on [ ... ] (for IPv6 domain literals) */
1318		if (c == '[')
1319			bracklev++;
1320		else if (c == ']')
1321			bracklev--;
1322
1323		/* check for group: list; syntax */
1324		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1325		    !gotcolon && !ColonOkInAddr)
1326		{
1327			register char *q;
1328
1329			/*
1330			**  Check for DECnet phase IV ``::'' (host::user)
1331			**  or DECnet phase V ``:.'' syntaxes.  The latter
1332			**  covers ``user@DEC:.tay.myhost'' and
1333			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1334			*/
1335
1336			if (*p == ':' || *p == '.')
1337			{
1338				if (cmtlev <= 0 && !qmode)
1339					quoteit = true;
1340				if (copylev > 0)
1341				{
1342					SM_APPEND_CHAR(c);
1343					SM_APPEND_CHAR(*p);
1344				}
1345				p++;
1346				goto putg;
1347			}
1348
1349			gotcolon = true;
1350
1351			bp = bufhead;
1352			if (quoteit)
1353			{
1354				SM_APPEND_CHAR('"');
1355
1356				/* back up over the ':' and any spaces */
1357				--p;
1358				while (p > addr &&
1359				       isascii(*--p) && isspace(*p))
1360					continue;
1361				p++;
1362			}
1363			for (q = addrhead; q < p; )
1364			{
1365				c = *q++;
1366				if (quoteit && c == '"')
1367					SM_APPEND_CHAR('\\');
1368				SM_APPEND_CHAR(c);
1369			}
1370			if (quoteit)
1371			{
1372				if (bp == &bufhead[1])
1373					bp--;
1374				else
1375					SM_APPEND_CHAR('"');
1376				while ((c = *p++) != ':')
1377					SM_APPEND_CHAR(c);
1378				SM_APPEND_CHAR(c);
1379			}
1380
1381			/* any trailing white space is part of group: */
1382			while (isascii(*p) && isspace(*p))
1383			{
1384				SM_APPEND_CHAR(*p);
1385				p++;
1386			}
1387			copylev = 0;
1388			putgmac = quoteit = false;
1389			bufhead = bp;
1390			addrhead = p;
1391			continue;
1392		}
1393
1394		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1395			SM_APPEND_CHAR(c);
1396
1397		/* check for characters that may have to be quoted */
1398		if (strchr(MustQuoteChars, c) != NULL)
1399		{
1400			/*
1401			**  If these occur as the phrase part of a <>
1402			**  construct, but are not inside of () or already
1403			**  quoted, they will have to be quoted.  Note that
1404			**  now (but don't actually do the quoting).
1405			*/
1406
1407			if (cmtlev <= 0 && !qmode)
1408				quoteit = true;
1409		}
1410
1411		/* check for angle brackets */
1412		if (c == '<')
1413		{
1414			register char *q;
1415
1416			/* assume first of two angles is bogus */
1417			if (gotangle)
1418				quoteit = true;
1419			gotangle = true;
1420
1421			/* oops -- have to change our mind */
1422			anglelev = 1;
1423			if (SM_HAVE_ROOM)
1424			{
1425				if (!addangle)
1426					buflim--;
1427				addangle = true;
1428			}
1429
1430			bp = bufhead;
1431			if (quoteit)
1432			{
1433				SM_APPEND_CHAR('"');
1434
1435				/* back up over the '<' and any spaces */
1436				--p;
1437				while (p > addr &&
1438				       isascii(*--p) && isspace(*p))
1439					continue;
1440				p++;
1441			}
1442			for (q = addrhead; q < p; )
1443			{
1444				c = *q++;
1445				if (quoteit && c == '"')
1446				{
1447					SM_APPEND_CHAR('\\');
1448					SM_APPEND_CHAR(c);
1449				}
1450				else
1451					SM_APPEND_CHAR(c);
1452			}
1453			if (quoteit)
1454			{
1455				if (bp == &buf[1])
1456					bp--;
1457				else
1458					SM_APPEND_CHAR('"');
1459				while ((c = *p++) != '<')
1460					SM_APPEND_CHAR(c);
1461				SM_APPEND_CHAR(c);
1462			}
1463			copylev = 0;
1464			putgmac = quoteit = false;
1465			continue;
1466		}
1467
1468		if (c == '>')
1469		{
1470			if (anglelev > 0)
1471			{
1472				anglelev--;
1473				if (SM_HAVE_ROOM)
1474				{
1475					if (addangle)
1476						buflim++;
1477					addangle = false;
1478				}
1479			}
1480			else if (SM_HAVE_ROOM)
1481			{
1482				/* syntax error: unmatched > */
1483				if (copylev > 0 && bp > bufhead)
1484					bp--;
1485				quoteit = true;
1486				continue;
1487			}
1488			if (copylev++ <= 0)
1489				SM_APPEND_CHAR(c);
1490			continue;
1491		}
1492
1493		/* must be a real address character */
1494	putg:
1495		if (copylev <= 0 && !putgmac)
1496		{
1497			if (bp > buf && bp[-1] == ')')
1498				SM_APPEND_CHAR(' ');
1499			SM_APPEND_CHAR(MACROEXPAND);
1500			SM_APPEND_CHAR('g');
1501			putgmac = true;
1502		}
1503	}
1504
1505	/* repair any syntactic damage */
1506	if (realqmode && bp < bufend)
1507		*bp++ = '"';
1508	while (realcmtlev-- > 0 && bp < bufend)
1509		*bp++ = ')';
1510	if (addangle && bp < bufend)
1511		*bp++ = '>';
1512	*bp = '\0';
1513	if (bp < bufend)
1514		goto success;
1515
1516 returng:
1517	/* String too long, punt */
1518	buf[0] = '<';
1519	buf[1] = MACROEXPAND;
1520	buf[2]= 'g';
1521	buf[3] = '>';
1522	buf[4]= '\0';
1523	sm_syslog(LOG_ALERT, e->e_id,
1524		  "Dropped invalid comments from header address");
1525
1526 success:
1527	if (tTd(33, 1))
1528	{
1529		sm_dprintf("crackaddr=>`");
1530		xputs(sm_debug_file(), buf);
1531		sm_dprintf("'\n");
1532	}
1533	return buf;
1534}
1535/*
1536**  PUTHEADER -- put the header part of a message from the in-core copy
1537**
1538**	Parameters:
1539**		mci -- the connection information.
1540**		hdr -- the header to put.
1541**		e -- envelope to use.
1542**		flags -- MIME conversion flags.
1543**
1544**	Returns:
1545**		none.
1546**
1547**	Side Effects:
1548**		none.
1549*/
1550
1551void
1552putheader(mci, hdr, e, flags)
1553	register MCI *mci;
1554	HDR *hdr;
1555	register ENVELOPE *e;
1556	int flags;
1557{
1558	register HDR *h;
1559	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1560	char obuf[MAXLINE];
1561
1562	if (tTd(34, 1))
1563		sm_dprintf("--- putheader, mailer = %s ---\n",
1564			mci->mci_mailer->m_name);
1565
1566	/*
1567	**  If we're in MIME mode, we're not really in the header of the
1568	**  message, just the header of one of the parts of the body of
1569	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1570	*/
1571
1572	if (!bitset(MCIF_INMIME, mci->mci_flags))
1573		mci->mci_flags |= MCIF_INHEADER;
1574
1575	for (h = hdr; h != NULL; h = h->h_link)
1576	{
1577		register char *p = h->h_value;
1578		char *q;
1579
1580		if (tTd(34, 11))
1581		{
1582			sm_dprintf("  %s: ", h->h_field);
1583			xputs(sm_debug_file(), p);
1584		}
1585
1586		/* Skip empty headers */
1587		if (h->h_value == NULL)
1588			continue;
1589
1590		/* heuristic shortening of MIME fields to avoid MUA overflows */
1591		if (MaxMimeFieldLength > 0 &&
1592		    wordinclass(h->h_field,
1593				macid("{checkMIMEFieldHeaders}")))
1594		{
1595			size_t len;
1596
1597			len = fix_mime_header(h, e);
1598			if (len > 0)
1599			{
1600				sm_syslog(LOG_ALERT, e->e_id,
1601					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1602					  h->h_field, (unsigned long) len);
1603				if (tTd(34, 11))
1604					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1605						   h->h_field,
1606						   (unsigned long) len);
1607			}
1608		}
1609
1610		if (MaxMimeHeaderLength > 0 &&
1611		    wordinclass(h->h_field,
1612				macid("{checkMIMETextHeaders}")))
1613		{
1614			size_t len;
1615
1616			len = strlen(h->h_value);
1617			if (len > (size_t) MaxMimeHeaderLength)
1618			{
1619				h->h_value[MaxMimeHeaderLength - 1] = '\0';
1620				sm_syslog(LOG_ALERT, e->e_id,
1621					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1622					  h->h_field, (unsigned long) len);
1623				if (tTd(34, 11))
1624					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1625						   h->h_field,
1626						   (unsigned long) len);
1627			}
1628		}
1629
1630		if (MaxMimeHeaderLength > 0 &&
1631		    wordinclass(h->h_field,
1632				macid("{checkMIMEHeaders}")))
1633		{
1634			size_t len;
1635
1636			len = strlen(h->h_value);
1637			if (shorten_rfc822_string(h->h_value,
1638						  MaxMimeHeaderLength))
1639			{
1640				if (len < MaxMimeHeaderLength)
1641				{
1642					/* we only rebalanced a bogus header */
1643					sm_syslog(LOG_ALERT, e->e_id,
1644						  "Fixed MIME %s header (possible attack)",
1645						  h->h_field);
1646					if (tTd(34, 11))
1647						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1648							   h->h_field);
1649				}
1650				else
1651				{
1652					/* we actually shortened header */
1653					sm_syslog(LOG_ALERT, e->e_id,
1654						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1655						  h->h_field,
1656						  (unsigned long) len);
1657					if (tTd(34, 11))
1658						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1659							   h->h_field,
1660							   (unsigned long) len);
1661				}
1662			}
1663		}
1664
1665		/*
1666		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1667		**  and we are potentially converting from 8 bit to 7 bit
1668		**  MIME.  If converting, add a new CTE header in
1669		**  mime8to7().
1670		*/
1671
1672		if (bitset(H_CTE, h->h_flags) &&
1673		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1674			   mci->mci_flags) &&
1675		    !bitset(M87F_NO8TO7, flags))
1676		{
1677			if (tTd(34, 11))
1678				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1679			continue;
1680		}
1681
1682		if (bitset(MCIF_INMIME, mci->mci_flags))
1683		{
1684			if (tTd(34, 11))
1685				sm_dprintf("\n");
1686			put_vanilla_header(h, p, mci);
1687			continue;
1688		}
1689
1690		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1691		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1692		    (h->h_macro == '\0' ||
1693		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1694		     *q == '\0'))
1695		{
1696			if (tTd(34, 11))
1697				sm_dprintf(" (skipped)\n");
1698			continue;
1699		}
1700
1701		/* handle Resent-... headers specially */
1702		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1703		{
1704			if (tTd(34, 11))
1705				sm_dprintf(" (skipped (resent))\n");
1706			continue;
1707		}
1708
1709		/* suppress return receipts if requested */
1710		if (bitset(H_RECEIPTTO, h->h_flags) &&
1711		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1712		{
1713			if (tTd(34, 11))
1714				sm_dprintf(" (skipped (receipt))\n");
1715			continue;
1716		}
1717
1718		/* macro expand value if generated internally */
1719		if (bitset(H_DEFAULT, h->h_flags) ||
1720		    bitset(H_BINDLATE, h->h_flags))
1721		{
1722			expand(p, buf, sizeof buf, e);
1723			p = buf;
1724			if (*p == '\0')
1725			{
1726				if (tTd(34, 11))
1727					sm_dprintf(" (skipped -- null value)\n");
1728				continue;
1729			}
1730		}
1731
1732		if (bitset(H_BCC, h->h_flags))
1733		{
1734			/* Bcc: field -- either truncate or delete */
1735			if (bitset(EF_DELETE_BCC, e->e_flags))
1736			{
1737				if (tTd(34, 11))
1738					sm_dprintf(" (skipped -- bcc)\n");
1739			}
1740			else
1741			{
1742				/* no other recipient headers: truncate value */
1743				(void) sm_strlcpyn(obuf, sizeof obuf, 2,
1744						   h->h_field, ":");
1745				putline(obuf, mci);
1746			}
1747			continue;
1748		}
1749
1750		if (tTd(34, 11))
1751			sm_dprintf("\n");
1752
1753		if (bitset(H_FROM|H_RCPT, h->h_flags))
1754		{
1755			/* address field */
1756			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1757
1758			if (bitset(H_FROM, h->h_flags))
1759				oldstyle = false;
1760			commaize(h, p, oldstyle, mci, e);
1761		}
1762		else
1763		{
1764			put_vanilla_header(h, p, mci);
1765		}
1766	}
1767
1768	/*
1769	**  If we are converting this to a MIME message, add the
1770	**  MIME headers (but not in MIME mode!).
1771	*/
1772
1773#if MIME8TO7
1774	if (bitset(MM_MIME8BIT, MimeMode) &&
1775	    bitset(EF_HAS8BIT, e->e_flags) &&
1776	    !bitset(EF_DONT_MIME, e->e_flags) &&
1777	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1778	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1779	    hvalue("MIME-Version", e->e_header) == NULL)
1780	{
1781		putline("MIME-Version: 1.0", mci);
1782		if (hvalue("Content-Type", e->e_header) == NULL)
1783		{
1784			(void) sm_snprintf(obuf, sizeof obuf,
1785					"Content-Type: text/plain; charset=%s",
1786					defcharset(e));
1787			putline(obuf, mci);
1788		}
1789		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1790			putline("Content-Transfer-Encoding: 8bit", mci);
1791	}
1792#endif /* MIME8TO7 */
1793}
1794/*
1795**  PUT_VANILLA_HEADER -- output a fairly ordinary header
1796**
1797**	Parameters:
1798**		h -- the structure describing this header
1799**		v -- the value of this header
1800**		mci -- the connection info for output
1801**
1802**	Returns:
1803**		none.
1804*/
1805
1806static void
1807put_vanilla_header(h, v, mci)
1808	HDR *h;
1809	char *v;
1810	MCI *mci;
1811{
1812	register char *nlp;
1813	register char *obp;
1814	int putflags;
1815	char obuf[MAXLINE];
1816
1817	putflags = PXLF_HEADER;
1818	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1819		putflags |= PXLF_STRIP8BIT;
1820	(void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1821	obp = obuf + strlen(obuf);
1822	while ((nlp = strchr(v, '\n')) != NULL)
1823	{
1824		int l;
1825
1826		l = nlp - v;
1827
1828		/*
1829		**  XXX This is broken for SPACELEFT()==0
1830		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
1831		*/
1832
1833		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1834			l = SPACELEFT(obuf, obp) - 1;
1835
1836		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1837		putxline(obuf, strlen(obuf), mci, putflags);
1838		v += l + 1;
1839		obp = obuf;
1840		if (*v != ' ' && *v != '\t')
1841			*obp++ = ' ';
1842	}
1843
1844	/* XXX This is broken for SPACELEFT()==0 */
1845	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1846			   (int) (SPACELEFT(obuf, obp) - 1), v);
1847	putxline(obuf, strlen(obuf), mci, putflags);
1848}
1849/*
1850**  COMMAIZE -- output a header field, making a comma-translated list.
1851**
1852**	Parameters:
1853**		h -- the header field to output.
1854**		p -- the value to put in it.
1855**		oldstyle -- true if this is an old style header.
1856**		mci -- the connection information.
1857**		e -- the envelope containing the message.
1858**
1859**	Returns:
1860**		none.
1861**
1862**	Side Effects:
1863**		outputs "p" to file "fp".
1864*/
1865
1866void
1867commaize(h, p, oldstyle, mci, e)
1868	register HDR *h;
1869	register char *p;
1870	bool oldstyle;
1871	register MCI *mci;
1872	register ENVELOPE *e;
1873{
1874	register char *obp;
1875	int opos;
1876	int omax;
1877	bool firstone = true;
1878	int putflags = PXLF_HEADER;
1879	char **res;
1880	char obuf[MAXLINE + 3];
1881
1882	/*
1883	**  Output the address list translated by the
1884	**  mailer and with commas.
1885	*/
1886
1887	if (tTd(14, 2))
1888		sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1889
1890	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1891		putflags |= PXLF_STRIP8BIT;
1892
1893	obp = obuf;
1894	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
1895			h->h_field);
1896
1897	/* opos = strlen(obp); */
1898	opos = strlen(h->h_field) + 2;
1899	if (opos > 202)
1900		opos = 202;
1901	obp += opos;
1902	omax = mci->mci_mailer->m_linelimit - 2;
1903	if (omax < 0 || omax > 78)
1904		omax = 78;
1905
1906	/*
1907	**  Run through the list of values.
1908	*/
1909
1910	while (*p != '\0')
1911	{
1912		register char *name;
1913		register int c;
1914		char savechar;
1915		int flags;
1916		auto int status;
1917
1918		/*
1919		**  Find the end of the name.  New style names
1920		**  end with a comma, old style names end with
1921		**  a space character.  However, spaces do not
1922		**  necessarily delimit an old-style name -- at
1923		**  signs mean keep going.
1924		*/
1925
1926		/* find end of name */
1927		while ((isascii(*p) && isspace(*p)) || *p == ',')
1928			p++;
1929		name = p;
1930		res = NULL;
1931		for (;;)
1932		{
1933			auto char *oldp;
1934			char pvpbuf[PSBUFSIZE];
1935
1936			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1937				      sizeof pvpbuf, &oldp, NULL, false);
1938			p = oldp;
1939#if _FFR_IGNORE_BOGUS_ADDR
1940			/* ignore addresses that can't be parsed */
1941			if (res == NULL)
1942			{
1943				name = p;
1944				continue;
1945			}
1946#endif /* _FFR_IGNORE_BOGUS_ADDR */
1947
1948			/* look to see if we have an at sign */
1949			while (*p != '\0' && isascii(*p) && isspace(*p))
1950				p++;
1951
1952			if (*p != '@')
1953			{
1954				p = oldp;
1955				break;
1956			}
1957			++p;
1958			while (*p != '\0' && isascii(*p) && isspace(*p))
1959				p++;
1960		}
1961		/* at the end of one complete name */
1962
1963		/* strip off trailing white space */
1964		while (p >= name &&
1965		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1966			p--;
1967		if (++p == name)
1968			continue;
1969
1970		/*
1971		**  if prescan() failed go a bit backwards; this is a hack,
1972		**  there should be some better error recovery.
1973		*/
1974
1975		if (res == NULL && p > name &&
1976		    !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1977			--p;
1978		savechar = *p;
1979		*p = '\0';
1980
1981		/* translate the name to be relative */
1982		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1983		if (bitset(H_FROM, h->h_flags))
1984			flags |= RF_SENDERADDR;
1985#if USERDB
1986		else if (e->e_from.q_mailer != NULL &&
1987			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1988		{
1989			char *q;
1990
1991			q = udbsender(name, e->e_rpool);
1992			if (q != NULL)
1993				name = q;
1994		}
1995#endif /* USERDB */
1996		status = EX_OK;
1997		name = remotename(name, mci->mci_mailer, flags, &status, e);
1998		if (*name == '\0')
1999		{
2000			*p = savechar;
2001			continue;
2002		}
2003		name = denlstring(name, false, true);
2004
2005		/*
2006		**  record data progress so DNS timeouts
2007		**  don't cause DATA timeouts
2008		*/
2009
2010		DataProgress = true;
2011
2012		/* output the name with nice formatting */
2013		opos += strlen(name);
2014		if (!firstone)
2015			opos += 2;
2016		if (opos > omax && !firstone)
2017		{
2018			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2019			putxline(obuf, strlen(obuf), mci, putflags);
2020			obp = obuf;
2021			(void) sm_strlcpy(obp, "        ", sizeof obuf);
2022			opos = strlen(obp);
2023			obp += opos;
2024			opos += strlen(name);
2025		}
2026		else if (!firstone)
2027		{
2028			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2029			obp += 2;
2030		}
2031
2032		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2033			*obp++ = c;
2034		firstone = false;
2035		*p = savechar;
2036	}
2037	if (obp < &obuf[sizeof obuf])
2038		*obp = '\0';
2039	else
2040		obuf[sizeof obuf - 1] = '\0';
2041	putxline(obuf, strlen(obuf), mci, putflags);
2042}
2043/*
2044**  COPYHEADER -- copy header list
2045**
2046**	This routine is the equivalent of newstr for header lists
2047**
2048**	Parameters:
2049**		header -- list of header structures to copy.
2050**		rpool -- resource pool, or NULL
2051**
2052**	Returns:
2053**		a copy of 'header'.
2054**
2055**	Side Effects:
2056**		none.
2057*/
2058
2059HDR *
2060copyheader(header, rpool)
2061	register HDR *header;
2062	SM_RPOOL_T *rpool;
2063{
2064	register HDR *newhdr;
2065	HDR *ret;
2066	register HDR **tail = &ret;
2067
2068	while (header != NULL)
2069	{
2070		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
2071		STRUCTCOPY(*header, *newhdr);
2072		*tail = newhdr;
2073		tail = &newhdr->h_link;
2074		header = header->h_link;
2075	}
2076	*tail = NULL;
2077
2078	return ret;
2079}
2080/*
2081**  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
2082**
2083**	Run through all of the parameters of a MIME header and
2084**	possibly truncate and rebalance the parameter according
2085**	to MaxMimeFieldLength.
2086**
2087**	Parameters:
2088**		h -- the header to truncate/rebalance
2089**		e -- the current envelope
2090**
2091**	Returns:
2092**		length of last offending field, 0 if all ok.
2093**
2094**	Side Effects:
2095**		string modified in place
2096*/
2097
2098static size_t
2099fix_mime_header(h, e)
2100	HDR *h;
2101	ENVELOPE *e;
2102{
2103	char *begin = h->h_value;
2104	char *end;
2105	size_t len = 0;
2106	size_t retlen = 0;
2107
2108	if (begin == NULL || *begin == '\0')
2109		return 0;
2110
2111	/* Split on each ';' */
2112	/* find_character() never returns NULL */
2113	while ((end = find_character(begin, ';')) != NULL)
2114	{
2115		char save = *end;
2116		char *bp;
2117
2118		*end = '\0';
2119
2120		len = strlen(begin);
2121
2122		/* Shorten individual parameter */
2123		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2124		{
2125			if (len < MaxMimeFieldLength)
2126			{
2127				/* we only rebalanced a bogus field */
2128				sm_syslog(LOG_ALERT, e->e_id,
2129					  "Fixed MIME %s header field (possible attack)",
2130					  h->h_field);
2131				if (tTd(34, 11))
2132					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
2133						   h->h_field);
2134			}
2135			else
2136			{
2137				/* we actually shortened the header */
2138				retlen = len;
2139			}
2140		}
2141
2142		/* Collapse the possibly shortened string with rest */
2143		bp = begin + strlen(begin);
2144		if (bp != end)
2145		{
2146			char *ep = end;
2147
2148			*end = save;
2149			end = bp;
2150
2151			/* copy character by character due to overlap */
2152			while (*ep != '\0')
2153				*bp++ = *ep++;
2154			*bp = '\0';
2155		}
2156		else
2157			*end = save;
2158		if (*end == '\0')
2159			break;
2160
2161		/* Move past ';' */
2162		begin = end + 1;
2163	}
2164	return retlen;
2165}
2166