headers.c revision 159613
1/*
2 * Copyright (c) 1998-2004, 2006 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 159613 2006-06-14 16:25:31Z gshapiro $
13 */
14
15#include <sendmail.h>
16
17SM_RCSID("@(#)$Id: headers.c,v 8.291 2006/03/24 01:01:56 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 bool	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	char hbuf[MAXNAME + 1];
998	char sbuf[MAXLINE + 1];
999	char mbuf[MAXNAME + 1];
1000
1001	/* don't allow newlines in the message-id */
1002	/* XXX do we still need this? sm_syslog() replaces control chars */
1003	if (msgid != NULL)
1004	{
1005		size_t l;
1006
1007		l = strlen(msgid);
1008		if (l > sizeof mbuf - 1)
1009			l = sizeof mbuf - 1;
1010		memmove(mbuf, msgid, l);
1011		mbuf[l] = '\0';
1012		p = mbuf;
1013		while ((p = strchr(p, '\n')) != NULL)
1014			*p++ = ' ';
1015	}
1016
1017	if (bitset(EF_RESPONSE, e->e_flags))
1018		name = "[RESPONSE]";
1019	else if ((name = macvalue('_', e)) != NULL)
1020		/* EMPTY */
1021		;
1022	else if (RealHostName == NULL)
1023		name = "localhost";
1024	else if (RealHostName[0] == '[')
1025		name = RealHostName;
1026	else
1027	{
1028		name = hbuf;
1029		(void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
1030		if (RealHostAddr.sa.sa_family != 0)
1031		{
1032			p = &hbuf[strlen(hbuf)];
1033			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
1034					   " (%.100s)",
1035					   anynet_ntoa(&RealHostAddr));
1036		}
1037	}
1038
1039	/* some versions of syslog only take 5 printf args */
1040#if (SYSLOG_BUFSIZE) >= 256
1041	sbp = sbuf;
1042	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1043		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
1044		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
1045		e->e_msgsize, e->e_class, e->e_nrcpts);
1046	sbp += strlen(sbp);
1047	if (msgid != NULL)
1048	{
1049		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1050				", msgid=%.100s", mbuf);
1051		sbp += strlen(sbp);
1052	}
1053	if (e->e_bodytype != NULL)
1054	{
1055		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1056				", bodytype=%.20s", e->e_bodytype);
1057		sbp += strlen(sbp);
1058	}
1059	p = macvalue('r', e);
1060	if (p != NULL)
1061	{
1062		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1063				", proto=%.20s", p);
1064		sbp += strlen(sbp);
1065	}
1066	p = macvalue(macid("{daemon_name}"), e);
1067	if (p != NULL)
1068	{
1069		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1070				", daemon=%.20s", p);
1071		sbp += strlen(sbp);
1072	}
1073	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
1074
1075#else /* (SYSLOG_BUFSIZE) >= 256 */
1076
1077	sm_syslog(LOG_INFO, e->e_id,
1078		  "from=%s",
1079		  e->e_from.q_paddr == NULL ? "<NONE>"
1080					    : shortenstring(e->e_from.q_paddr,
1081							    83));
1082	sm_syslog(LOG_INFO, e->e_id,
1083		  "size=%ld, class=%ld, nrcpts=%d",
1084		  e->e_msgsize, e->e_class, e->e_nrcpts);
1085	if (msgid != NULL)
1086		sm_syslog(LOG_INFO, e->e_id,
1087			  "msgid=%s",
1088			  shortenstring(mbuf, 83));
1089	sbp = sbuf;
1090	*sbp = '\0';
1091	if (e->e_bodytype != NULL)
1092	{
1093		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1094				"bodytype=%.20s, ", e->e_bodytype);
1095		sbp += strlen(sbp);
1096	}
1097	p = macvalue('r', e);
1098	if (p != NULL)
1099	{
1100		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1101				"proto=%.20s, ", p);
1102		sbp += strlen(sbp);
1103	}
1104	sm_syslog(LOG_INFO, e->e_id,
1105		  "%.400srelay=%s", sbuf, name);
1106#endif /* (SYSLOG_BUFSIZE) >= 256 */
1107}
1108/*
1109**  PRIENCODE -- encode external priority names into internal values.
1110**
1111**	Parameters:
1112**		p -- priority in ascii.
1113**
1114**	Returns:
1115**		priority as a numeric level.
1116**
1117**	Side Effects:
1118**		none.
1119*/
1120
1121static int
1122priencode(p)
1123	char *p;
1124{
1125	register int i;
1126
1127	for (i = 0; i < NumPriorities; i++)
1128	{
1129		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
1130			return Priorities[i].pri_val;
1131	}
1132
1133	/* unknown priority */
1134	return 0;
1135}
1136/*
1137**  CRACKADDR -- parse an address and turn it into a macro
1138**
1139**	This doesn't actually parse the address -- it just extracts
1140**	it and replaces it with "$g".  The parse is totally ad hoc
1141**	and isn't even guaranteed to leave something syntactically
1142**	identical to what it started with.  However, it does leave
1143**	something semantically identical if possible, else at least
1144**	syntactically correct.
1145**
1146**	For example, it changes "Real Name <real@example.com> (Comment)"
1147**	to "Real Name <$g> (Comment)".
1148**
1149**	This algorithm has been cleaned up to handle a wider range
1150**	of cases -- notably quoted and backslash escaped strings.
1151**	This modification makes it substantially better at preserving
1152**	the original syntax.
1153**
1154**	Parameters:
1155**		addr -- the address to be cracked.
1156**		e -- the current envelope.
1157**
1158**	Returns:
1159**		a pointer to the new version.
1160**
1161**	Side Effects:
1162**		none.
1163**
1164**	Warning:
1165**		The return value is saved in local storage and should
1166**		be copied if it is to be reused.
1167*/
1168
1169#define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1170
1171/*
1172**  Append a character to bp if we have room.
1173**  If not, punt and return $g.
1174*/
1175
1176#define SM_APPEND_CHAR(c)					\
1177	do							\
1178	{							\
1179		if (SM_HAVE_ROOM)				\
1180			*bp++ = (c);				\
1181		else						\
1182			goto returng;				\
1183	} while (0)
1184
1185#if MAXNAME < 10
1186ERROR MAXNAME must be at least 10
1187#endif /* MAXNAME < 10 */
1188
1189char *
1190crackaddr(addr, e)
1191	register char *addr;
1192	ENVELOPE *e;
1193{
1194	register char *p;
1195	register char c;
1196	int cmtlev;			/* comment level in input string */
1197	int realcmtlev;			/* comment level in output string */
1198	int anglelev;			/* angle level in input string */
1199	int copylev;			/* 0 == in address, >0 copying */
1200	int bracklev;			/* bracket level for IPv6 addr check */
1201	bool addangle;			/* put closing angle in output */
1202	bool qmode;			/* quoting in original string? */
1203	bool realqmode;			/* quoting in output string? */
1204	bool putgmac = false;		/* already wrote $g */
1205	bool quoteit = false;		/* need to quote next character */
1206	bool gotangle = false;		/* found first '<' */
1207	bool gotcolon = false;		/* found a ':' */
1208	register char *bp;
1209	char *buflim;
1210	char *bufhead;
1211	char *addrhead;
1212	char *bufend;
1213	static char buf[MAXNAME + 1];
1214
1215	if (tTd(33, 1))
1216		sm_dprintf("crackaddr(%s)\n", addr);
1217
1218	/* strip leading spaces */
1219	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1220		addr++;
1221
1222	/*
1223	**  Start by assuming we have no angle brackets.  This will be
1224	**  adjusted later if we find them.
1225	*/
1226
1227	buflim = bufend = &buf[sizeof(buf) - 1];
1228	bp = bufhead = buf;
1229	p = addrhead = addr;
1230	copylev = anglelev = cmtlev = realcmtlev = 0;
1231	bracklev = 0;
1232	qmode = realqmode = addangle = false;
1233
1234	while ((c = *p++) != '\0')
1235	{
1236		/*
1237		**  Try to keep legal syntax using spare buffer space
1238		**  (maintained by buflim).
1239		*/
1240
1241		if (copylev > 0)
1242			SM_APPEND_CHAR(c);
1243
1244		/* check for backslash escapes */
1245		if (c == '\\')
1246		{
1247			/* arrange to quote the address */
1248			if (cmtlev <= 0 && !qmode)
1249				quoteit = true;
1250
1251			if ((c = *p++) == '\0')
1252			{
1253				/* too far */
1254				p--;
1255				goto putg;
1256			}
1257			if (copylev > 0)
1258				SM_APPEND_CHAR(c);
1259			goto putg;
1260		}
1261
1262		/* check for quoted strings */
1263		if (c == '"' && cmtlev <= 0)
1264		{
1265			qmode = !qmode;
1266			if (copylev > 0 && SM_HAVE_ROOM)
1267			{
1268				if (realqmode)
1269					buflim--;
1270				else
1271					buflim++;
1272				realqmode = !realqmode;
1273			}
1274			continue;
1275		}
1276		if (qmode)
1277			goto putg;
1278
1279		/* check for comments */
1280		if (c == '(')
1281		{
1282			cmtlev++;
1283
1284			/* allow space for closing paren */
1285			if (SM_HAVE_ROOM)
1286			{
1287				buflim--;
1288				realcmtlev++;
1289				if (copylev++ <= 0)
1290				{
1291					if (bp != bufhead)
1292						SM_APPEND_CHAR(' ');
1293					SM_APPEND_CHAR(c);
1294				}
1295			}
1296		}
1297		if (cmtlev > 0)
1298		{
1299			if (c == ')')
1300			{
1301				cmtlev--;
1302				copylev--;
1303				if (SM_HAVE_ROOM)
1304				{
1305					realcmtlev--;
1306					buflim++;
1307				}
1308			}
1309			continue;
1310		}
1311		else if (c == ')')
1312		{
1313			/* syntax error: unmatched ) */
1314			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1315				bp--;
1316		}
1317
1318		/* count nesting on [ ... ] (for IPv6 domain literals) */
1319		if (c == '[')
1320			bracklev++;
1321		else if (c == ']')
1322			bracklev--;
1323
1324		/* check for group: list; syntax */
1325		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1326		    !gotcolon && !ColonOkInAddr)
1327		{
1328			register char *q;
1329
1330			/*
1331			**  Check for DECnet phase IV ``::'' (host::user)
1332			**  or DECnet phase V ``:.'' syntaxes.  The latter
1333			**  covers ``user@DEC:.tay.myhost'' and
1334			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1335			*/
1336
1337			if (*p == ':' || *p == '.')
1338			{
1339				if (cmtlev <= 0 && !qmode)
1340					quoteit = true;
1341				if (copylev > 0)
1342				{
1343					SM_APPEND_CHAR(c);
1344					SM_APPEND_CHAR(*p);
1345				}
1346				p++;
1347				goto putg;
1348			}
1349
1350			gotcolon = true;
1351
1352			bp = bufhead;
1353			if (quoteit)
1354			{
1355				SM_APPEND_CHAR('"');
1356
1357				/* back up over the ':' and any spaces */
1358				--p;
1359				while (p > addr &&
1360				       isascii(*--p) && isspace(*p))
1361					continue;
1362				p++;
1363			}
1364			for (q = addrhead; q < p; )
1365			{
1366				c = *q++;
1367				if (quoteit && c == '"')
1368					SM_APPEND_CHAR('\\');
1369				SM_APPEND_CHAR(c);
1370			}
1371			if (quoteit)
1372			{
1373				if (bp == &bufhead[1])
1374					bp--;
1375				else
1376					SM_APPEND_CHAR('"');
1377				while ((c = *p++) != ':')
1378					SM_APPEND_CHAR(c);
1379				SM_APPEND_CHAR(c);
1380			}
1381
1382			/* any trailing white space is part of group: */
1383			while (isascii(*p) && isspace(*p))
1384			{
1385				SM_APPEND_CHAR(*p);
1386				p++;
1387			}
1388			copylev = 0;
1389			putgmac = quoteit = false;
1390			bufhead = bp;
1391			addrhead = p;
1392			continue;
1393		}
1394
1395		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1396			SM_APPEND_CHAR(c);
1397
1398		/* check for characters that may have to be quoted */
1399		if (strchr(MustQuoteChars, c) != NULL)
1400		{
1401			/*
1402			**  If these occur as the phrase part of a <>
1403			**  construct, but are not inside of () or already
1404			**  quoted, they will have to be quoted.  Note that
1405			**  now (but don't actually do the quoting).
1406			*/
1407
1408			if (cmtlev <= 0 && !qmode)
1409				quoteit = true;
1410		}
1411
1412		/* check for angle brackets */
1413		if (c == '<')
1414		{
1415			register char *q;
1416
1417			/* assume first of two angles is bogus */
1418			if (gotangle)
1419				quoteit = true;
1420			gotangle = true;
1421
1422			/* oops -- have to change our mind */
1423			anglelev = 1;
1424			if (SM_HAVE_ROOM)
1425			{
1426				if (!addangle)
1427					buflim--;
1428				addangle = true;
1429			}
1430
1431			bp = bufhead;
1432			if (quoteit)
1433			{
1434				SM_APPEND_CHAR('"');
1435
1436				/* back up over the '<' and any spaces */
1437				--p;
1438				while (p > addr &&
1439				       isascii(*--p) && isspace(*p))
1440					continue;
1441				p++;
1442			}
1443			for (q = addrhead; q < p; )
1444			{
1445				c = *q++;
1446				if (quoteit && c == '"')
1447				{
1448					SM_APPEND_CHAR('\\');
1449					SM_APPEND_CHAR(c);
1450				}
1451				else
1452					SM_APPEND_CHAR(c);
1453			}
1454			if (quoteit)
1455			{
1456				if (bp == &buf[1])
1457					bp--;
1458				else
1459					SM_APPEND_CHAR('"');
1460				while ((c = *p++) != '<')
1461					SM_APPEND_CHAR(c);
1462				SM_APPEND_CHAR(c);
1463			}
1464			copylev = 0;
1465			putgmac = quoteit = false;
1466			continue;
1467		}
1468
1469		if (c == '>')
1470		{
1471			if (anglelev > 0)
1472			{
1473				anglelev--;
1474				if (SM_HAVE_ROOM)
1475				{
1476					if (addangle)
1477						buflim++;
1478					addangle = false;
1479				}
1480			}
1481			else if (SM_HAVE_ROOM)
1482			{
1483				/* syntax error: unmatched > */
1484				if (copylev > 0 && bp > bufhead)
1485					bp--;
1486				quoteit = true;
1487				continue;
1488			}
1489			if (copylev++ <= 0)
1490				SM_APPEND_CHAR(c);
1491			continue;
1492		}
1493
1494		/* must be a real address character */
1495	putg:
1496		if (copylev <= 0 && !putgmac)
1497		{
1498			if (bp > buf && bp[-1] == ')')
1499				SM_APPEND_CHAR(' ');
1500			SM_APPEND_CHAR(MACROEXPAND);
1501			SM_APPEND_CHAR('g');
1502			putgmac = true;
1503		}
1504	}
1505
1506	/* repair any syntactic damage */
1507	if (realqmode && bp < bufend)
1508		*bp++ = '"';
1509	while (realcmtlev-- > 0 && bp < bufend)
1510		*bp++ = ')';
1511	if (addangle && bp < bufend)
1512		*bp++ = '>';
1513	*bp = '\0';
1514	if (bp < bufend)
1515		goto success;
1516
1517 returng:
1518	/* String too long, punt */
1519	buf[0] = '<';
1520	buf[1] = MACROEXPAND;
1521	buf[2]= 'g';
1522	buf[3] = '>';
1523	buf[4]= '\0';
1524	sm_syslog(LOG_ALERT, e->e_id,
1525		  "Dropped invalid comments from header address");
1526
1527 success:
1528	if (tTd(33, 1))
1529	{
1530		sm_dprintf("crackaddr=>`");
1531		xputs(sm_debug_file(), buf);
1532		sm_dprintf("'\n");
1533	}
1534	return buf;
1535}
1536/*
1537**  PUTHEADER -- put the header part of a message from the in-core copy
1538**
1539**	Parameters:
1540**		mci -- the connection information.
1541**		hdr -- the header to put.
1542**		e -- envelope to use.
1543**		flags -- MIME conversion flags.
1544**
1545**	Returns:
1546**		true iff header part was written successfully
1547**
1548**	Side Effects:
1549**		none.
1550*/
1551
1552bool
1553putheader(mci, hdr, e, flags)
1554	register MCI *mci;
1555	HDR *hdr;
1556	register ENVELOPE *e;
1557	int flags;
1558{
1559	register HDR *h;
1560	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1561	char obuf[MAXLINE];
1562
1563	if (tTd(34, 1))
1564		sm_dprintf("--- putheader, mailer = %s ---\n",
1565			mci->mci_mailer->m_name);
1566
1567	/*
1568	**  If we're in MIME mode, we're not really in the header of the
1569	**  message, just the header of one of the parts of the body of
1570	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1571	*/
1572
1573	if (!bitset(MCIF_INMIME, mci->mci_flags))
1574		mci->mci_flags |= MCIF_INHEADER;
1575
1576	for (h = hdr; h != NULL; h = h->h_link)
1577	{
1578		register char *p = h->h_value;
1579		char *q;
1580
1581		if (tTd(34, 11))
1582		{
1583			sm_dprintf("  %s: ", h->h_field);
1584			xputs(sm_debug_file(), p);
1585		}
1586
1587		/* Skip empty headers */
1588		if (h->h_value == NULL)
1589			continue;
1590
1591		/* heuristic shortening of MIME fields to avoid MUA overflows */
1592		if (MaxMimeFieldLength > 0 &&
1593		    wordinclass(h->h_field,
1594				macid("{checkMIMEFieldHeaders}")))
1595		{
1596			size_t len;
1597
1598			len = fix_mime_header(h, e);
1599			if (len > 0)
1600			{
1601				sm_syslog(LOG_ALERT, e->e_id,
1602					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1603					  h->h_field, (unsigned long) len);
1604				if (tTd(34, 11))
1605					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1606						   h->h_field,
1607						   (unsigned long) len);
1608			}
1609		}
1610
1611		if (MaxMimeHeaderLength > 0 &&
1612		    wordinclass(h->h_field,
1613				macid("{checkMIMETextHeaders}")))
1614		{
1615			size_t len;
1616
1617			len = strlen(h->h_value);
1618			if (len > (size_t) MaxMimeHeaderLength)
1619			{
1620				h->h_value[MaxMimeHeaderLength - 1] = '\0';
1621				sm_syslog(LOG_ALERT, e->e_id,
1622					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1623					  h->h_field, (unsigned long) len);
1624				if (tTd(34, 11))
1625					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1626						   h->h_field,
1627						   (unsigned long) len);
1628			}
1629		}
1630
1631		if (MaxMimeHeaderLength > 0 &&
1632		    wordinclass(h->h_field,
1633				macid("{checkMIMEHeaders}")))
1634		{
1635			size_t len;
1636
1637			len = strlen(h->h_value);
1638			if (shorten_rfc822_string(h->h_value,
1639						  MaxMimeHeaderLength))
1640			{
1641				if (len < MaxMimeHeaderLength)
1642				{
1643					/* we only rebalanced a bogus header */
1644					sm_syslog(LOG_ALERT, e->e_id,
1645						  "Fixed MIME %s header (possible attack)",
1646						  h->h_field);
1647					if (tTd(34, 11))
1648						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1649							   h->h_field);
1650				}
1651				else
1652				{
1653					/* we actually shortened header */
1654					sm_syslog(LOG_ALERT, e->e_id,
1655						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1656						  h->h_field,
1657						  (unsigned long) len);
1658					if (tTd(34, 11))
1659						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1660							   h->h_field,
1661							   (unsigned long) len);
1662				}
1663			}
1664		}
1665
1666		/*
1667		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1668		**  and we are potentially converting from 8 bit to 7 bit
1669		**  MIME.  If converting, add a new CTE header in
1670		**  mime8to7().
1671		*/
1672
1673		if (bitset(H_CTE, h->h_flags) &&
1674		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1675			   mci->mci_flags) &&
1676		    !bitset(M87F_NO8TO7, flags))
1677		{
1678			if (tTd(34, 11))
1679				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1680			continue;
1681		}
1682
1683		if (bitset(MCIF_INMIME, mci->mci_flags))
1684		{
1685			if (tTd(34, 11))
1686				sm_dprintf("\n");
1687			if (!put_vanilla_header(h, p, mci))
1688				goto writeerr;
1689			continue;
1690		}
1691
1692		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1693		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1694		    (h->h_macro == '\0' ||
1695		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1696		     *q == '\0'))
1697		{
1698			if (tTd(34, 11))
1699				sm_dprintf(" (skipped)\n");
1700			continue;
1701		}
1702
1703		/* handle Resent-... headers specially */
1704		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1705		{
1706			if (tTd(34, 11))
1707				sm_dprintf(" (skipped (resent))\n");
1708			continue;
1709		}
1710
1711		/* suppress return receipts if requested */
1712		if (bitset(H_RECEIPTTO, h->h_flags) &&
1713		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1714		{
1715			if (tTd(34, 11))
1716				sm_dprintf(" (skipped (receipt))\n");
1717			continue;
1718		}
1719
1720		/* macro expand value if generated internally */
1721		if (bitset(H_DEFAULT, h->h_flags) ||
1722		    bitset(H_BINDLATE, h->h_flags))
1723		{
1724			expand(p, buf, sizeof buf, e);
1725			p = buf;
1726			if (*p == '\0')
1727			{
1728				if (tTd(34, 11))
1729					sm_dprintf(" (skipped -- null value)\n");
1730				continue;
1731			}
1732		}
1733
1734		if (bitset(H_BCC, h->h_flags))
1735		{
1736			/* Bcc: field -- either truncate or delete */
1737			if (bitset(EF_DELETE_BCC, e->e_flags))
1738			{
1739				if (tTd(34, 11))
1740					sm_dprintf(" (skipped -- bcc)\n");
1741			}
1742			else
1743			{
1744				/* no other recipient headers: truncate value */
1745				(void) sm_strlcpyn(obuf, sizeof obuf, 2,
1746						   h->h_field, ":");
1747				if (!putline(obuf, mci))
1748					goto writeerr;
1749			}
1750			continue;
1751		}
1752
1753		if (tTd(34, 11))
1754			sm_dprintf("\n");
1755
1756		if (bitset(H_FROM|H_RCPT, h->h_flags))
1757		{
1758			/* address field */
1759			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1760
1761			if (bitset(H_FROM, h->h_flags))
1762				oldstyle = false;
1763			commaize(h, p, oldstyle, mci, e);
1764		}
1765		else
1766		{
1767			if (!put_vanilla_header(h, p, mci))
1768				goto writeerr;
1769		}
1770	}
1771
1772	/*
1773	**  If we are converting this to a MIME message, add the
1774	**  MIME headers (but not in MIME mode!).
1775	*/
1776
1777#if MIME8TO7
1778	if (bitset(MM_MIME8BIT, MimeMode) &&
1779	    bitset(EF_HAS8BIT, e->e_flags) &&
1780	    !bitset(EF_DONT_MIME, e->e_flags) &&
1781	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1782	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1783	    hvalue("MIME-Version", e->e_header) == NULL)
1784	{
1785		if (!putline("MIME-Version: 1.0", mci))
1786			goto writeerr;
1787		if (hvalue("Content-Type", e->e_header) == NULL)
1788		{
1789			(void) sm_snprintf(obuf, sizeof obuf,
1790					"Content-Type: text/plain; charset=%s",
1791					defcharset(e));
1792			if (!putline(obuf, mci))
1793				goto writeerr;
1794		}
1795		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1796		    && !putline("Content-Transfer-Encoding: 8bit", mci))
1797			goto writeerr;
1798	}
1799#endif /* MIME8TO7 */
1800	return true;
1801
1802  writeerr:
1803	return false;
1804}
1805/*
1806**  PUT_VANILLA_HEADER -- output a fairly ordinary header
1807**
1808**	Parameters:
1809**		h -- the structure describing this header
1810**		v -- the value of this header
1811**		mci -- the connection info for output
1812**
1813**	Returns:
1814**		true iff header was written successfully
1815*/
1816
1817static bool
1818put_vanilla_header(h, v, mci)
1819	HDR *h;
1820	char *v;
1821	MCI *mci;
1822{
1823	register char *nlp;
1824	register char *obp;
1825	int putflags;
1826	char obuf[MAXLINE + 256];	/* additional length for h_field */
1827
1828	putflags = PXLF_HEADER;
1829	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1830		putflags |= PXLF_STRIP8BIT;
1831	(void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1832	obp = obuf + strlen(obuf);
1833	while ((nlp = strchr(v, '\n')) != NULL)
1834	{
1835		int l;
1836
1837		l = nlp - v;
1838
1839		/*
1840		**  XXX This is broken for SPACELEFT()==0
1841		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
1842		*/
1843
1844		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1845			l = SPACELEFT(obuf, obp) - 1;
1846
1847		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1848		if (!putxline(obuf, strlen(obuf), mci, putflags))
1849			goto writeerr;
1850		v += l + 1;
1851		obp = obuf;
1852		if (*v != ' ' && *v != '\t')
1853			*obp++ = ' ';
1854	}
1855
1856	/* XXX This is broken for SPACELEFT()==0 */
1857	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1858			   (int) (SPACELEFT(obuf, obp) - 1), v);
1859	return putxline(obuf, strlen(obuf), mci, putflags);
1860
1861  writeerr:
1862	return false;
1863}
1864/*
1865**  COMMAIZE -- output a header field, making a comma-translated list.
1866**
1867**	Parameters:
1868**		h -- the header field to output.
1869**		p -- the value to put in it.
1870**		oldstyle -- true if this is an old style header.
1871**		mci -- the connection information.
1872**		e -- the envelope containing the message.
1873**
1874**	Returns:
1875**		true iff header field was written successfully
1876**
1877**	Side Effects:
1878**		outputs "p" to file "fp".
1879*/
1880
1881bool
1882commaize(h, p, oldstyle, mci, e)
1883	register HDR *h;
1884	register char *p;
1885	bool oldstyle;
1886	register MCI *mci;
1887	register ENVELOPE *e;
1888{
1889	register char *obp;
1890	int opos;
1891	int omax;
1892	bool firstone = true;
1893	int putflags = PXLF_HEADER;
1894	char **res;
1895	char obuf[MAXLINE + 3];
1896
1897	/*
1898	**  Output the address list translated by the
1899	**  mailer and with commas.
1900	*/
1901
1902	if (tTd(14, 2))
1903		sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1904
1905	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1906		putflags |= PXLF_STRIP8BIT;
1907
1908	obp = obuf;
1909	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
1910			h->h_field);
1911
1912	/* opos = strlen(obp); */
1913	opos = strlen(h->h_field) + 2;
1914	if (opos > 202)
1915		opos = 202;
1916	obp += opos;
1917	omax = mci->mci_mailer->m_linelimit - 2;
1918	if (omax < 0 || omax > 78)
1919		omax = 78;
1920
1921	/*
1922	**  Run through the list of values.
1923	*/
1924
1925	while (*p != '\0')
1926	{
1927		register char *name;
1928		register int c;
1929		char savechar;
1930		int flags;
1931		auto int status;
1932
1933		/*
1934		**  Find the end of the name.  New style names
1935		**  end with a comma, old style names end with
1936		**  a space character.  However, spaces do not
1937		**  necessarily delimit an old-style name -- at
1938		**  signs mean keep going.
1939		*/
1940
1941		/* find end of name */
1942		while ((isascii(*p) && isspace(*p)) || *p == ',')
1943			p++;
1944		name = p;
1945		res = NULL;
1946		for (;;)
1947		{
1948			auto char *oldp;
1949			char pvpbuf[PSBUFSIZE];
1950
1951			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1952				      sizeof pvpbuf, &oldp, NULL, false);
1953			p = oldp;
1954#if _FFR_IGNORE_BOGUS_ADDR
1955			/* ignore addresses that can't be parsed */
1956			if (res == NULL)
1957			{
1958				name = p;
1959				continue;
1960			}
1961#endif /* _FFR_IGNORE_BOGUS_ADDR */
1962
1963			/* look to see if we have an at sign */
1964			while (*p != '\0' && isascii(*p) && isspace(*p))
1965				p++;
1966
1967			if (*p != '@')
1968			{
1969				p = oldp;
1970				break;
1971			}
1972			++p;
1973			while (*p != '\0' && isascii(*p) && isspace(*p))
1974				p++;
1975		}
1976		/* at the end of one complete name */
1977
1978		/* strip off trailing white space */
1979		while (p >= name &&
1980		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1981			p--;
1982		if (++p == name)
1983			continue;
1984
1985		/*
1986		**  if prescan() failed go a bit backwards; this is a hack,
1987		**  there should be some better error recovery.
1988		*/
1989
1990		if (res == NULL && p > name &&
1991		    !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1992			--p;
1993		savechar = *p;
1994		*p = '\0';
1995
1996		/* translate the name to be relative */
1997		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1998		if (bitset(H_FROM, h->h_flags))
1999			flags |= RF_SENDERADDR;
2000#if USERDB
2001		else if (e->e_from.q_mailer != NULL &&
2002			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
2003		{
2004			char *q;
2005
2006			q = udbsender(name, e->e_rpool);
2007			if (q != NULL)
2008				name = q;
2009		}
2010#endif /* USERDB */
2011		status = EX_OK;
2012		name = remotename(name, mci->mci_mailer, flags, &status, e);
2013		if (*name == '\0')
2014		{
2015			*p = savechar;
2016			continue;
2017		}
2018		name = denlstring(name, false, true);
2019
2020		/* output the name with nice formatting */
2021		opos += strlen(name);
2022		if (!firstone)
2023			opos += 2;
2024		if (opos > omax && !firstone)
2025		{
2026			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2027			if (!putxline(obuf, strlen(obuf), mci, putflags))
2028				goto writeerr;
2029			obp = obuf;
2030			(void) sm_strlcpy(obp, "        ", sizeof obuf);
2031			opos = strlen(obp);
2032			obp += opos;
2033			opos += strlen(name);
2034		}
2035		else if (!firstone)
2036		{
2037			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2038			obp += 2;
2039		}
2040
2041		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2042			*obp++ = c;
2043		firstone = false;
2044		*p = savechar;
2045	}
2046	if (obp < &obuf[sizeof obuf])
2047		*obp = '\0';
2048	else
2049		obuf[sizeof obuf - 1] = '\0';
2050	return putxline(obuf, strlen(obuf), mci, putflags);
2051
2052  writeerr:
2053	return false;
2054}
2055
2056/*
2057**  COPYHEADER -- copy header list
2058**
2059**	This routine is the equivalent of newstr for header lists
2060**
2061**	Parameters:
2062**		header -- list of header structures to copy.
2063**		rpool -- resource pool, or NULL
2064**
2065**	Returns:
2066**		a copy of 'header'.
2067**
2068**	Side Effects:
2069**		none.
2070*/
2071
2072HDR *
2073copyheader(header, rpool)
2074	register HDR *header;
2075	SM_RPOOL_T *rpool;
2076{
2077	register HDR *newhdr;
2078	HDR *ret;
2079	register HDR **tail = &ret;
2080
2081	while (header != NULL)
2082	{
2083		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
2084		STRUCTCOPY(*header, *newhdr);
2085		*tail = newhdr;
2086		tail = &newhdr->h_link;
2087		header = header->h_link;
2088	}
2089	*tail = NULL;
2090
2091	return ret;
2092}
2093/*
2094**  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
2095**
2096**	Run through all of the parameters of a MIME header and
2097**	possibly truncate and rebalance the parameter according
2098**	to MaxMimeFieldLength.
2099**
2100**	Parameters:
2101**		h -- the header to truncate/rebalance
2102**		e -- the current envelope
2103**
2104**	Returns:
2105**		length of last offending field, 0 if all ok.
2106**
2107**	Side Effects:
2108**		string modified in place
2109*/
2110
2111static size_t
2112fix_mime_header(h, e)
2113	HDR *h;
2114	ENVELOPE *e;
2115{
2116	char *begin = h->h_value;
2117	char *end;
2118	size_t len = 0;
2119	size_t retlen = 0;
2120
2121	if (begin == NULL || *begin == '\0')
2122		return 0;
2123
2124	/* Split on each ';' */
2125	/* find_character() never returns NULL */
2126	while ((end = find_character(begin, ';')) != NULL)
2127	{
2128		char save = *end;
2129		char *bp;
2130
2131		*end = '\0';
2132
2133		len = strlen(begin);
2134
2135		/* Shorten individual parameter */
2136		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2137		{
2138			if (len < MaxMimeFieldLength)
2139			{
2140				/* we only rebalanced a bogus field */
2141				sm_syslog(LOG_ALERT, e->e_id,
2142					  "Fixed MIME %s header field (possible attack)",
2143					  h->h_field);
2144				if (tTd(34, 11))
2145					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
2146						   h->h_field);
2147			}
2148			else
2149			{
2150				/* we actually shortened the header */
2151				retlen = len;
2152			}
2153		}
2154
2155		/* Collapse the possibly shortened string with rest */
2156		bp = begin + strlen(begin);
2157		if (bp != end)
2158		{
2159			char *ep = end;
2160
2161			*end = save;
2162			end = bp;
2163
2164			/* copy character by character due to overlap */
2165			while (*ep != '\0')
2166				*bp++ = *ep++;
2167			*bp = '\0';
2168		}
2169		else
2170			*end = save;
2171		if (*end == '\0')
2172			break;
2173
2174		/* Move past ';' */
2175		begin = end + 1;
2176	}
2177	return retlen;
2178}
2179