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