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