xref: /illumos-gate/usr/src/cmd/sendmail/src/headers.c (revision 4aac33d31b41cc7e3ac6fb66747ff2cae63d08cf)
17c478bd9Sstevel@tonic-gate /*
2058561cbSjbeck  * Copyright (c) 1998-2004, 2006, 2007 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate  * the sendmail distribution.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate #include <sendmail.h>
17058561cbSjbeck #include <sm/sendmail.h>
187c478bd9Sstevel@tonic-gate 
19*4aac33d3Sjbeck SM_RCSID("@(#)$Id: headers.c,v 8.310 2007/02/07 22:44:35 ca Exp $")
207c478bd9Sstevel@tonic-gate 
21058561cbSjbeck static HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *, bool));
227c478bd9Sstevel@tonic-gate static size_t	fix_mime_header __P((HDR *, ENVELOPE *));
237c478bd9Sstevel@tonic-gate static int	priencode __P((char *));
24445f2479Sjbeck static bool	put_vanilla_header __P((HDR *, char *, MCI *));
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate **  SETUPHEADERS -- initialize headers in symbol table
287c478bd9Sstevel@tonic-gate **
297c478bd9Sstevel@tonic-gate **	Parameters:
307c478bd9Sstevel@tonic-gate **		none
317c478bd9Sstevel@tonic-gate **
327c478bd9Sstevel@tonic-gate **	Returns:
337c478bd9Sstevel@tonic-gate **		none
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate void
377c478bd9Sstevel@tonic-gate setupheaders()
387c478bd9Sstevel@tonic-gate {
397c478bd9Sstevel@tonic-gate 	struct hdrinfo *hi;
407c478bd9Sstevel@tonic-gate 	STAB *s;
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
437c478bd9Sstevel@tonic-gate 	{
447c478bd9Sstevel@tonic-gate 		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
457c478bd9Sstevel@tonic-gate 		s->s_header.hi_flags = hi->hi_flags;
467c478bd9Sstevel@tonic-gate 		s->s_header.hi_ruleset = NULL;
477c478bd9Sstevel@tonic-gate 	}
487c478bd9Sstevel@tonic-gate }
49058561cbSjbeck 
507c478bd9Sstevel@tonic-gate /*
51058561cbSjbeck **  DOCHOMPHEADER -- process and save a header line.
527c478bd9Sstevel@tonic-gate **
53058561cbSjbeck **	Called by chompheader.
547c478bd9Sstevel@tonic-gate **
557c478bd9Sstevel@tonic-gate **	Parameters:
567c478bd9Sstevel@tonic-gate **		line -- header as a text line.
577c478bd9Sstevel@tonic-gate **		pflag -- flags for chompheader() (from sendmail.h)
587c478bd9Sstevel@tonic-gate **		hdrp -- a pointer to the place to save the header.
597c478bd9Sstevel@tonic-gate **		e -- the envelope including this header.
607c478bd9Sstevel@tonic-gate **
617c478bd9Sstevel@tonic-gate **	Returns:
627c478bd9Sstevel@tonic-gate **		flags for this header.
637c478bd9Sstevel@tonic-gate **
647c478bd9Sstevel@tonic-gate **	Side Effects:
657c478bd9Sstevel@tonic-gate **		The header is saved on the header list.
667c478bd9Sstevel@tonic-gate **		Contents of 'line' are destroyed.
677c478bd9Sstevel@tonic-gate */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
70058561cbSjbeck static unsigned long	dochompheader __P((char *, int, HDR **, ENVELOPE *));
717c478bd9Sstevel@tonic-gate 
72058561cbSjbeck static unsigned long
73058561cbSjbeck dochompheader(line, pflag, hdrp, e)
747c478bd9Sstevel@tonic-gate 	char *line;
757c478bd9Sstevel@tonic-gate 	int pflag;
767c478bd9Sstevel@tonic-gate 	HDR **hdrp;
77058561cbSjbeck 	ENVELOPE *e;
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	unsigned char mid = '\0';
807c478bd9Sstevel@tonic-gate 	register char *p;
817c478bd9Sstevel@tonic-gate 	register HDR *h;
827c478bd9Sstevel@tonic-gate 	HDR **hp;
837c478bd9Sstevel@tonic-gate 	char *fname;
847c478bd9Sstevel@tonic-gate 	char *fvalue;
857c478bd9Sstevel@tonic-gate 	bool cond = false;
867c478bd9Sstevel@tonic-gate 	bool dropfrom;
877c478bd9Sstevel@tonic-gate 	bool headeronly;
887c478bd9Sstevel@tonic-gate 	STAB *s;
897c478bd9Sstevel@tonic-gate 	struct hdrinfo *hi;
907c478bd9Sstevel@tonic-gate 	bool nullheader = false;
917c478bd9Sstevel@tonic-gate 	BITMAP256 mopts;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	headeronly = hdrp != NULL;
947c478bd9Sstevel@tonic-gate 	if (!headeronly)
957c478bd9Sstevel@tonic-gate 		hdrp = &e->e_header;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	/* strip off options */
987c478bd9Sstevel@tonic-gate 	clrbitmap(mopts);
997c478bd9Sstevel@tonic-gate 	p = line;
1007c478bd9Sstevel@tonic-gate 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
1017c478bd9Sstevel@tonic-gate 	{
1027c478bd9Sstevel@tonic-gate 		int c;
1037c478bd9Sstevel@tonic-gate 		register char *q;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 		q = strchr(++p, '?');
1067c478bd9Sstevel@tonic-gate 		if (q == NULL)
1077c478bd9Sstevel@tonic-gate 			goto hse;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 		*q = '\0';
1107c478bd9Sstevel@tonic-gate 		c = *p & 0377;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 		/* possibly macro conditional */
1137c478bd9Sstevel@tonic-gate 		if (c == MACROEXPAND)
1147c478bd9Sstevel@tonic-gate 		{
1157c478bd9Sstevel@tonic-gate 			/* catch ?$? */
1167c478bd9Sstevel@tonic-gate 			if (*++p == '\0')
1177c478bd9Sstevel@tonic-gate 			{
1187c478bd9Sstevel@tonic-gate 				*q = '?';
1197c478bd9Sstevel@tonic-gate 				goto hse;
1207c478bd9Sstevel@tonic-gate 			}
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 			mid = (unsigned char) *p++;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 			/* catch ?$abc? */
1257c478bd9Sstevel@tonic-gate 			if (*p != '\0')
1267c478bd9Sstevel@tonic-gate 			{
1277c478bd9Sstevel@tonic-gate 				*q = '?';
1287c478bd9Sstevel@tonic-gate 				goto hse;
1297c478bd9Sstevel@tonic-gate 			}
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 		else if (*p == '$')
1327c478bd9Sstevel@tonic-gate 		{
1337c478bd9Sstevel@tonic-gate 			/* catch ?$? */
1347c478bd9Sstevel@tonic-gate 			if (*++p == '\0')
1357c478bd9Sstevel@tonic-gate 			{
1367c478bd9Sstevel@tonic-gate 				*q = '?';
1377c478bd9Sstevel@tonic-gate 				goto hse;
1387c478bd9Sstevel@tonic-gate 			}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 			mid = (unsigned char) macid(p);
1417c478bd9Sstevel@tonic-gate 			if (bitset(0200, mid))
1427c478bd9Sstevel@tonic-gate 			{
1437c478bd9Sstevel@tonic-gate 				p += strlen(macname(mid)) + 2;
1447c478bd9Sstevel@tonic-gate 				SM_ASSERT(p <= q);
1457c478bd9Sstevel@tonic-gate 			}
1467c478bd9Sstevel@tonic-gate 			else
1477c478bd9Sstevel@tonic-gate 				p++;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 			/* catch ?$abc? */
1507c478bd9Sstevel@tonic-gate 			if (*p != '\0')
1517c478bd9Sstevel@tonic-gate 			{
1527c478bd9Sstevel@tonic-gate 				*q = '?';
1537c478bd9Sstevel@tonic-gate 				goto hse;
1547c478bd9Sstevel@tonic-gate 			}
1557c478bd9Sstevel@tonic-gate 		}
1567c478bd9Sstevel@tonic-gate 		else
1577c478bd9Sstevel@tonic-gate 		{
1587c478bd9Sstevel@tonic-gate 			while (*p != '\0')
1597c478bd9Sstevel@tonic-gate 			{
1607c478bd9Sstevel@tonic-gate 				if (!isascii(*p))
1617c478bd9Sstevel@tonic-gate 				{
1627c478bd9Sstevel@tonic-gate 					*q = '?';
1637c478bd9Sstevel@tonic-gate 					goto hse;
1647c478bd9Sstevel@tonic-gate 				}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 				setbitn(bitidx(*p), mopts);
1677c478bd9Sstevel@tonic-gate 				cond = true;
1687c478bd9Sstevel@tonic-gate 				p++;
1697c478bd9Sstevel@tonic-gate 			}
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 		p = q + 1;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* find canonical name */
1757c478bd9Sstevel@tonic-gate 	fname = p;
1767c478bd9Sstevel@tonic-gate 	while (isascii(*p) && isgraph(*p) && *p != ':')
1777c478bd9Sstevel@tonic-gate 		p++;
1787c478bd9Sstevel@tonic-gate 	fvalue = p;
1797c478bd9Sstevel@tonic-gate 	while (isascii(*p) && isspace(*p))
1807c478bd9Sstevel@tonic-gate 		p++;
1817c478bd9Sstevel@tonic-gate 	if (*p++ != ':' || fname == fvalue)
1827c478bd9Sstevel@tonic-gate 	{
1837c478bd9Sstevel@tonic-gate hse:
1847c478bd9Sstevel@tonic-gate 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
1857c478bd9Sstevel@tonic-gate 		return 0;
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 	*fvalue = '\0';
1887c478bd9Sstevel@tonic-gate 	fvalue = p;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	/* if the field is null, go ahead and use the default */
1917c478bd9Sstevel@tonic-gate 	while (isascii(*p) && isspace(*p))
1927c478bd9Sstevel@tonic-gate 		p++;
1937c478bd9Sstevel@tonic-gate 	if (*p == '\0')
1947c478bd9Sstevel@tonic-gate 		nullheader = true;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/* security scan: long field names are end-of-header */
1977c478bd9Sstevel@tonic-gate 	if (strlen(fname) > 100)
1987c478bd9Sstevel@tonic-gate 		return H_EOH;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/* check to see if it represents a ruleset call */
2017c478bd9Sstevel@tonic-gate 	if (bitset(pflag, CHHDR_DEF))
2027c478bd9Sstevel@tonic-gate 	{
2037c478bd9Sstevel@tonic-gate 		char hbuf[50];
2047c478bd9Sstevel@tonic-gate 
205058561cbSjbeck 		(void) expand(fvalue, hbuf, sizeof(hbuf), e);
2067c478bd9Sstevel@tonic-gate 		for (p = hbuf; isascii(*p) && isspace(*p); )
2077c478bd9Sstevel@tonic-gate 			p++;
2087c478bd9Sstevel@tonic-gate 		if ((*p++ & 0377) == CALLSUBR)
2097c478bd9Sstevel@tonic-gate 		{
2107c478bd9Sstevel@tonic-gate 			auto char *endp;
2117c478bd9Sstevel@tonic-gate 			bool strc;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 			strc = *p == '+';	/* strip comments? */
2147c478bd9Sstevel@tonic-gate 			if (strc)
2157c478bd9Sstevel@tonic-gate 				++p;
2167c478bd9Sstevel@tonic-gate 			if (strtorwset(p, &endp, ST_ENTER) > 0)
2177c478bd9Sstevel@tonic-gate 			{
2187c478bd9Sstevel@tonic-gate 				*endp = '\0';
2197c478bd9Sstevel@tonic-gate 				s = stab(fname, ST_HEADER, ST_ENTER);
2207c478bd9Sstevel@tonic-gate 				if (LogLevel > 9 &&
2217c478bd9Sstevel@tonic-gate 				    s->s_header.hi_ruleset != NULL)
2227c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_WARNING, NOQID,
2237c478bd9Sstevel@tonic-gate 						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
2247c478bd9Sstevel@tonic-gate 						  fname,
2257c478bd9Sstevel@tonic-gate 						  s->s_header.hi_ruleset, p);
2267c478bd9Sstevel@tonic-gate 				s->s_header.hi_ruleset = newstr(p);
2277c478bd9Sstevel@tonic-gate 				if (!strc)
2287c478bd9Sstevel@tonic-gate 					s->s_header.hi_flags |= H_STRIPCOMM;
2297c478bd9Sstevel@tonic-gate 			}
2307c478bd9Sstevel@tonic-gate 			return 0;
2317c478bd9Sstevel@tonic-gate 		}
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/* see if it is a known type */
2357c478bd9Sstevel@tonic-gate 	s = stab(fname, ST_HEADER, ST_FIND);
2367c478bd9Sstevel@tonic-gate 	if (s != NULL)
2377c478bd9Sstevel@tonic-gate 		hi = &s->s_header;
2387c478bd9Sstevel@tonic-gate 	else
2397c478bd9Sstevel@tonic-gate 		hi = &NormalHeader;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if (tTd(31, 9))
2427c478bd9Sstevel@tonic-gate 	{
2437c478bd9Sstevel@tonic-gate 		if (s == NULL)
2447c478bd9Sstevel@tonic-gate 			sm_dprintf("no header flags match\n");
2457c478bd9Sstevel@tonic-gate 		else
2467c478bd9Sstevel@tonic-gate 			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
2477c478bd9Sstevel@tonic-gate 				   hi->hi_flags,
2487c478bd9Sstevel@tonic-gate 				   hi->hi_ruleset == NULL ? "<NULL>"
2497c478bd9Sstevel@tonic-gate 							  : hi->hi_ruleset);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/* see if this is a resent message */
2537c478bd9Sstevel@tonic-gate 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2547c478bd9Sstevel@tonic-gate 	    bitset(H_RESENT, hi->hi_flags))
2557c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_RESENT;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/* if this is an Errors-To: header keep track of it now */
2587c478bd9Sstevel@tonic-gate 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
2597c478bd9Sstevel@tonic-gate 	    bitset(H_ERRORSTO, hi->hi_flags))
2607c478bd9Sstevel@tonic-gate 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/* if this means "end of header" quit now */
2637c478bd9Sstevel@tonic-gate 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
2647c478bd9Sstevel@tonic-gate 		return hi->hi_flags;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/*
2677c478bd9Sstevel@tonic-gate 	**  Horrible hack to work around problem with Lotus Notes SMTP
2687c478bd9Sstevel@tonic-gate 	**  mail gateway, which generates From: headers with newlines in
2697c478bd9Sstevel@tonic-gate 	**  them and the <address> on the second line.  Although this is
2707c478bd9Sstevel@tonic-gate 	**  legal RFC 822, many MUAs don't handle this properly and thus
2717c478bd9Sstevel@tonic-gate 	**  never find the actual address.
2727c478bd9Sstevel@tonic-gate 	*/
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
2757c478bd9Sstevel@tonic-gate 	{
2767c478bd9Sstevel@tonic-gate 		while ((p = strchr(fvalue, '\n')) != NULL)
2777c478bd9Sstevel@tonic-gate 			*p = ' ';
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	**  If there is a check ruleset, verify it against the header.
2827c478bd9Sstevel@tonic-gate 	*/
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (bitset(pflag, CHHDR_CHECK))
2857c478bd9Sstevel@tonic-gate 	{
2867c478bd9Sstevel@tonic-gate 		int rscheckflags;
2877c478bd9Sstevel@tonic-gate 		char *rs;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		rscheckflags = RSF_COUNT;
2907c478bd9Sstevel@tonic-gate 		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2917c478bd9Sstevel@tonic-gate 			rscheckflags |= RSF_UNSTRUCTURED;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		/* no ruleset? look for default */
2947c478bd9Sstevel@tonic-gate 		rs = hi->hi_ruleset;
2957c478bd9Sstevel@tonic-gate 		if (rs == NULL)
2967c478bd9Sstevel@tonic-gate 		{
2977c478bd9Sstevel@tonic-gate 			s = stab("*", ST_HEADER, ST_FIND);
2987c478bd9Sstevel@tonic-gate 			if (s != NULL)
2997c478bd9Sstevel@tonic-gate 			{
3007c478bd9Sstevel@tonic-gate 				rs = (&s->s_header)->hi_ruleset;
3017c478bd9Sstevel@tonic-gate 				if (bitset((&s->s_header)->hi_flags,
3027c478bd9Sstevel@tonic-gate 					   H_STRIPCOMM))
3037c478bd9Sstevel@tonic-gate 					rscheckflags |= RSF_RMCOMM;
3047c478bd9Sstevel@tonic-gate 			}
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 		else if (bitset(hi->hi_flags, H_STRIPCOMM))
3077c478bd9Sstevel@tonic-gate 			rscheckflags |= RSF_RMCOMM;
3087c478bd9Sstevel@tonic-gate 		if (rs != NULL)
3097c478bd9Sstevel@tonic-gate 		{
3107c478bd9Sstevel@tonic-gate 			int l, k;
3117c478bd9Sstevel@tonic-gate 			char qval[MAXNAME];
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 			l = 0;
3147c478bd9Sstevel@tonic-gate 			qval[l++] = '"';
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 			/* - 3 to avoid problems with " at the end */
3177c478bd9Sstevel@tonic-gate 			/* should be sizeof(qval), not MAXNAME */
3187c478bd9Sstevel@tonic-gate 			for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
3197c478bd9Sstevel@tonic-gate 			{
3207c478bd9Sstevel@tonic-gate 				switch (fvalue[k])
3217c478bd9Sstevel@tonic-gate 				{
3227c478bd9Sstevel@tonic-gate 				  /* XXX other control chars? */
3237c478bd9Sstevel@tonic-gate 				  case '\011': /* ht */
3247c478bd9Sstevel@tonic-gate 				  case '\012': /* nl */
3257c478bd9Sstevel@tonic-gate 				  case '\013': /* vt */
3267c478bd9Sstevel@tonic-gate 				  case '\014': /* np */
3277c478bd9Sstevel@tonic-gate 				  case '\015': /* cr */
3287c478bd9Sstevel@tonic-gate 					qval[l++] = ' ';
3297c478bd9Sstevel@tonic-gate 					break;
3307c478bd9Sstevel@tonic-gate 				  case '"':
3317c478bd9Sstevel@tonic-gate 					qval[l++] = '\\';
3327c478bd9Sstevel@tonic-gate 					/* FALLTHROUGH */
3337c478bd9Sstevel@tonic-gate 				  default:
3347c478bd9Sstevel@tonic-gate 					qval[l++] = fvalue[k];
3357c478bd9Sstevel@tonic-gate 					break;
3367c478bd9Sstevel@tonic-gate 				}
3377c478bd9Sstevel@tonic-gate 			}
3387c478bd9Sstevel@tonic-gate 			qval[l++] = '"';
3397c478bd9Sstevel@tonic-gate 			qval[l] = '\0';
3407c478bd9Sstevel@tonic-gate 			k += strlen(fvalue + k);
3417c478bd9Sstevel@tonic-gate 			if (k >= MAXNAME)
3427c478bd9Sstevel@tonic-gate 			{
3437c478bd9Sstevel@tonic-gate 				if (LogLevel > 9)
3447c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_WARNING, e->e_id,
3457c478bd9Sstevel@tonic-gate 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
3467c478bd9Sstevel@tonic-gate 						  fname, rs, k, MAXNAME - 1);
3477c478bd9Sstevel@tonic-gate 			}
3487c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_TEMP,
3497c478bd9Sstevel@tonic-gate 				macid("{currHeader}"), qval);
3507c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_TEMP,
3517c478bd9Sstevel@tonic-gate 				macid("{hdr_name}"), fname);
3527c478bd9Sstevel@tonic-gate 
353058561cbSjbeck 			(void) sm_snprintf(qval, sizeof(qval), "%d", k);
3547c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
3557c478bd9Sstevel@tonic-gate 			if (bitset(H_FROM, hi->hi_flags))
3567c478bd9Sstevel@tonic-gate 				macdefine(&e->e_macro, A_PERM,
3577c478bd9Sstevel@tonic-gate 					macid("{addr_type}"), "h s");
3587c478bd9Sstevel@tonic-gate 			else if (bitset(H_RCPT, hi->hi_flags))
3597c478bd9Sstevel@tonic-gate 				macdefine(&e->e_macro, A_PERM,
3607c478bd9Sstevel@tonic-gate 					macid("{addr_type}"), "h r");
3617c478bd9Sstevel@tonic-gate 			else
3627c478bd9Sstevel@tonic-gate 				macdefine(&e->e_macro, A_PERM,
3637c478bd9Sstevel@tonic-gate 					macid("{addr_type}"), "h");
3647c478bd9Sstevel@tonic-gate 			(void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
365058561cbSjbeck 				       NULL, e->e_id, NULL);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/*
3707c478bd9Sstevel@tonic-gate 	**  Drop explicit From: if same as what we would generate.
3717c478bd9Sstevel@tonic-gate 	**  This is to make MH (which doesn't always give a full name)
3727c478bd9Sstevel@tonic-gate 	**  insert the full name information in all circumstances.
3737c478bd9Sstevel@tonic-gate 	*/
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	dropfrom = false;
3767c478bd9Sstevel@tonic-gate 	p = "resent-from";
3777c478bd9Sstevel@tonic-gate 	if (!bitset(EF_RESENT, e->e_flags))
3787c478bd9Sstevel@tonic-gate 		p += 7;
3797c478bd9Sstevel@tonic-gate 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
3807c478bd9Sstevel@tonic-gate 	    !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
3817c478bd9Sstevel@tonic-gate 	{
3827c478bd9Sstevel@tonic-gate 		if (tTd(31, 2))
3837c478bd9Sstevel@tonic-gate 		{
3847c478bd9Sstevel@tonic-gate 			sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
3857c478bd9Sstevel@tonic-gate 				fvalue, e->e_from.q_paddr, e->e_from.q_user);
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 		if (e->e_from.q_paddr != NULL &&
3887c478bd9Sstevel@tonic-gate 		    e->e_from.q_mailer != NULL &&
3897c478bd9Sstevel@tonic-gate 		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
3907c478bd9Sstevel@tonic-gate 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
3917c478bd9Sstevel@tonic-gate 		     strcmp(fvalue, e->e_from.q_user) == 0))
3927c478bd9Sstevel@tonic-gate 			dropfrom = true;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* delete default value for this header */
3967c478bd9Sstevel@tonic-gate 	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
3977c478bd9Sstevel@tonic-gate 	{
3987c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(fname, h->h_field) == 0 &&
3997c478bd9Sstevel@tonic-gate 		    !bitset(H_USER, h->h_flags) &&
4007c478bd9Sstevel@tonic-gate 		    !bitset(H_FORCE, h->h_flags))
4017c478bd9Sstevel@tonic-gate 		{
4027c478bd9Sstevel@tonic-gate 			if (nullheader)
4037c478bd9Sstevel@tonic-gate 			{
4047c478bd9Sstevel@tonic-gate 				/* user-supplied value was null */
4057c478bd9Sstevel@tonic-gate 				return 0;
4067c478bd9Sstevel@tonic-gate 			}
4077c478bd9Sstevel@tonic-gate 			if (dropfrom)
4087c478bd9Sstevel@tonic-gate 			{
4097c478bd9Sstevel@tonic-gate 				/* make this look like the user entered it */
4107c478bd9Sstevel@tonic-gate 				h->h_flags |= H_USER;
4117c478bd9Sstevel@tonic-gate 				return hi->hi_flags;
4127c478bd9Sstevel@tonic-gate 			}
4137c478bd9Sstevel@tonic-gate 			h->h_value = NULL;
4147c478bd9Sstevel@tonic-gate 			if (!cond)
4157c478bd9Sstevel@tonic-gate 			{
4167c478bd9Sstevel@tonic-gate 				/* copy conditions from default case */
4177c478bd9Sstevel@tonic-gate 				memmove((char *) mopts, (char *) h->h_mflags,
418058561cbSjbeck 					sizeof(mopts));
4197c478bd9Sstevel@tonic-gate 			}
4207c478bd9Sstevel@tonic-gate 			h->h_macro = mid;
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	/* create a new node */
425058561cbSjbeck 	h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h));
4267c478bd9Sstevel@tonic-gate 	h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
4277c478bd9Sstevel@tonic-gate 	h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
4287c478bd9Sstevel@tonic-gate 	h->h_link = NULL;
429058561cbSjbeck 	memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
4307c478bd9Sstevel@tonic-gate 	h->h_macro = mid;
4317c478bd9Sstevel@tonic-gate 	*hp = h;
4327c478bd9Sstevel@tonic-gate 	h->h_flags = hi->hi_flags;
4337c478bd9Sstevel@tonic-gate 	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4347c478bd9Sstevel@tonic-gate 		h->h_flags |= H_USER;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/* strip EOH flag if parsing MIME headers */
4377c478bd9Sstevel@tonic-gate 	if (headeronly)
4387c478bd9Sstevel@tonic-gate 		h->h_flags &= ~H_EOH;
4397c478bd9Sstevel@tonic-gate 	if (bitset(pflag, CHHDR_DEF))
4407c478bd9Sstevel@tonic-gate 		h->h_flags |= H_DEFAULT;
4417c478bd9Sstevel@tonic-gate 	if (cond || mid != '\0')
4427c478bd9Sstevel@tonic-gate 		h->h_flags |= H_CHECK;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/* hack to see if this is a new format message */
4457c478bd9Sstevel@tonic-gate 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4467c478bd9Sstevel@tonic-gate 	    bitset(H_RCPT|H_FROM, h->h_flags) &&
4477c478bd9Sstevel@tonic-gate 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
4487c478bd9Sstevel@tonic-gate 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
4497c478bd9Sstevel@tonic-gate 	{
4507c478bd9Sstevel@tonic-gate 		e->e_flags &= ~EF_OLDSTYLE;
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	return h->h_flags;
4547c478bd9Sstevel@tonic-gate }
455058561cbSjbeck 
456058561cbSjbeck /*
457058561cbSjbeck **  CHOMPHEADER -- process and save a header line.
458058561cbSjbeck **
459058561cbSjbeck **	Called by collect, readcf, and readqf to deal with header lines.
460058561cbSjbeck **	This is just a wrapper for dochompheader().
461058561cbSjbeck **
462058561cbSjbeck **	Parameters:
463058561cbSjbeck **		line -- header as a text line.
464058561cbSjbeck **		pflag -- flags for chompheader() (from sendmail.h)
465058561cbSjbeck **		hdrp -- a pointer to the place to save the header.
466058561cbSjbeck **		e -- the envelope including this header.
467058561cbSjbeck **
468058561cbSjbeck **	Returns:
469058561cbSjbeck **		flags for this header.
470058561cbSjbeck **
471058561cbSjbeck **	Side Effects:
472058561cbSjbeck **		The header is saved on the header list.
473058561cbSjbeck **		Contents of 'line' are destroyed.
474058561cbSjbeck */
475058561cbSjbeck 
476058561cbSjbeck 
477058561cbSjbeck unsigned long
478058561cbSjbeck chompheader(line, pflag, hdrp, e)
479058561cbSjbeck 	char *line;
480058561cbSjbeck 	int pflag;
481058561cbSjbeck 	HDR **hdrp;
482058561cbSjbeck 	register ENVELOPE *e;
483058561cbSjbeck {
484058561cbSjbeck 	unsigned long rval;
485058561cbSjbeck 
486058561cbSjbeck 	if (tTd(31, 6))
487058561cbSjbeck 	{
488058561cbSjbeck 		sm_dprintf("chompheader: ");
489058561cbSjbeck 		xputs(sm_debug_file(), line);
490058561cbSjbeck 		sm_dprintf("\n");
491058561cbSjbeck 	}
492058561cbSjbeck 
493058561cbSjbeck 	/* quote this if user (not config file) input */
494058561cbSjbeck 	if (bitset(pflag, CHHDR_USER))
495058561cbSjbeck 	{
496058561cbSjbeck 		char xbuf[MAXLINE];
497058561cbSjbeck 		char *xbp = NULL;
498058561cbSjbeck 		int xbufs;
499058561cbSjbeck 
500058561cbSjbeck 		xbufs = sizeof(xbuf);
501058561cbSjbeck 		xbp = quote_internal_chars(line, xbuf, &xbufs);
502058561cbSjbeck 		if (tTd(31, 7))
503058561cbSjbeck 		{
504058561cbSjbeck 			sm_dprintf("chompheader: quoted: ");
505058561cbSjbeck 			xputs(sm_debug_file(), xbp);
506058561cbSjbeck 			sm_dprintf("\n");
507058561cbSjbeck 		}
508058561cbSjbeck 		rval = dochompheader(xbp, pflag, hdrp, e);
509058561cbSjbeck 		if (xbp != xbuf)
510058561cbSjbeck 			sm_free(xbp);
511058561cbSjbeck 	}
512058561cbSjbeck 	else
513058561cbSjbeck 		rval = dochompheader(line, pflag, hdrp, e);
514058561cbSjbeck 
515058561cbSjbeck 	return rval;
516058561cbSjbeck }
517058561cbSjbeck 
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate **  ALLOCHEADER -- allocate a header entry
5207c478bd9Sstevel@tonic-gate **
5217c478bd9Sstevel@tonic-gate **	Parameters:
522058561cbSjbeck **		field -- the name of the header field (will not be copied).
523058561cbSjbeck **		value -- the value of the field (will be copied).
5247c478bd9Sstevel@tonic-gate **		flags -- flags to add to h_flags.
5257c478bd9Sstevel@tonic-gate **		rp -- resource pool for allocations
526058561cbSjbeck **		space -- add leading space?
5277c478bd9Sstevel@tonic-gate **
5287c478bd9Sstevel@tonic-gate **	Returns:
5297c478bd9Sstevel@tonic-gate **		Pointer to a newly allocated and populated HDR.
530058561cbSjbeck **
531058561cbSjbeck **	Notes:
532058561cbSjbeck **		o field and value must be in internal format, i.e.,
533058561cbSjbeck **		metacharacters must be "quoted", see quote_internal_chars().
534058561cbSjbeck **		o maybe add more flags to decide:
535058561cbSjbeck **		  - what to copy (field/value)
536058561cbSjbeck **		  - whether to convert value to an internal format
5377c478bd9Sstevel@tonic-gate */
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate static HDR *
540058561cbSjbeck allocheader(field, value, flags, rp, space)
5417c478bd9Sstevel@tonic-gate 	char *field;
5427c478bd9Sstevel@tonic-gate 	char *value;
5437c478bd9Sstevel@tonic-gate 	int flags;
5447c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rp;
545058561cbSjbeck 	bool space;
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	HDR *h;
5487c478bd9Sstevel@tonic-gate 	STAB *s;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	/* find info struct */
5517c478bd9Sstevel@tonic-gate 	s = stab(field, ST_HEADER, ST_FIND);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/* allocate space for new header */
554058561cbSjbeck 	h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
5557c478bd9Sstevel@tonic-gate 	h->h_field = field;
556058561cbSjbeck 	if (space)
557058561cbSjbeck 	{
558058561cbSjbeck 		size_t l;
559058561cbSjbeck 		char *n;
560058561cbSjbeck 
561058561cbSjbeck 		l = strlen(value);
562058561cbSjbeck 		SM_ASSERT(l + 2 > l);
563058561cbSjbeck 		n = sm_rpool_malloc_x(rp, l + 2);
564058561cbSjbeck 		n[0] = ' ';
565058561cbSjbeck 		n[1] = '\0';
566058561cbSjbeck 		sm_strlcpy(n + 1, value, l + 1);
567058561cbSjbeck 		h->h_value = n;
568058561cbSjbeck 	}
569058561cbSjbeck 	else
5707c478bd9Sstevel@tonic-gate 		h->h_value = sm_rpool_strdup_x(rp, value);
5717c478bd9Sstevel@tonic-gate 	h->h_flags = flags;
5727c478bd9Sstevel@tonic-gate 	if (s != NULL)
5737c478bd9Sstevel@tonic-gate 		h->h_flags |= s->s_header.hi_flags;
5747c478bd9Sstevel@tonic-gate 	clrbitmap(h->h_mflags);
5757c478bd9Sstevel@tonic-gate 	h->h_macro = '\0';
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	return h;
5787c478bd9Sstevel@tonic-gate }
579058561cbSjbeck 
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate **  ADDHEADER -- add a header entry to the end of the queue.
5827c478bd9Sstevel@tonic-gate **
5837c478bd9Sstevel@tonic-gate **	This bypasses the special checking of chompheader.
5847c478bd9Sstevel@tonic-gate **
5857c478bd9Sstevel@tonic-gate **	Parameters:
586058561cbSjbeck **		field -- the name of the header field (will not be copied).
587058561cbSjbeck **		value -- the value of the field (will be copied).
5887c478bd9Sstevel@tonic-gate **		flags -- flags to add to h_flags.
5897c478bd9Sstevel@tonic-gate **		e -- envelope.
590058561cbSjbeck **		space -- add leading space?
5917c478bd9Sstevel@tonic-gate **
5927c478bd9Sstevel@tonic-gate **	Returns:
5937c478bd9Sstevel@tonic-gate **		none.
5947c478bd9Sstevel@tonic-gate **
5957c478bd9Sstevel@tonic-gate **	Side Effects:
5967c478bd9Sstevel@tonic-gate **		adds the field on the list of headers for this envelope.
597058561cbSjbeck **
598058561cbSjbeck **	Notes: field and value must be in internal format, i.e.,
599058561cbSjbeck **		metacharacters must be "quoted", see quote_internal_chars().
6007c478bd9Sstevel@tonic-gate */
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate void
603058561cbSjbeck addheader(field, value, flags, e, space)
6047c478bd9Sstevel@tonic-gate 	char *field;
6057c478bd9Sstevel@tonic-gate 	char *value;
6067c478bd9Sstevel@tonic-gate 	int flags;
6077c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
608058561cbSjbeck 	bool space;
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	register HDR *h;
6117c478bd9Sstevel@tonic-gate 	HDR **hp;
6127c478bd9Sstevel@tonic-gate 	HDR **hdrlist = &e->e_header;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	/* find current place in list -- keep back pointer? */
6157c478bd9Sstevel@tonic-gate 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
6167c478bd9Sstevel@tonic-gate 	{
6177c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(field, h->h_field) == 0)
6187c478bd9Sstevel@tonic-gate 			break;
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/* allocate space for new header */
622058561cbSjbeck 	h = allocheader(field, value, flags, e->e_rpool, space);
6237c478bd9Sstevel@tonic-gate 	h->h_link = *hp;
6247c478bd9Sstevel@tonic-gate 	*hp = h;
6257c478bd9Sstevel@tonic-gate }
626058561cbSjbeck 
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate **  INSHEADER -- insert a header entry at the specified index
6297c478bd9Sstevel@tonic-gate **	This bypasses the special checking of chompheader.
6307c478bd9Sstevel@tonic-gate **
6317c478bd9Sstevel@tonic-gate **	Parameters:
6327c478bd9Sstevel@tonic-gate **		idx -- index into the header list at which to insert
633058561cbSjbeck **		field -- the name of the header field (will be copied).
634058561cbSjbeck **		value -- the value of the field (will be copied).
6357c478bd9Sstevel@tonic-gate **		flags -- flags to add to h_flags.
6367c478bd9Sstevel@tonic-gate **		e -- envelope.
637058561cbSjbeck **		space -- add leading space?
6387c478bd9Sstevel@tonic-gate **
6397c478bd9Sstevel@tonic-gate **	Returns:
6407c478bd9Sstevel@tonic-gate **		none.
6417c478bd9Sstevel@tonic-gate **
6427c478bd9Sstevel@tonic-gate **	Side Effects:
6437c478bd9Sstevel@tonic-gate **		inserts the field on the list of headers for this envelope.
644058561cbSjbeck **
645058561cbSjbeck **	Notes:
646058561cbSjbeck **		- field and value must be in internal format, i.e.,
647058561cbSjbeck **		metacharacters must be "quoted", see quote_internal_chars().
648058561cbSjbeck **		- the header list contains headers that might not be
649058561cbSjbeck **		sent "out" (see putheader(): "skip"), hence there is no
650058561cbSjbeck **		reliable way to insert a header at an exact position
651058561cbSjbeck **		(except at the front or end).
6527c478bd9Sstevel@tonic-gate */
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate void
655058561cbSjbeck insheader(idx, field, value, flags, e, space)
6567c478bd9Sstevel@tonic-gate 	int idx;
6577c478bd9Sstevel@tonic-gate 	char *field;
6587c478bd9Sstevel@tonic-gate 	char *value;
6597c478bd9Sstevel@tonic-gate 	int flags;
6607c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
661058561cbSjbeck 	bool space;
6627c478bd9Sstevel@tonic-gate {
6637c478bd9Sstevel@tonic-gate 	HDR *h, *srch, *last = NULL;
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/* allocate space for new header */
666058561cbSjbeck 	h = allocheader(field, value, flags, e->e_rpool, space);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/* find insertion position */
6697c478bd9Sstevel@tonic-gate 	for (srch = e->e_header; srch != NULL && idx > 0;
6707c478bd9Sstevel@tonic-gate 	     srch = srch->h_link, idx--)
6717c478bd9Sstevel@tonic-gate 		last = srch;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	if (e->e_header == NULL)
6747c478bd9Sstevel@tonic-gate 	{
6757c478bd9Sstevel@tonic-gate 		e->e_header = h;
6767c478bd9Sstevel@tonic-gate 		h->h_link = NULL;
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 	else if (srch == NULL)
6797c478bd9Sstevel@tonic-gate 	{
6807c478bd9Sstevel@tonic-gate 		SM_ASSERT(last != NULL);
6817c478bd9Sstevel@tonic-gate 		last->h_link = h;
6827c478bd9Sstevel@tonic-gate 		h->h_link = NULL;
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 	else
6857c478bd9Sstevel@tonic-gate 	{
6867c478bd9Sstevel@tonic-gate 		h->h_link = srch->h_link;
6877c478bd9Sstevel@tonic-gate 		srch->h_link = h;
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate }
690058561cbSjbeck 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate **  HVALUE -- return value of a header.
6937c478bd9Sstevel@tonic-gate **
6947c478bd9Sstevel@tonic-gate **	Only "real" fields (i.e., ones that have not been supplied
6957c478bd9Sstevel@tonic-gate **	as a default) are used.
6967c478bd9Sstevel@tonic-gate **
6977c478bd9Sstevel@tonic-gate **	Parameters:
6987c478bd9Sstevel@tonic-gate **		field -- the field name.
6997c478bd9Sstevel@tonic-gate **		header -- the header list.
7007c478bd9Sstevel@tonic-gate **
7017c478bd9Sstevel@tonic-gate **	Returns:
702058561cbSjbeck **		pointer to the value part (internal format).
7037c478bd9Sstevel@tonic-gate **		NULL if not found.
7047c478bd9Sstevel@tonic-gate **
7057c478bd9Sstevel@tonic-gate **	Side Effects:
7067c478bd9Sstevel@tonic-gate **		none.
7077c478bd9Sstevel@tonic-gate */
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate char *
7107c478bd9Sstevel@tonic-gate hvalue(field, header)
7117c478bd9Sstevel@tonic-gate 	char *field;
7127c478bd9Sstevel@tonic-gate 	HDR *header;
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	register HDR *h;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	for (h = header; h != NULL; h = h->h_link)
7177c478bd9Sstevel@tonic-gate 	{
7187c478bd9Sstevel@tonic-gate 		if (!bitset(H_DEFAULT, h->h_flags) &&
7197c478bd9Sstevel@tonic-gate 		    sm_strcasecmp(h->h_field, field) == 0)
7207c478bd9Sstevel@tonic-gate 			return h->h_value;
7217c478bd9Sstevel@tonic-gate 	}
7227c478bd9Sstevel@tonic-gate 	return NULL;
7237c478bd9Sstevel@tonic-gate }
724058561cbSjbeck 
7257c478bd9Sstevel@tonic-gate /*
7267c478bd9Sstevel@tonic-gate **  ISHEADER -- predicate telling if argument is a header.
7277c478bd9Sstevel@tonic-gate **
7287c478bd9Sstevel@tonic-gate **	A line is a header if it has a single word followed by
7297c478bd9Sstevel@tonic-gate **	optional white space followed by a colon.
7307c478bd9Sstevel@tonic-gate **
7317c478bd9Sstevel@tonic-gate **	Header fields beginning with two dashes, although technically
7327c478bd9Sstevel@tonic-gate **	permitted by RFC822, are automatically rejected in order
7337c478bd9Sstevel@tonic-gate **	to make MIME work out.  Without this we could have a technically
7347c478bd9Sstevel@tonic-gate **	legal header such as ``--"foo:bar"'' that would also be a legal
7357c478bd9Sstevel@tonic-gate **	MIME separator.
7367c478bd9Sstevel@tonic-gate **
7377c478bd9Sstevel@tonic-gate **	Parameters:
7387c478bd9Sstevel@tonic-gate **		h -- string to check for possible headerness.
7397c478bd9Sstevel@tonic-gate **
7407c478bd9Sstevel@tonic-gate **	Returns:
7417c478bd9Sstevel@tonic-gate **		true if h is a header.
7427c478bd9Sstevel@tonic-gate **		false otherwise.
7437c478bd9Sstevel@tonic-gate **
7447c478bd9Sstevel@tonic-gate **	Side Effects:
7457c478bd9Sstevel@tonic-gate **		none.
7467c478bd9Sstevel@tonic-gate */
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate bool
7497c478bd9Sstevel@tonic-gate isheader(h)
7507c478bd9Sstevel@tonic-gate 	char *h;
7517c478bd9Sstevel@tonic-gate {
752058561cbSjbeck 	char *s;
7537c478bd9Sstevel@tonic-gate 
754058561cbSjbeck 	s = h;
7557c478bd9Sstevel@tonic-gate 	if (s[0] == '-' && s[1] == '-')
7567c478bd9Sstevel@tonic-gate 		return false;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	while (*s > ' ' && *s != ':' && *s != '\0')
7597c478bd9Sstevel@tonic-gate 		s++;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	if (h == s)
7627c478bd9Sstevel@tonic-gate 		return false;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/* following technically violates RFC822 */
7657c478bd9Sstevel@tonic-gate 	while (isascii(*s) && isspace(*s))
7667c478bd9Sstevel@tonic-gate 		s++;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	return (*s == ':');
7697c478bd9Sstevel@tonic-gate }
770058561cbSjbeck 
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate **  EATHEADER -- run through the stored header and extract info.
7737c478bd9Sstevel@tonic-gate **
7747c478bd9Sstevel@tonic-gate **	Parameters:
7757c478bd9Sstevel@tonic-gate **		e -- the envelope to process.
7767c478bd9Sstevel@tonic-gate **		full -- if set, do full processing (e.g., compute
7777c478bd9Sstevel@tonic-gate **			message priority).  This should not be set
7787c478bd9Sstevel@tonic-gate **			when reading a queue file because some info
7797c478bd9Sstevel@tonic-gate **			needed to compute the priority is wrong.
7807c478bd9Sstevel@tonic-gate **		log -- call logsender()?
7817c478bd9Sstevel@tonic-gate **
7827c478bd9Sstevel@tonic-gate **	Returns:
7837c478bd9Sstevel@tonic-gate **		none.
7847c478bd9Sstevel@tonic-gate **
7857c478bd9Sstevel@tonic-gate **	Side Effects:
7867c478bd9Sstevel@tonic-gate **		Sets a bunch of global variables from information
7877c478bd9Sstevel@tonic-gate **			in the collected header.
7887c478bd9Sstevel@tonic-gate */
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate void
7917c478bd9Sstevel@tonic-gate eatheader(e, full, log)
7927c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
7937c478bd9Sstevel@tonic-gate 	bool full;
7947c478bd9Sstevel@tonic-gate 	bool log;
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	register HDR *h;
7977c478bd9Sstevel@tonic-gate 	register char *p;
7987c478bd9Sstevel@tonic-gate 	int hopcnt = 0;
7997c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/*
8027c478bd9Sstevel@tonic-gate 	**  Set up macros for possible expansion in headers.
8037c478bd9Sstevel@tonic-gate 	*/
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
8067c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
8077c478bd9Sstevel@tonic-gate 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
8087c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
8097c478bd9Sstevel@tonic-gate 	else
8107c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, 'u', NULL);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/* full name of from person */
8137c478bd9Sstevel@tonic-gate 	p = hvalue("full-name", e->e_header);
8147c478bd9Sstevel@tonic-gate 	if (p != NULL)
8157c478bd9Sstevel@tonic-gate 	{
8167c478bd9Sstevel@tonic-gate 		if (!rfc822_string(p))
8177c478bd9Sstevel@tonic-gate 		{
8187c478bd9Sstevel@tonic-gate 			/*
8197c478bd9Sstevel@tonic-gate 			**  Quote a full name with special characters
8207c478bd9Sstevel@tonic-gate 			**  as a comment so crackaddr() doesn't destroy
8217c478bd9Sstevel@tonic-gate 			**  the name portion of the address.
8227c478bd9Sstevel@tonic-gate 			*/
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 			p = addquotes(p, e->e_rpool);
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, 'x', p);
8277c478bd9Sstevel@tonic-gate 	}
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	if (tTd(32, 1))
8307c478bd9Sstevel@tonic-gate 		sm_dprintf("----- collected header -----\n");
8317c478bd9Sstevel@tonic-gate 	e->e_msgid = NULL;
8327c478bd9Sstevel@tonic-gate 	for (h = e->e_header; h != NULL; h = h->h_link)
8337c478bd9Sstevel@tonic-gate 	{
8347c478bd9Sstevel@tonic-gate 		if (tTd(32, 1))
8357c478bd9Sstevel@tonic-gate 			sm_dprintf("%s:", h->h_field);
8367c478bd9Sstevel@tonic-gate 		if (h->h_value == NULL)
8377c478bd9Sstevel@tonic-gate 		{
8387c478bd9Sstevel@tonic-gate 			if (tTd(32, 1))
8397c478bd9Sstevel@tonic-gate 				sm_dprintf("<NULL>\n");
8407c478bd9Sstevel@tonic-gate 			continue;
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 		/* do early binding */
8447c478bd9Sstevel@tonic-gate 		if (bitset(H_DEFAULT, h->h_flags) &&
8457c478bd9Sstevel@tonic-gate 		    !bitset(H_BINDLATE, h->h_flags))
8467c478bd9Sstevel@tonic-gate 		{
8477c478bd9Sstevel@tonic-gate 			if (tTd(32, 1))
8487c478bd9Sstevel@tonic-gate 			{
8497c478bd9Sstevel@tonic-gate 				sm_dprintf("(");
8507c478bd9Sstevel@tonic-gate 				xputs(sm_debug_file(), h->h_value);
8517c478bd9Sstevel@tonic-gate 				sm_dprintf(") ");
8527c478bd9Sstevel@tonic-gate 			}
853058561cbSjbeck 			expand(h->h_value, buf, sizeof(buf), e);
854*4aac33d3Sjbeck 			if (buf[0] != '\0' &&
855*4aac33d3Sjbeck 			    (buf[0] != ' ' || buf[1] != '\0'))
8567c478bd9Sstevel@tonic-gate 			{
8577c478bd9Sstevel@tonic-gate 				if (bitset(H_FROM, h->h_flags))
8587c478bd9Sstevel@tonic-gate 					expand(crackaddr(buf, e),
859058561cbSjbeck 					       buf, sizeof(buf), e);
8607c478bd9Sstevel@tonic-gate 				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
8617c478bd9Sstevel@tonic-gate 				h->h_flags &= ~H_DEFAULT;
8627c478bd9Sstevel@tonic-gate 			}
8637c478bd9Sstevel@tonic-gate 		}
8647c478bd9Sstevel@tonic-gate 		if (tTd(32, 1))
8657c478bd9Sstevel@tonic-gate 		{
8667c478bd9Sstevel@tonic-gate 			xputs(sm_debug_file(), h->h_value);
8677c478bd9Sstevel@tonic-gate 			sm_dprintf("\n");
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		/* count the number of times it has been processed */
8717c478bd9Sstevel@tonic-gate 		if (bitset(H_TRACE, h->h_flags))
8727c478bd9Sstevel@tonic-gate 			hopcnt++;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 		/* send to this person if we so desire */
8757c478bd9Sstevel@tonic-gate 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
8767c478bd9Sstevel@tonic-gate 		    !bitset(H_DEFAULT, h->h_flags) &&
8777c478bd9Sstevel@tonic-gate 		    (!bitset(EF_RESENT, e->e_flags) ||
8787c478bd9Sstevel@tonic-gate 		     bitset(H_RESENT, h->h_flags)))
8797c478bd9Sstevel@tonic-gate 		{
8807c478bd9Sstevel@tonic-gate #if 0
8817c478bd9Sstevel@tonic-gate 			int saveflags = e->e_flags;
8827c478bd9Sstevel@tonic-gate #endif /* 0 */
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 			(void) sendtolist(denlstring(h->h_value, true, false),
8857c478bd9Sstevel@tonic-gate 					  NULLADDR, &e->e_sendqueue, 0, e);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate #if 0
8887c478bd9Sstevel@tonic-gate 			/*
8897c478bd9Sstevel@tonic-gate 			**  Change functionality so a fatal error on an
8907c478bd9Sstevel@tonic-gate 			**  address doesn't affect the entire envelope.
8917c478bd9Sstevel@tonic-gate 			*/
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 			/* delete fatal errors generated by this address */
8947c478bd9Sstevel@tonic-gate 			if (!bitset(EF_FATALERRS, saveflags))
8957c478bd9Sstevel@tonic-gate 				e->e_flags &= ~EF_FATALERRS;
8967c478bd9Sstevel@tonic-gate #endif /* 0 */
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 		/* save the message-id for logging */
9007c478bd9Sstevel@tonic-gate 		p = "resent-message-id";
9017c478bd9Sstevel@tonic-gate 		if (!bitset(EF_RESENT, e->e_flags))
9027c478bd9Sstevel@tonic-gate 			p += 7;
9037c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(h->h_field, p) == 0)
9047c478bd9Sstevel@tonic-gate 		{
9057c478bd9Sstevel@tonic-gate 			e->e_msgid = h->h_value;
9067c478bd9Sstevel@tonic-gate 			while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
9077c478bd9Sstevel@tonic-gate 				e->e_msgid++;
9087c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
9097c478bd9Sstevel@tonic-gate 				  e->e_msgid);
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 	}
9127c478bd9Sstevel@tonic-gate 	if (tTd(32, 1))
9137c478bd9Sstevel@tonic-gate 		sm_dprintf("----------------------------\n");
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
9167c478bd9Sstevel@tonic-gate 	if (OpMode == MD_VERIFY)
9177c478bd9Sstevel@tonic-gate 		return;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	/* store hop count */
9207c478bd9Sstevel@tonic-gate 	if (hopcnt > e->e_hopcount)
9217c478bd9Sstevel@tonic-gate 	{
9227c478bd9Sstevel@tonic-gate 		e->e_hopcount = hopcnt;
923058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
9247c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, 'c', buf);
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/* message priority */
9287c478bd9Sstevel@tonic-gate 	p = hvalue("precedence", e->e_header);
9297c478bd9Sstevel@tonic-gate 	if (p != NULL)
9307c478bd9Sstevel@tonic-gate 		e->e_class = priencode(p);
9317c478bd9Sstevel@tonic-gate 	if (e->e_class < 0)
9327c478bd9Sstevel@tonic-gate 		e->e_timeoutclass = TOC_NONURGENT;
9337c478bd9Sstevel@tonic-gate 	else if (e->e_class > 0)
9347c478bd9Sstevel@tonic-gate 		e->e_timeoutclass = TOC_URGENT;
9357c478bd9Sstevel@tonic-gate 	if (full)
9367c478bd9Sstevel@tonic-gate 	{
9377c478bd9Sstevel@tonic-gate 		e->e_msgpriority = e->e_msgsize
9387c478bd9Sstevel@tonic-gate 				 - e->e_class * WkClassFact
9397c478bd9Sstevel@tonic-gate 				 + e->e_nrcpts * WkRecipFact;
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	/* check for DSN to properly set e_timeoutclass */
9437c478bd9Sstevel@tonic-gate 	p = hvalue("content-type", e->e_header);
9447c478bd9Sstevel@tonic-gate 	if (p != NULL)
9457c478bd9Sstevel@tonic-gate 	{
9467c478bd9Sstevel@tonic-gate 		bool oldsupr;
9477c478bd9Sstevel@tonic-gate 		char **pvp;
9487c478bd9Sstevel@tonic-gate 		char pvpbuf[MAXLINE];
9497c478bd9Sstevel@tonic-gate 		extern unsigned char MimeTokenTab[256];
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		/* tokenize header */
9527c478bd9Sstevel@tonic-gate 		oldsupr = SuprErrs;
9537c478bd9Sstevel@tonic-gate 		SuprErrs = true;
954058561cbSjbeck 		pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
9557c478bd9Sstevel@tonic-gate 			      MimeTokenTab, false);
9567c478bd9Sstevel@tonic-gate 		SuprErrs = oldsupr;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 		/* Check if multipart/report */
9597c478bd9Sstevel@tonic-gate 		if (pvp != NULL && pvp[0] != NULL &&
9607c478bd9Sstevel@tonic-gate 		    pvp[1] != NULL && pvp[2] != NULL &&
9617c478bd9Sstevel@tonic-gate 		    sm_strcasecmp(*pvp++, "multipart") == 0 &&
9627c478bd9Sstevel@tonic-gate 		    strcmp(*pvp++, "/") == 0 &&
9637c478bd9Sstevel@tonic-gate 		    sm_strcasecmp(*pvp++, "report") == 0)
9647c478bd9Sstevel@tonic-gate 		{
9657c478bd9Sstevel@tonic-gate 			/* Look for report-type=delivery-status */
9667c478bd9Sstevel@tonic-gate 			while (*pvp != NULL)
9677c478bd9Sstevel@tonic-gate 			{
9687c478bd9Sstevel@tonic-gate 				/* skip to semicolon separator */
9697c478bd9Sstevel@tonic-gate 				while (*pvp != NULL && strcmp(*pvp, ";") != 0)
9707c478bd9Sstevel@tonic-gate 					pvp++;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 				/* skip semicolon */
9737c478bd9Sstevel@tonic-gate 				if (*pvp++ == NULL || *pvp == NULL)
9747c478bd9Sstevel@tonic-gate 					break;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 				/* look for report-type */
9777c478bd9Sstevel@tonic-gate 				if (sm_strcasecmp(*pvp++, "report-type") != 0)
9787c478bd9Sstevel@tonic-gate 					continue;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 				/* skip equal */
9817c478bd9Sstevel@tonic-gate 				if (*pvp == NULL || strcmp(*pvp, "=") != 0)
9827c478bd9Sstevel@tonic-gate 					continue;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 				/* check value */
9857c478bd9Sstevel@tonic-gate 				if (*++pvp != NULL &&
9867c478bd9Sstevel@tonic-gate 				    sm_strcasecmp(*pvp,
9877c478bd9Sstevel@tonic-gate 						  "delivery-status") == 0)
9887c478bd9Sstevel@tonic-gate 					e->e_timeoutclass = TOC_DSN;
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 				/* found report-type, no need to continue */
9917c478bd9Sstevel@tonic-gate 				break;
9927c478bd9Sstevel@tonic-gate 			}
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	/* message timeout priority */
9977c478bd9Sstevel@tonic-gate 	p = hvalue("priority", e->e_header);
9987c478bd9Sstevel@tonic-gate 	if (p != NULL)
9997c478bd9Sstevel@tonic-gate 	{
10007c478bd9Sstevel@tonic-gate 		/* (this should be in the configuration file) */
10017c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(p, "urgent") == 0)
10027c478bd9Sstevel@tonic-gate 			e->e_timeoutclass = TOC_URGENT;
10037c478bd9Sstevel@tonic-gate 		else if (sm_strcasecmp(p, "normal") == 0)
10047c478bd9Sstevel@tonic-gate 			e->e_timeoutclass = TOC_NORMAL;
10057c478bd9Sstevel@tonic-gate 		else if (sm_strcasecmp(p, "non-urgent") == 0)
10067c478bd9Sstevel@tonic-gate 			e->e_timeoutclass = TOC_NONURGENT;
10077c478bd9Sstevel@tonic-gate 		else if (bitset(EF_RESPONSE, e->e_flags))
10087c478bd9Sstevel@tonic-gate 			e->e_timeoutclass = TOC_DSN;
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 	else if (bitset(EF_RESPONSE, e->e_flags))
10117c478bd9Sstevel@tonic-gate 		e->e_timeoutclass = TOC_DSN;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/* date message originated */
10147c478bd9Sstevel@tonic-gate 	p = hvalue("posted-date", e->e_header);
10157c478bd9Sstevel@tonic-gate 	if (p == NULL)
10167c478bd9Sstevel@tonic-gate 		p = hvalue("date", e->e_header);
10177c478bd9Sstevel@tonic-gate 	if (p != NULL)
10187c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_PERM, 'a', p);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	/* check to see if this is a MIME message */
10217c478bd9Sstevel@tonic-gate 	if ((e->e_bodytype != NULL &&
10227c478bd9Sstevel@tonic-gate 	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
10237c478bd9Sstevel@tonic-gate 	    hvalue("MIME-Version", e->e_header) != NULL)
10247c478bd9Sstevel@tonic-gate 	{
10257c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_IS_MIME;
10267c478bd9Sstevel@tonic-gate 		if (HasEightBits)
10277c478bd9Sstevel@tonic-gate 			e->e_bodytype = "8BITMIME";
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
10307c478bd9Sstevel@tonic-gate 	{
10317c478bd9Sstevel@tonic-gate 		/* this may be an RFC 1049 message */
10327c478bd9Sstevel@tonic-gate 		p = strpbrk(p, ";/");
10337c478bd9Sstevel@tonic-gate 		if (p == NULL || *p == ';')
10347c478bd9Sstevel@tonic-gate 		{
10357c478bd9Sstevel@tonic-gate 			/* yep, it is */
10367c478bd9Sstevel@tonic-gate 			e->e_flags |= EF_DONT_MIME;
10377c478bd9Sstevel@tonic-gate 		}
10387c478bd9Sstevel@tonic-gate 	}
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	/*
10417c478bd9Sstevel@tonic-gate 	**  From person in antiquated ARPANET mode
10427c478bd9Sstevel@tonic-gate 	**	required by UK Grey Book e-mail gateways (sigh)
10437c478bd9Sstevel@tonic-gate 	*/
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	if (OpMode == MD_ARPAFTP)
10467c478bd9Sstevel@tonic-gate 	{
10477c478bd9Sstevel@tonic-gate 		register struct hdrinfo *hi;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
10507c478bd9Sstevel@tonic-gate 		{
10517c478bd9Sstevel@tonic-gate 			if (bitset(H_FROM, hi->hi_flags) &&
10527c478bd9Sstevel@tonic-gate 			    (!bitset(H_RESENT, hi->hi_flags) ||
10537c478bd9Sstevel@tonic-gate 			     bitset(EF_RESENT, e->e_flags)) &&
10547c478bd9Sstevel@tonic-gate 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
10557c478bd9Sstevel@tonic-gate 				break;
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 		if (hi->hi_field != NULL)
10587c478bd9Sstevel@tonic-gate 		{
10597c478bd9Sstevel@tonic-gate 			if (tTd(32, 2))
10607c478bd9Sstevel@tonic-gate 				sm_dprintf("eatheader: setsender(*%s == %s)\n",
10617c478bd9Sstevel@tonic-gate 					hi->hi_field, p);
10627c478bd9Sstevel@tonic-gate 			setsender(p, e, NULL, '\0', true);
10637c478bd9Sstevel@tonic-gate 		}
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	/*
10677c478bd9Sstevel@tonic-gate 	**  Log collection information.
10687c478bd9Sstevel@tonic-gate 	*/
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
10717c478bd9Sstevel@tonic-gate 	{
10727c478bd9Sstevel@tonic-gate 		logsender(e, e->e_msgid);
10737c478bd9Sstevel@tonic-gate 		e->e_flags &= ~EF_LOGSENDER;
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate }
1076058561cbSjbeck 
10777c478bd9Sstevel@tonic-gate /*
10787c478bd9Sstevel@tonic-gate **  LOGSENDER -- log sender information
10797c478bd9Sstevel@tonic-gate **
10807c478bd9Sstevel@tonic-gate **	Parameters:
10817c478bd9Sstevel@tonic-gate **		e -- the envelope to log
10827c478bd9Sstevel@tonic-gate **		msgid -- the message id
10837c478bd9Sstevel@tonic-gate **
10847c478bd9Sstevel@tonic-gate **	Returns:
10857c478bd9Sstevel@tonic-gate **		none
10867c478bd9Sstevel@tonic-gate */
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate void
10897c478bd9Sstevel@tonic-gate logsender(e, msgid)
10907c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
10917c478bd9Sstevel@tonic-gate 	char *msgid;
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate 	char *name;
10947c478bd9Sstevel@tonic-gate 	register char *sbp;
10957c478bd9Sstevel@tonic-gate 	register char *p;
10967c478bd9Sstevel@tonic-gate 	char hbuf[MAXNAME + 1];
10977c478bd9Sstevel@tonic-gate 	char sbuf[MAXLINE + 1];
10987c478bd9Sstevel@tonic-gate 	char mbuf[MAXNAME + 1];
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	/* don't allow newlines in the message-id */
11017c478bd9Sstevel@tonic-gate 	/* XXX do we still need this? sm_syslog() replaces control chars */
11027c478bd9Sstevel@tonic-gate 	if (msgid != NULL)
11037c478bd9Sstevel@tonic-gate 	{
1104445f2479Sjbeck 		size_t l;
1105445f2479Sjbeck 
11067c478bd9Sstevel@tonic-gate 		l = strlen(msgid);
1107058561cbSjbeck 		if (l > sizeof(mbuf) - 1)
1108058561cbSjbeck 			l = sizeof(mbuf) - 1;
11097c478bd9Sstevel@tonic-gate 		memmove(mbuf, msgid, l);
11107c478bd9Sstevel@tonic-gate 		mbuf[l] = '\0';
11117c478bd9Sstevel@tonic-gate 		p = mbuf;
11127c478bd9Sstevel@tonic-gate 		while ((p = strchr(p, '\n')) != NULL)
11137c478bd9Sstevel@tonic-gate 			*p++ = ' ';
11147c478bd9Sstevel@tonic-gate 	}
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	if (bitset(EF_RESPONSE, e->e_flags))
11177c478bd9Sstevel@tonic-gate 		name = "[RESPONSE]";
11187c478bd9Sstevel@tonic-gate 	else if ((name = macvalue('_', e)) != NULL)
11197c478bd9Sstevel@tonic-gate 		/* EMPTY */
11207c478bd9Sstevel@tonic-gate 		;
11217c478bd9Sstevel@tonic-gate 	else if (RealHostName == NULL)
11227c478bd9Sstevel@tonic-gate 		name = "localhost";
11237c478bd9Sstevel@tonic-gate 	else if (RealHostName[0] == '[')
11247c478bd9Sstevel@tonic-gate 		name = RealHostName;
11257c478bd9Sstevel@tonic-gate 	else
11267c478bd9Sstevel@tonic-gate 	{
11277c478bd9Sstevel@tonic-gate 		name = hbuf;
1128058561cbSjbeck 		(void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
11297c478bd9Sstevel@tonic-gate 		if (RealHostAddr.sa.sa_family != 0)
11307c478bd9Sstevel@tonic-gate 		{
11317c478bd9Sstevel@tonic-gate 			p = &hbuf[strlen(hbuf)];
11327c478bd9Sstevel@tonic-gate 			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
11337c478bd9Sstevel@tonic-gate 					   " (%.100s)",
11347c478bd9Sstevel@tonic-gate 					   anynet_ntoa(&RealHostAddr));
11357c478bd9Sstevel@tonic-gate 		}
11367c478bd9Sstevel@tonic-gate 	}
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	/* some versions of syslog only take 5 printf args */
11397c478bd9Sstevel@tonic-gate #if (SYSLOG_BUFSIZE) >= 256
11407c478bd9Sstevel@tonic-gate 	sbp = sbuf;
11417c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11427c478bd9Sstevel@tonic-gate 		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
11437c478bd9Sstevel@tonic-gate 		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
11447c478bd9Sstevel@tonic-gate 		e->e_msgsize, e->e_class, e->e_nrcpts);
11457c478bd9Sstevel@tonic-gate 	sbp += strlen(sbp);
11467c478bd9Sstevel@tonic-gate 	if (msgid != NULL)
11477c478bd9Sstevel@tonic-gate 	{
11487c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11497c478bd9Sstevel@tonic-gate 				", msgid=%.100s", mbuf);
11507c478bd9Sstevel@tonic-gate 		sbp += strlen(sbp);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 	if (e->e_bodytype != NULL)
11537c478bd9Sstevel@tonic-gate 	{
11547c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11557c478bd9Sstevel@tonic-gate 				", bodytype=%.20s", e->e_bodytype);
11567c478bd9Sstevel@tonic-gate 		sbp += strlen(sbp);
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate 	p = macvalue('r', e);
11597c478bd9Sstevel@tonic-gate 	if (p != NULL)
11607c478bd9Sstevel@tonic-gate 	{
11617c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11627c478bd9Sstevel@tonic-gate 				", proto=%.20s", p);
11637c478bd9Sstevel@tonic-gate 		sbp += strlen(sbp);
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 	p = macvalue(macid("{daemon_name}"), e);
11667c478bd9Sstevel@tonic-gate 	if (p != NULL)
11677c478bd9Sstevel@tonic-gate 	{
11687c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11697c478bd9Sstevel@tonic-gate 				", daemon=%.20s", p);
11707c478bd9Sstevel@tonic-gate 		sbp += strlen(sbp);
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate #else /* (SYSLOG_BUFSIZE) >= 256 */
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, e->e_id,
11777c478bd9Sstevel@tonic-gate 		  "from=%s",
11787c478bd9Sstevel@tonic-gate 		  e->e_from.q_paddr == NULL ? "<NONE>"
11797c478bd9Sstevel@tonic-gate 					    : shortenstring(e->e_from.q_paddr,
11807c478bd9Sstevel@tonic-gate 							    83));
11817c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, e->e_id,
11827c478bd9Sstevel@tonic-gate 		  "size=%ld, class=%ld, nrcpts=%d",
11837c478bd9Sstevel@tonic-gate 		  e->e_msgsize, e->e_class, e->e_nrcpts);
11847c478bd9Sstevel@tonic-gate 	if (msgid != NULL)
11857c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id,
11867c478bd9Sstevel@tonic-gate 			  "msgid=%s",
11877c478bd9Sstevel@tonic-gate 			  shortenstring(mbuf, 83));
11887c478bd9Sstevel@tonic-gate 	sbp = sbuf;
11897c478bd9Sstevel@tonic-gate 	*sbp = '\0';
11907c478bd9Sstevel@tonic-gate 	if (e->e_bodytype != NULL)
11917c478bd9Sstevel@tonic-gate 	{
11927c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11937c478bd9Sstevel@tonic-gate 				"bodytype=%.20s, ", e->e_bodytype);
11947c478bd9Sstevel@tonic-gate 		sbp += strlen(sbp);
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 	p = macvalue('r', e);
11977c478bd9Sstevel@tonic-gate 	if (p != NULL)
11987c478bd9Sstevel@tonic-gate 	{
11997c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
12007c478bd9Sstevel@tonic-gate 				"proto=%.20s, ", p);
12017c478bd9Sstevel@tonic-gate 		sbp += strlen(sbp);
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, e->e_id,
12047c478bd9Sstevel@tonic-gate 		  "%.400srelay=%s", sbuf, name);
12057c478bd9Sstevel@tonic-gate #endif /* (SYSLOG_BUFSIZE) >= 256 */
12067c478bd9Sstevel@tonic-gate }
1207058561cbSjbeck 
12087c478bd9Sstevel@tonic-gate /*
12097c478bd9Sstevel@tonic-gate **  PRIENCODE -- encode external priority names into internal values.
12107c478bd9Sstevel@tonic-gate **
12117c478bd9Sstevel@tonic-gate **	Parameters:
12127c478bd9Sstevel@tonic-gate **		p -- priority in ascii.
12137c478bd9Sstevel@tonic-gate **
12147c478bd9Sstevel@tonic-gate **	Returns:
12157c478bd9Sstevel@tonic-gate **		priority as a numeric level.
12167c478bd9Sstevel@tonic-gate **
12177c478bd9Sstevel@tonic-gate **	Side Effects:
12187c478bd9Sstevel@tonic-gate **		none.
12197c478bd9Sstevel@tonic-gate */
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate static int
12227c478bd9Sstevel@tonic-gate priencode(p)
12237c478bd9Sstevel@tonic-gate 	char *p;
12247c478bd9Sstevel@tonic-gate {
12257c478bd9Sstevel@tonic-gate 	register int i;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	for (i = 0; i < NumPriorities; i++)
12287c478bd9Sstevel@tonic-gate 	{
12297c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
12307c478bd9Sstevel@tonic-gate 			return Priorities[i].pri_val;
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	/* unknown priority */
12347c478bd9Sstevel@tonic-gate 	return 0;
12357c478bd9Sstevel@tonic-gate }
1236058561cbSjbeck 
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate **  CRACKADDR -- parse an address and turn it into a macro
12397c478bd9Sstevel@tonic-gate **
12407c478bd9Sstevel@tonic-gate **	This doesn't actually parse the address -- it just extracts
12417c478bd9Sstevel@tonic-gate **	it and replaces it with "$g".  The parse is totally ad hoc
12427c478bd9Sstevel@tonic-gate **	and isn't even guaranteed to leave something syntactically
12437c478bd9Sstevel@tonic-gate **	identical to what it started with.  However, it does leave
12447c478bd9Sstevel@tonic-gate **	something semantically identical if possible, else at least
12457c478bd9Sstevel@tonic-gate **	syntactically correct.
12467c478bd9Sstevel@tonic-gate **
12477c478bd9Sstevel@tonic-gate **	For example, it changes "Real Name <real@example.com> (Comment)"
12487c478bd9Sstevel@tonic-gate **	to "Real Name <$g> (Comment)".
12497c478bd9Sstevel@tonic-gate **
12507c478bd9Sstevel@tonic-gate **	This algorithm has been cleaned up to handle a wider range
12517c478bd9Sstevel@tonic-gate **	of cases -- notably quoted and backslash escaped strings.
12527c478bd9Sstevel@tonic-gate **	This modification makes it substantially better at preserving
12537c478bd9Sstevel@tonic-gate **	the original syntax.
12547c478bd9Sstevel@tonic-gate **
12557c478bd9Sstevel@tonic-gate **	Parameters:
12567c478bd9Sstevel@tonic-gate **		addr -- the address to be cracked.
12577c478bd9Sstevel@tonic-gate **		e -- the current envelope.
12587c478bd9Sstevel@tonic-gate **
12597c478bd9Sstevel@tonic-gate **	Returns:
12607c478bd9Sstevel@tonic-gate **		a pointer to the new version.
12617c478bd9Sstevel@tonic-gate **
12627c478bd9Sstevel@tonic-gate **	Side Effects:
12637c478bd9Sstevel@tonic-gate **		none.
12647c478bd9Sstevel@tonic-gate **
12657c478bd9Sstevel@tonic-gate **	Warning:
12667c478bd9Sstevel@tonic-gate **		The return value is saved in local storage and should
12677c478bd9Sstevel@tonic-gate **		be copied if it is to be reused.
12687c478bd9Sstevel@tonic-gate */
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate #define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate /*
12737c478bd9Sstevel@tonic-gate **  Append a character to bp if we have room.
12747c478bd9Sstevel@tonic-gate **  If not, punt and return $g.
12757c478bd9Sstevel@tonic-gate */
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate #define SM_APPEND_CHAR(c)					\
12787c478bd9Sstevel@tonic-gate 	do							\
12797c478bd9Sstevel@tonic-gate 	{							\
12807c478bd9Sstevel@tonic-gate 		if (SM_HAVE_ROOM)				\
12817c478bd9Sstevel@tonic-gate 			*bp++ = (c);				\
12827c478bd9Sstevel@tonic-gate 		else						\
12837c478bd9Sstevel@tonic-gate 			goto returng;				\
12847c478bd9Sstevel@tonic-gate 	} while (0)
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate #if MAXNAME < 10
12877c478bd9Sstevel@tonic-gate ERROR MAXNAME must be at least 10
12887c478bd9Sstevel@tonic-gate #endif /* MAXNAME < 10 */
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate char *
12917c478bd9Sstevel@tonic-gate crackaddr(addr, e)
12927c478bd9Sstevel@tonic-gate 	register char *addr;
12937c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
12947c478bd9Sstevel@tonic-gate {
12957c478bd9Sstevel@tonic-gate 	register char *p;
12967c478bd9Sstevel@tonic-gate 	register char c;
12977c478bd9Sstevel@tonic-gate 	int cmtlev;			/* comment level in input string */
12987c478bd9Sstevel@tonic-gate 	int realcmtlev;			/* comment level in output string */
12997c478bd9Sstevel@tonic-gate 	int anglelev;			/* angle level in input string */
13007c478bd9Sstevel@tonic-gate 	int copylev;			/* 0 == in address, >0 copying */
13017c478bd9Sstevel@tonic-gate 	int bracklev;			/* bracket level for IPv6 addr check */
13027c478bd9Sstevel@tonic-gate 	bool addangle;			/* put closing angle in output */
13037c478bd9Sstevel@tonic-gate 	bool qmode;			/* quoting in original string? */
13047c478bd9Sstevel@tonic-gate 	bool realqmode;			/* quoting in output string? */
13057c478bd9Sstevel@tonic-gate 	bool putgmac = false;		/* already wrote $g */
13067c478bd9Sstevel@tonic-gate 	bool quoteit = false;		/* need to quote next character */
13077c478bd9Sstevel@tonic-gate 	bool gotangle = false;		/* found first '<' */
13087c478bd9Sstevel@tonic-gate 	bool gotcolon = false;		/* found a ':' */
13097c478bd9Sstevel@tonic-gate 	register char *bp;
13107c478bd9Sstevel@tonic-gate 	char *buflim;
13117c478bd9Sstevel@tonic-gate 	char *bufhead;
13127c478bd9Sstevel@tonic-gate 	char *addrhead;
13137c478bd9Sstevel@tonic-gate 	char *bufend;
13147c478bd9Sstevel@tonic-gate 	static char buf[MAXNAME + 1];
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	if (tTd(33, 1))
13177c478bd9Sstevel@tonic-gate 		sm_dprintf("crackaddr(%s)\n", addr);
13187c478bd9Sstevel@tonic-gate 
1319058561cbSjbeck 	buflim = bufend = &buf[sizeof(buf) - 1];
1320058561cbSjbeck 	bp = bufhead = buf;
1321058561cbSjbeck 
1322058561cbSjbeck 	/* skip over leading spaces but preserve them */
13237c478bd9Sstevel@tonic-gate 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1324058561cbSjbeck 	{
1325058561cbSjbeck 		SM_APPEND_CHAR(*addr);
13267c478bd9Sstevel@tonic-gate 		addr++;
1327058561cbSjbeck 	}
1328058561cbSjbeck 	bufhead = bp;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	/*
13317c478bd9Sstevel@tonic-gate 	**  Start by assuming we have no angle brackets.  This will be
13327c478bd9Sstevel@tonic-gate 	**  adjusted later if we find them.
13337c478bd9Sstevel@tonic-gate 	*/
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	p = addrhead = addr;
13367c478bd9Sstevel@tonic-gate 	copylev = anglelev = cmtlev = realcmtlev = 0;
13377c478bd9Sstevel@tonic-gate 	bracklev = 0;
13387c478bd9Sstevel@tonic-gate 	qmode = realqmode = addangle = false;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	while ((c = *p++) != '\0')
13417c478bd9Sstevel@tonic-gate 	{
13427c478bd9Sstevel@tonic-gate 		/*
13437c478bd9Sstevel@tonic-gate 		**  Try to keep legal syntax using spare buffer space
13447c478bd9Sstevel@tonic-gate 		**  (maintained by buflim).
13457c478bd9Sstevel@tonic-gate 		*/
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 		if (copylev > 0)
13487c478bd9Sstevel@tonic-gate 			SM_APPEND_CHAR(c);
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 		/* check for backslash escapes */
13517c478bd9Sstevel@tonic-gate 		if (c == '\\')
13527c478bd9Sstevel@tonic-gate 		{
13537c478bd9Sstevel@tonic-gate 			/* arrange to quote the address */
13547c478bd9Sstevel@tonic-gate 			if (cmtlev <= 0 && !qmode)
13557c478bd9Sstevel@tonic-gate 				quoteit = true;
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 			if ((c = *p++) == '\0')
13587c478bd9Sstevel@tonic-gate 			{
13597c478bd9Sstevel@tonic-gate 				/* too far */
13607c478bd9Sstevel@tonic-gate 				p--;
13617c478bd9Sstevel@tonic-gate 				goto putg;
13627c478bd9Sstevel@tonic-gate 			}
13637c478bd9Sstevel@tonic-gate 			if (copylev > 0)
13647c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(c);
13657c478bd9Sstevel@tonic-gate 			goto putg;
13667c478bd9Sstevel@tonic-gate 		}
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 		/* check for quoted strings */
13697c478bd9Sstevel@tonic-gate 		if (c == '"' && cmtlev <= 0)
13707c478bd9Sstevel@tonic-gate 		{
13717c478bd9Sstevel@tonic-gate 			qmode = !qmode;
13727c478bd9Sstevel@tonic-gate 			if (copylev > 0 && SM_HAVE_ROOM)
13737c478bd9Sstevel@tonic-gate 			{
13747c478bd9Sstevel@tonic-gate 				if (realqmode)
13757c478bd9Sstevel@tonic-gate 					buflim--;
13767c478bd9Sstevel@tonic-gate 				else
13777c478bd9Sstevel@tonic-gate 					buflim++;
13787c478bd9Sstevel@tonic-gate 				realqmode = !realqmode;
13797c478bd9Sstevel@tonic-gate 			}
13807c478bd9Sstevel@tonic-gate 			continue;
13817c478bd9Sstevel@tonic-gate 		}
13827c478bd9Sstevel@tonic-gate 		if (qmode)
13837c478bd9Sstevel@tonic-gate 			goto putg;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 		/* check for comments */
13867c478bd9Sstevel@tonic-gate 		if (c == '(')
13877c478bd9Sstevel@tonic-gate 		{
13887c478bd9Sstevel@tonic-gate 			cmtlev++;
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 			/* allow space for closing paren */
13917c478bd9Sstevel@tonic-gate 			if (SM_HAVE_ROOM)
13927c478bd9Sstevel@tonic-gate 			{
13937c478bd9Sstevel@tonic-gate 				buflim--;
13947c478bd9Sstevel@tonic-gate 				realcmtlev++;
13957c478bd9Sstevel@tonic-gate 				if (copylev++ <= 0)
13967c478bd9Sstevel@tonic-gate 				{
13977c478bd9Sstevel@tonic-gate 					if (bp != bufhead)
13987c478bd9Sstevel@tonic-gate 						SM_APPEND_CHAR(' ');
13997c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(c);
14007c478bd9Sstevel@tonic-gate 				}
14017c478bd9Sstevel@tonic-gate 			}
14027c478bd9Sstevel@tonic-gate 		}
14037c478bd9Sstevel@tonic-gate 		if (cmtlev > 0)
14047c478bd9Sstevel@tonic-gate 		{
14057c478bd9Sstevel@tonic-gate 			if (c == ')')
14067c478bd9Sstevel@tonic-gate 			{
14077c478bd9Sstevel@tonic-gate 				cmtlev--;
14087c478bd9Sstevel@tonic-gate 				copylev--;
14097c478bd9Sstevel@tonic-gate 				if (SM_HAVE_ROOM)
14107c478bd9Sstevel@tonic-gate 				{
14117c478bd9Sstevel@tonic-gate 					realcmtlev--;
14127c478bd9Sstevel@tonic-gate 					buflim++;
14137c478bd9Sstevel@tonic-gate 				}
14147c478bd9Sstevel@tonic-gate 			}
14157c478bd9Sstevel@tonic-gate 			continue;
14167c478bd9Sstevel@tonic-gate 		}
14177c478bd9Sstevel@tonic-gate 		else if (c == ')')
14187c478bd9Sstevel@tonic-gate 		{
14197c478bd9Sstevel@tonic-gate 			/* syntax error: unmatched ) */
14207c478bd9Sstevel@tonic-gate 			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
14217c478bd9Sstevel@tonic-gate 				bp--;
14227c478bd9Sstevel@tonic-gate 		}
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 		/* count nesting on [ ... ] (for IPv6 domain literals) */
14257c478bd9Sstevel@tonic-gate 		if (c == '[')
14267c478bd9Sstevel@tonic-gate 			bracklev++;
14277c478bd9Sstevel@tonic-gate 		else if (c == ']')
14287c478bd9Sstevel@tonic-gate 			bracklev--;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 		/* check for group: list; syntax */
14317c478bd9Sstevel@tonic-gate 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
14327c478bd9Sstevel@tonic-gate 		    !gotcolon && !ColonOkInAddr)
14337c478bd9Sstevel@tonic-gate 		{
14347c478bd9Sstevel@tonic-gate 			register char *q;
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 			/*
14377c478bd9Sstevel@tonic-gate 			**  Check for DECnet phase IV ``::'' (host::user)
14387c478bd9Sstevel@tonic-gate 			**  or DECnet phase V ``:.'' syntaxes.  The latter
14397c478bd9Sstevel@tonic-gate 			**  covers ``user@DEC:.tay.myhost'' and
14407c478bd9Sstevel@tonic-gate 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
14417c478bd9Sstevel@tonic-gate 			*/
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 			if (*p == ':' || *p == '.')
14447c478bd9Sstevel@tonic-gate 			{
14457c478bd9Sstevel@tonic-gate 				if (cmtlev <= 0 && !qmode)
14467c478bd9Sstevel@tonic-gate 					quoteit = true;
14477c478bd9Sstevel@tonic-gate 				if (copylev > 0)
14487c478bd9Sstevel@tonic-gate 				{
14497c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(c);
14507c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(*p);
14517c478bd9Sstevel@tonic-gate 				}
14527c478bd9Sstevel@tonic-gate 				p++;
14537c478bd9Sstevel@tonic-gate 				goto putg;
14547c478bd9Sstevel@tonic-gate 			}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 			gotcolon = true;
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 			bp = bufhead;
14597c478bd9Sstevel@tonic-gate 			if (quoteit)
14607c478bd9Sstevel@tonic-gate 			{
14617c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR('"');
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 				/* back up over the ':' and any spaces */
14647c478bd9Sstevel@tonic-gate 				--p;
14657c478bd9Sstevel@tonic-gate 				while (p > addr &&
14667c478bd9Sstevel@tonic-gate 				       isascii(*--p) && isspace(*p))
14677c478bd9Sstevel@tonic-gate 					continue;
14687c478bd9Sstevel@tonic-gate 				p++;
14697c478bd9Sstevel@tonic-gate 			}
14707c478bd9Sstevel@tonic-gate 			for (q = addrhead; q < p; )
14717c478bd9Sstevel@tonic-gate 			{
14727c478bd9Sstevel@tonic-gate 				c = *q++;
14737c478bd9Sstevel@tonic-gate 				if (quoteit && c == '"')
14747c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR('\\');
14757c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(c);
14767c478bd9Sstevel@tonic-gate 			}
14777c478bd9Sstevel@tonic-gate 			if (quoteit)
14787c478bd9Sstevel@tonic-gate 			{
14797c478bd9Sstevel@tonic-gate 				if (bp == &bufhead[1])
14807c478bd9Sstevel@tonic-gate 					bp--;
14817c478bd9Sstevel@tonic-gate 				else
14827c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR('"');
14837c478bd9Sstevel@tonic-gate 				while ((c = *p++) != ':')
14847c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(c);
14857c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(c);
14867c478bd9Sstevel@tonic-gate 			}
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 			/* any trailing white space is part of group: */
14897c478bd9Sstevel@tonic-gate 			while (isascii(*p) && isspace(*p))
14907c478bd9Sstevel@tonic-gate 			{
14917c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(*p);
14927c478bd9Sstevel@tonic-gate 				p++;
14937c478bd9Sstevel@tonic-gate 			}
14947c478bd9Sstevel@tonic-gate 			copylev = 0;
14957c478bd9Sstevel@tonic-gate 			putgmac = quoteit = false;
14967c478bd9Sstevel@tonic-gate 			bufhead = bp;
14977c478bd9Sstevel@tonic-gate 			addrhead = p;
14987c478bd9Sstevel@tonic-gate 			continue;
14997c478bd9Sstevel@tonic-gate 		}
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
15027c478bd9Sstevel@tonic-gate 			SM_APPEND_CHAR(c);
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 		/* check for characters that may have to be quoted */
15057c478bd9Sstevel@tonic-gate 		if (strchr(MustQuoteChars, c) != NULL)
15067c478bd9Sstevel@tonic-gate 		{
15077c478bd9Sstevel@tonic-gate 			/*
15087c478bd9Sstevel@tonic-gate 			**  If these occur as the phrase part of a <>
15097c478bd9Sstevel@tonic-gate 			**  construct, but are not inside of () or already
15107c478bd9Sstevel@tonic-gate 			**  quoted, they will have to be quoted.  Note that
15117c478bd9Sstevel@tonic-gate 			**  now (but don't actually do the quoting).
15127c478bd9Sstevel@tonic-gate 			*/
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 			if (cmtlev <= 0 && !qmode)
15157c478bd9Sstevel@tonic-gate 				quoteit = true;
15167c478bd9Sstevel@tonic-gate 		}
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 		/* check for angle brackets */
15197c478bd9Sstevel@tonic-gate 		if (c == '<')
15207c478bd9Sstevel@tonic-gate 		{
15217c478bd9Sstevel@tonic-gate 			register char *q;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 			/* assume first of two angles is bogus */
15247c478bd9Sstevel@tonic-gate 			if (gotangle)
15257c478bd9Sstevel@tonic-gate 				quoteit = true;
15267c478bd9Sstevel@tonic-gate 			gotangle = true;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 			/* oops -- have to change our mind */
15297c478bd9Sstevel@tonic-gate 			anglelev = 1;
15307c478bd9Sstevel@tonic-gate 			if (SM_HAVE_ROOM)
15317c478bd9Sstevel@tonic-gate 			{
15327c478bd9Sstevel@tonic-gate 				if (!addangle)
15337c478bd9Sstevel@tonic-gate 					buflim--;
15347c478bd9Sstevel@tonic-gate 				addangle = true;
15357c478bd9Sstevel@tonic-gate 			}
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 			bp = bufhead;
15387c478bd9Sstevel@tonic-gate 			if (quoteit)
15397c478bd9Sstevel@tonic-gate 			{
15407c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR('"');
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 				/* back up over the '<' and any spaces */
15437c478bd9Sstevel@tonic-gate 				--p;
15447c478bd9Sstevel@tonic-gate 				while (p > addr &&
15457c478bd9Sstevel@tonic-gate 				       isascii(*--p) && isspace(*p))
15467c478bd9Sstevel@tonic-gate 					continue;
15477c478bd9Sstevel@tonic-gate 				p++;
15487c478bd9Sstevel@tonic-gate 			}
15497c478bd9Sstevel@tonic-gate 			for (q = addrhead; q < p; )
15507c478bd9Sstevel@tonic-gate 			{
15517c478bd9Sstevel@tonic-gate 				c = *q++;
15527c478bd9Sstevel@tonic-gate 				if (quoteit && c == '"')
15537c478bd9Sstevel@tonic-gate 				{
15547c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR('\\');
15557c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(c);
15567c478bd9Sstevel@tonic-gate 				}
15577c478bd9Sstevel@tonic-gate 				else
15587c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(c);
15597c478bd9Sstevel@tonic-gate 			}
15607c478bd9Sstevel@tonic-gate 			if (quoteit)
15617c478bd9Sstevel@tonic-gate 			{
15627c478bd9Sstevel@tonic-gate 				if (bp == &buf[1])
15637c478bd9Sstevel@tonic-gate 					bp--;
15647c478bd9Sstevel@tonic-gate 				else
15657c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR('"');
15667c478bd9Sstevel@tonic-gate 				while ((c = *p++) != '<')
15677c478bd9Sstevel@tonic-gate 					SM_APPEND_CHAR(c);
15687c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(c);
15697c478bd9Sstevel@tonic-gate 			}
15707c478bd9Sstevel@tonic-gate 			copylev = 0;
15717c478bd9Sstevel@tonic-gate 			putgmac = quoteit = false;
15727c478bd9Sstevel@tonic-gate 			continue;
15737c478bd9Sstevel@tonic-gate 		}
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 		if (c == '>')
15767c478bd9Sstevel@tonic-gate 		{
15777c478bd9Sstevel@tonic-gate 			if (anglelev > 0)
15787c478bd9Sstevel@tonic-gate 			{
15797c478bd9Sstevel@tonic-gate 				anglelev--;
15807c478bd9Sstevel@tonic-gate 				if (SM_HAVE_ROOM)
15817c478bd9Sstevel@tonic-gate 				{
15827c478bd9Sstevel@tonic-gate 					if (addangle)
15837c478bd9Sstevel@tonic-gate 						buflim++;
15847c478bd9Sstevel@tonic-gate 					addangle = false;
15857c478bd9Sstevel@tonic-gate 				}
15867c478bd9Sstevel@tonic-gate 			}
15877c478bd9Sstevel@tonic-gate 			else if (SM_HAVE_ROOM)
15887c478bd9Sstevel@tonic-gate 			{
15897c478bd9Sstevel@tonic-gate 				/* syntax error: unmatched > */
15907c478bd9Sstevel@tonic-gate 				if (copylev > 0 && bp > bufhead)
15917c478bd9Sstevel@tonic-gate 					bp--;
15927c478bd9Sstevel@tonic-gate 				quoteit = true;
15937c478bd9Sstevel@tonic-gate 				continue;
15947c478bd9Sstevel@tonic-gate 			}
15957c478bd9Sstevel@tonic-gate 			if (copylev++ <= 0)
15967c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(c);
15977c478bd9Sstevel@tonic-gate 			continue;
15987c478bd9Sstevel@tonic-gate 		}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 		/* must be a real address character */
16017c478bd9Sstevel@tonic-gate 	putg:
16027c478bd9Sstevel@tonic-gate 		if (copylev <= 0 && !putgmac)
16037c478bd9Sstevel@tonic-gate 		{
16047c478bd9Sstevel@tonic-gate 			if (bp > buf && bp[-1] == ')')
16057c478bd9Sstevel@tonic-gate 				SM_APPEND_CHAR(' ');
16067c478bd9Sstevel@tonic-gate 			SM_APPEND_CHAR(MACROEXPAND);
16077c478bd9Sstevel@tonic-gate 			SM_APPEND_CHAR('g');
16087c478bd9Sstevel@tonic-gate 			putgmac = true;
16097c478bd9Sstevel@tonic-gate 		}
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	/* repair any syntactic damage */
16137c478bd9Sstevel@tonic-gate 	if (realqmode && bp < bufend)
16147c478bd9Sstevel@tonic-gate 		*bp++ = '"';
16157c478bd9Sstevel@tonic-gate 	while (realcmtlev-- > 0 && bp < bufend)
16167c478bd9Sstevel@tonic-gate 		*bp++ = ')';
16177c478bd9Sstevel@tonic-gate 	if (addangle && bp < bufend)
16187c478bd9Sstevel@tonic-gate 		*bp++ = '>';
16197c478bd9Sstevel@tonic-gate 	*bp = '\0';
16207c478bd9Sstevel@tonic-gate 	if (bp < bufend)
16217c478bd9Sstevel@tonic-gate 		goto success;
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate  returng:
16247c478bd9Sstevel@tonic-gate 	/* String too long, punt */
16257c478bd9Sstevel@tonic-gate 	buf[0] = '<';
16267c478bd9Sstevel@tonic-gate 	buf[1] = MACROEXPAND;
16277c478bd9Sstevel@tonic-gate 	buf[2]= 'g';
16287c478bd9Sstevel@tonic-gate 	buf[3] = '>';
16297c478bd9Sstevel@tonic-gate 	buf[4]= '\0';
16307c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_ALERT, e->e_id,
16317c478bd9Sstevel@tonic-gate 		  "Dropped invalid comments from header address");
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate  success:
16347c478bd9Sstevel@tonic-gate 	if (tTd(33, 1))
16357c478bd9Sstevel@tonic-gate 	{
16367c478bd9Sstevel@tonic-gate 		sm_dprintf("crackaddr=>`");
16377c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), buf);
16387c478bd9Sstevel@tonic-gate 		sm_dprintf("'\n");
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate 	return buf;
16417c478bd9Sstevel@tonic-gate }
1642058561cbSjbeck 
16437c478bd9Sstevel@tonic-gate /*
16447c478bd9Sstevel@tonic-gate **  PUTHEADER -- put the header part of a message from the in-core copy
16457c478bd9Sstevel@tonic-gate **
16467c478bd9Sstevel@tonic-gate **	Parameters:
16477c478bd9Sstevel@tonic-gate **		mci -- the connection information.
16487c478bd9Sstevel@tonic-gate **		hdr -- the header to put.
16497c478bd9Sstevel@tonic-gate **		e -- envelope to use.
16507c478bd9Sstevel@tonic-gate **		flags -- MIME conversion flags.
16517c478bd9Sstevel@tonic-gate **
16527c478bd9Sstevel@tonic-gate **	Returns:
16533ee0e492Sjbeck **		true iff header part was written successfully
16547c478bd9Sstevel@tonic-gate **
16557c478bd9Sstevel@tonic-gate **	Side Effects:
16567c478bd9Sstevel@tonic-gate **		none.
16577c478bd9Sstevel@tonic-gate */
16587c478bd9Sstevel@tonic-gate 
1659445f2479Sjbeck bool
16607c478bd9Sstevel@tonic-gate putheader(mci, hdr, e, flags)
16617c478bd9Sstevel@tonic-gate 	register MCI *mci;
16627c478bd9Sstevel@tonic-gate 	HDR *hdr;
16637c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
16647c478bd9Sstevel@tonic-gate 	int flags;
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 	register HDR *h;
16677c478bd9Sstevel@tonic-gate 	char buf[SM_MAX(MAXLINE,BUFSIZ)];
16687c478bd9Sstevel@tonic-gate 	char obuf[MAXLINE];
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if (tTd(34, 1))
16717c478bd9Sstevel@tonic-gate 		sm_dprintf("--- putheader, mailer = %s ---\n",
16727c478bd9Sstevel@tonic-gate 			mci->mci_mailer->m_name);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/*
16757c478bd9Sstevel@tonic-gate 	**  If we're in MIME mode, we're not really in the header of the
16767c478bd9Sstevel@tonic-gate 	**  message, just the header of one of the parts of the body of
16777c478bd9Sstevel@tonic-gate 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
16787c478bd9Sstevel@tonic-gate 	*/
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	if (!bitset(MCIF_INMIME, mci->mci_flags))
16817c478bd9Sstevel@tonic-gate 		mci->mci_flags |= MCIF_INHEADER;
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	for (h = hdr; h != NULL; h = h->h_link)
16847c478bd9Sstevel@tonic-gate 	{
16857c478bd9Sstevel@tonic-gate 		register char *p = h->h_value;
16867c478bd9Sstevel@tonic-gate 		char *q;
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 		if (tTd(34, 11))
16897c478bd9Sstevel@tonic-gate 		{
16907c478bd9Sstevel@tonic-gate 			sm_dprintf("  %s:", h->h_field);
16917c478bd9Sstevel@tonic-gate 			xputs(sm_debug_file(), p);
16927c478bd9Sstevel@tonic-gate 		}
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 		/* Skip empty headers */
16957c478bd9Sstevel@tonic-gate 		if (h->h_value == NULL)
16967c478bd9Sstevel@tonic-gate 			continue;
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 		/* heuristic shortening of MIME fields to avoid MUA overflows */
16997c478bd9Sstevel@tonic-gate 		if (MaxMimeFieldLength > 0 &&
17007c478bd9Sstevel@tonic-gate 		    wordinclass(h->h_field,
17017c478bd9Sstevel@tonic-gate 				macid("{checkMIMEFieldHeaders}")))
17027c478bd9Sstevel@tonic-gate 		{
17037c478bd9Sstevel@tonic-gate 			size_t len;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 			len = fix_mime_header(h, e);
17067c478bd9Sstevel@tonic-gate 			if (len > 0)
17077c478bd9Sstevel@tonic-gate 			{
17087c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ALERT, e->e_id,
17097c478bd9Sstevel@tonic-gate 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
17107c478bd9Sstevel@tonic-gate 					  h->h_field, (unsigned long) len);
17117c478bd9Sstevel@tonic-gate 				if (tTd(34, 11))
17127c478bd9Sstevel@tonic-gate 					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
17137c478bd9Sstevel@tonic-gate 						   h->h_field,
17147c478bd9Sstevel@tonic-gate 						   (unsigned long) len);
17157c478bd9Sstevel@tonic-gate 			}
17167c478bd9Sstevel@tonic-gate 		}
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 		if (MaxMimeHeaderLength > 0 &&
17197c478bd9Sstevel@tonic-gate 		    wordinclass(h->h_field,
17207c478bd9Sstevel@tonic-gate 				macid("{checkMIMETextHeaders}")))
17217c478bd9Sstevel@tonic-gate 		{
17227c478bd9Sstevel@tonic-gate 			size_t len;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 			len = strlen(h->h_value);
17257c478bd9Sstevel@tonic-gate 			if (len > (size_t) MaxMimeHeaderLength)
17267c478bd9Sstevel@tonic-gate 			{
17277c478bd9Sstevel@tonic-gate 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
17287c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ALERT, e->e_id,
17297c478bd9Sstevel@tonic-gate 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
17307c478bd9Sstevel@tonic-gate 					  h->h_field, (unsigned long) len);
17317c478bd9Sstevel@tonic-gate 				if (tTd(34, 11))
17327c478bd9Sstevel@tonic-gate 					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
17337c478bd9Sstevel@tonic-gate 						   h->h_field,
17347c478bd9Sstevel@tonic-gate 						   (unsigned long) len);
17357c478bd9Sstevel@tonic-gate 			}
17367c478bd9Sstevel@tonic-gate 		}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 		if (MaxMimeHeaderLength > 0 &&
17397c478bd9Sstevel@tonic-gate 		    wordinclass(h->h_field,
17407c478bd9Sstevel@tonic-gate 				macid("{checkMIMEHeaders}")))
17417c478bd9Sstevel@tonic-gate 		{
17427c478bd9Sstevel@tonic-gate 			size_t len;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 			len = strlen(h->h_value);
17457c478bd9Sstevel@tonic-gate 			if (shorten_rfc822_string(h->h_value,
17467c478bd9Sstevel@tonic-gate 						  MaxMimeHeaderLength))
17477c478bd9Sstevel@tonic-gate 			{
17487c478bd9Sstevel@tonic-gate 				if (len < MaxMimeHeaderLength)
17497c478bd9Sstevel@tonic-gate 				{
17507c478bd9Sstevel@tonic-gate 					/* we only rebalanced a bogus header */
17517c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ALERT, e->e_id,
17527c478bd9Sstevel@tonic-gate 						  "Fixed MIME %s header (possible attack)",
17537c478bd9Sstevel@tonic-gate 						  h->h_field);
17547c478bd9Sstevel@tonic-gate 					if (tTd(34, 11))
17557c478bd9Sstevel@tonic-gate 						sm_dprintf("  fixed MIME %s header (possible attack)\n",
17567c478bd9Sstevel@tonic-gate 							   h->h_field);
17577c478bd9Sstevel@tonic-gate 				}
17587c478bd9Sstevel@tonic-gate 				else
17597c478bd9Sstevel@tonic-gate 				{
17607c478bd9Sstevel@tonic-gate 					/* we actually shortened header */
17617c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ALERT, e->e_id,
17627c478bd9Sstevel@tonic-gate 						  "Truncated long MIME %s header (length = %ld) (possible attack)",
17637c478bd9Sstevel@tonic-gate 						  h->h_field,
17647c478bd9Sstevel@tonic-gate 						  (unsigned long) len);
17657c478bd9Sstevel@tonic-gate 					if (tTd(34, 11))
17667c478bd9Sstevel@tonic-gate 						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
17677c478bd9Sstevel@tonic-gate 							   h->h_field,
17687c478bd9Sstevel@tonic-gate 							   (unsigned long) len);
17697c478bd9Sstevel@tonic-gate 				}
17707c478bd9Sstevel@tonic-gate 			}
17717c478bd9Sstevel@tonic-gate 		}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 		/*
17747c478bd9Sstevel@tonic-gate 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
17757c478bd9Sstevel@tonic-gate 		**  and we are potentially converting from 8 bit to 7 bit
17767c478bd9Sstevel@tonic-gate 		**  MIME.  If converting, add a new CTE header in
17777c478bd9Sstevel@tonic-gate 		**  mime8to7().
17787c478bd9Sstevel@tonic-gate 		*/
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 		if (bitset(H_CTE, h->h_flags) &&
17817c478bd9Sstevel@tonic-gate 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
17827c478bd9Sstevel@tonic-gate 			   mci->mci_flags) &&
17837c478bd9Sstevel@tonic-gate 		    !bitset(M87F_NO8TO7, flags))
17847c478bd9Sstevel@tonic-gate 		{
17857c478bd9Sstevel@tonic-gate 			if (tTd(34, 11))
17867c478bd9Sstevel@tonic-gate 				sm_dprintf(" (skipped (content-transfer-encoding))\n");
17877c478bd9Sstevel@tonic-gate 			continue;
17887c478bd9Sstevel@tonic-gate 		}
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 		if (bitset(MCIF_INMIME, mci->mci_flags))
17917c478bd9Sstevel@tonic-gate 		{
17927c478bd9Sstevel@tonic-gate 			if (tTd(34, 11))
17937c478bd9Sstevel@tonic-gate 				sm_dprintf("\n");
1794445f2479Sjbeck 			if (!put_vanilla_header(h, p, mci))
1795445f2479Sjbeck 				goto writeerr;
17967c478bd9Sstevel@tonic-gate 			continue;
17977c478bd9Sstevel@tonic-gate 		}
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
18007c478bd9Sstevel@tonic-gate 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
18017c478bd9Sstevel@tonic-gate 		    (h->h_macro == '\0' ||
18027c478bd9Sstevel@tonic-gate 		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
18037c478bd9Sstevel@tonic-gate 		     *q == '\0'))
18047c478bd9Sstevel@tonic-gate 		{
18057c478bd9Sstevel@tonic-gate 			if (tTd(34, 11))
18067c478bd9Sstevel@tonic-gate 				sm_dprintf(" (skipped)\n");
18077c478bd9Sstevel@tonic-gate 			continue;
18087c478bd9Sstevel@tonic-gate 		}
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 		/* handle Resent-... headers specially */
18117c478bd9Sstevel@tonic-gate 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
18127c478bd9Sstevel@tonic-gate 		{
18137c478bd9Sstevel@tonic-gate 			if (tTd(34, 11))
18147c478bd9Sstevel@tonic-gate 				sm_dprintf(" (skipped (resent))\n");
18157c478bd9Sstevel@tonic-gate 			continue;
18167c478bd9Sstevel@tonic-gate 		}
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		/* suppress return receipts if requested */
18197c478bd9Sstevel@tonic-gate 		if (bitset(H_RECEIPTTO, h->h_flags) &&
18207c478bd9Sstevel@tonic-gate 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
18217c478bd9Sstevel@tonic-gate 		{
18227c478bd9Sstevel@tonic-gate 			if (tTd(34, 11))
18237c478bd9Sstevel@tonic-gate 				sm_dprintf(" (skipped (receipt))\n");
18247c478bd9Sstevel@tonic-gate 			continue;
18257c478bd9Sstevel@tonic-gate 		}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 		/* macro expand value if generated internally */
18287c478bd9Sstevel@tonic-gate 		if (bitset(H_DEFAULT, h->h_flags) ||
18297c478bd9Sstevel@tonic-gate 		    bitset(H_BINDLATE, h->h_flags))
18307c478bd9Sstevel@tonic-gate 		{
1831058561cbSjbeck 			expand(p, buf, sizeof(buf), e);
18327c478bd9Sstevel@tonic-gate 			p = buf;
18337c478bd9Sstevel@tonic-gate 			if (*p == '\0')
18347c478bd9Sstevel@tonic-gate 			{
18357c478bd9Sstevel@tonic-gate 				if (tTd(34, 11))
18367c478bd9Sstevel@tonic-gate 					sm_dprintf(" (skipped -- null value)\n");
18377c478bd9Sstevel@tonic-gate 				continue;
18387c478bd9Sstevel@tonic-gate 			}
18397c478bd9Sstevel@tonic-gate 		}
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		if (bitset(H_BCC, h->h_flags))
18427c478bd9Sstevel@tonic-gate 		{
18437c478bd9Sstevel@tonic-gate 			/* Bcc: field -- either truncate or delete */
18447c478bd9Sstevel@tonic-gate 			if (bitset(EF_DELETE_BCC, e->e_flags))
18457c478bd9Sstevel@tonic-gate 			{
18467c478bd9Sstevel@tonic-gate 				if (tTd(34, 11))
18477c478bd9Sstevel@tonic-gate 					sm_dprintf(" (skipped -- bcc)\n");
18487c478bd9Sstevel@tonic-gate 			}
18497c478bd9Sstevel@tonic-gate 			else
18507c478bd9Sstevel@tonic-gate 			{
18517c478bd9Sstevel@tonic-gate 				/* no other recipient headers: truncate value */
1852058561cbSjbeck 				(void) sm_strlcpyn(obuf, sizeof(obuf), 2,
18537c478bd9Sstevel@tonic-gate 						   h->h_field, ":");
1854445f2479Sjbeck 				if (!putline(obuf, mci))
1855445f2479Sjbeck 					goto writeerr;
18567c478bd9Sstevel@tonic-gate 			}
18577c478bd9Sstevel@tonic-gate 			continue;
18587c478bd9Sstevel@tonic-gate 		}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 		if (tTd(34, 11))
18617c478bd9Sstevel@tonic-gate 			sm_dprintf("\n");
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 		if (bitset(H_FROM|H_RCPT, h->h_flags))
18647c478bd9Sstevel@tonic-gate 		{
18657c478bd9Sstevel@tonic-gate 			/* address field */
18667c478bd9Sstevel@tonic-gate 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 			if (bitset(H_FROM, h->h_flags))
18697c478bd9Sstevel@tonic-gate 				oldstyle = false;
18707c478bd9Sstevel@tonic-gate 			commaize(h, p, oldstyle, mci, e);
18717c478bd9Sstevel@tonic-gate 		}
18727c478bd9Sstevel@tonic-gate 		else
18737c478bd9Sstevel@tonic-gate 		{
1874445f2479Sjbeck 			if (!put_vanilla_header(h, p, mci))
1875445f2479Sjbeck 				goto writeerr;
18767c478bd9Sstevel@tonic-gate 		}
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/*
18807c478bd9Sstevel@tonic-gate 	**  If we are converting this to a MIME message, add the
18817c478bd9Sstevel@tonic-gate 	**  MIME headers (but not in MIME mode!).
18827c478bd9Sstevel@tonic-gate 	*/
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate #if MIME8TO7
18857c478bd9Sstevel@tonic-gate 	if (bitset(MM_MIME8BIT, MimeMode) &&
18867c478bd9Sstevel@tonic-gate 	    bitset(EF_HAS8BIT, e->e_flags) &&
18877c478bd9Sstevel@tonic-gate 	    !bitset(EF_DONT_MIME, e->e_flags) &&
18887c478bd9Sstevel@tonic-gate 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
18897c478bd9Sstevel@tonic-gate 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
18907c478bd9Sstevel@tonic-gate 	    hvalue("MIME-Version", e->e_header) == NULL)
18917c478bd9Sstevel@tonic-gate 	{
1892445f2479Sjbeck 		if (!putline("MIME-Version: 1.0", mci))
1893445f2479Sjbeck 			goto writeerr;
18947c478bd9Sstevel@tonic-gate 		if (hvalue("Content-Type", e->e_header) == NULL)
18957c478bd9Sstevel@tonic-gate 		{
1896058561cbSjbeck 			(void) sm_snprintf(obuf, sizeof(obuf),
18977c478bd9Sstevel@tonic-gate 					"Content-Type: text/plain; charset=%s",
18987c478bd9Sstevel@tonic-gate 					defcharset(e));
1899445f2479Sjbeck 			if (!putline(obuf, mci))
1900445f2479Sjbeck 				goto writeerr;
19017c478bd9Sstevel@tonic-gate 		}
1902445f2479Sjbeck 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1903445f2479Sjbeck 		    && !putline("Content-Transfer-Encoding: 8bit", mci))
1904445f2479Sjbeck 			goto writeerr;
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */
1907445f2479Sjbeck 	return true;
1908445f2479Sjbeck 
1909445f2479Sjbeck   writeerr:
1910445f2479Sjbeck 	return false;
19117c478bd9Sstevel@tonic-gate }
1912058561cbSjbeck 
19137c478bd9Sstevel@tonic-gate /*
19147c478bd9Sstevel@tonic-gate **  PUT_VANILLA_HEADER -- output a fairly ordinary header
19157c478bd9Sstevel@tonic-gate **
19167c478bd9Sstevel@tonic-gate **	Parameters:
19177c478bd9Sstevel@tonic-gate **		h -- the structure describing this header
19187c478bd9Sstevel@tonic-gate **		v -- the value of this header
19197c478bd9Sstevel@tonic-gate **		mci -- the connection info for output
19207c478bd9Sstevel@tonic-gate **
19217c478bd9Sstevel@tonic-gate **	Returns:
19223ee0e492Sjbeck **		true iff header was written successfully
19237c478bd9Sstevel@tonic-gate */
19247c478bd9Sstevel@tonic-gate 
1925445f2479Sjbeck static bool
19267c478bd9Sstevel@tonic-gate put_vanilla_header(h, v, mci)
19277c478bd9Sstevel@tonic-gate 	HDR *h;
19287c478bd9Sstevel@tonic-gate 	char *v;
19297c478bd9Sstevel@tonic-gate 	MCI *mci;
19307c478bd9Sstevel@tonic-gate {
19317c478bd9Sstevel@tonic-gate 	register char *nlp;
19327c478bd9Sstevel@tonic-gate 	register char *obp;
19337c478bd9Sstevel@tonic-gate 	int putflags;
19347c478bd9Sstevel@tonic-gate 	char obuf[MAXLINE + 256];	/* additional length for h_field */
19357c478bd9Sstevel@tonic-gate 
1936058561cbSjbeck 	putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
19377c478bd9Sstevel@tonic-gate 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
19387c478bd9Sstevel@tonic-gate 		putflags |= PXLF_STRIP8BIT;
1939058561cbSjbeck 	(void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
19407c478bd9Sstevel@tonic-gate 	obp = obuf + strlen(obuf);
19417c478bd9Sstevel@tonic-gate 	while ((nlp = strchr(v, '\n')) != NULL)
19427c478bd9Sstevel@tonic-gate 	{
19437c478bd9Sstevel@tonic-gate 		int l;
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 		l = nlp - v;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 		/*
19487c478bd9Sstevel@tonic-gate 		**  XXX This is broken for SPACELEFT()==0
19497c478bd9Sstevel@tonic-gate 		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
19507c478bd9Sstevel@tonic-gate 		*/
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
19537c478bd9Sstevel@tonic-gate 			l = SPACELEFT(obuf, obp) - 1;
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1956445f2479Sjbeck 		if (!putxline(obuf, strlen(obuf), mci, putflags))
1957445f2479Sjbeck 			goto writeerr;
19587c478bd9Sstevel@tonic-gate 		v += l + 1;
19597c478bd9Sstevel@tonic-gate 		obp = obuf;
19607c478bd9Sstevel@tonic-gate 		if (*v != ' ' && *v != '\t')
19617c478bd9Sstevel@tonic-gate 			*obp++ = ' ';
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	/* XXX This is broken for SPACELEFT()==0 */
19657c478bd9Sstevel@tonic-gate 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
19667c478bd9Sstevel@tonic-gate 			   (int) (SPACELEFT(obuf, obp) - 1), v);
1967445f2479Sjbeck 	return putxline(obuf, strlen(obuf), mci, putflags);
1968445f2479Sjbeck 
1969445f2479Sjbeck   writeerr:
1970445f2479Sjbeck 	return false;
19717c478bd9Sstevel@tonic-gate }
1972058561cbSjbeck 
19737c478bd9Sstevel@tonic-gate /*
19747c478bd9Sstevel@tonic-gate **  COMMAIZE -- output a header field, making a comma-translated list.
19757c478bd9Sstevel@tonic-gate **
19767c478bd9Sstevel@tonic-gate **	Parameters:
19777c478bd9Sstevel@tonic-gate **		h -- the header field to output.
19787c478bd9Sstevel@tonic-gate **		p -- the value to put in it.
19797c478bd9Sstevel@tonic-gate **		oldstyle -- true if this is an old style header.
19807c478bd9Sstevel@tonic-gate **		mci -- the connection information.
19817c478bd9Sstevel@tonic-gate **		e -- the envelope containing the message.
19827c478bd9Sstevel@tonic-gate **
19837c478bd9Sstevel@tonic-gate **	Returns:
19843ee0e492Sjbeck **		true iff header field was written successfully
19857c478bd9Sstevel@tonic-gate **
19867c478bd9Sstevel@tonic-gate **	Side Effects:
1987058561cbSjbeck **		outputs "p" to "mci".
19887c478bd9Sstevel@tonic-gate */
19897c478bd9Sstevel@tonic-gate 
1990445f2479Sjbeck bool
19917c478bd9Sstevel@tonic-gate commaize(h, p, oldstyle, mci, e)
19927c478bd9Sstevel@tonic-gate 	register HDR *h;
19937c478bd9Sstevel@tonic-gate 	register char *p;
19947c478bd9Sstevel@tonic-gate 	bool oldstyle;
19957c478bd9Sstevel@tonic-gate 	register MCI *mci;
19967c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
19977c478bd9Sstevel@tonic-gate {
19987c478bd9Sstevel@tonic-gate 	register char *obp;
1999058561cbSjbeck 	int opos, omax, spaces;
20007c478bd9Sstevel@tonic-gate 	bool firstone = true;
2001058561cbSjbeck 	int putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
20027c478bd9Sstevel@tonic-gate 	char **res;
20037c478bd9Sstevel@tonic-gate 	char obuf[MAXLINE + 3];
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 	/*
20067c478bd9Sstevel@tonic-gate 	**  Output the address list translated by the
20077c478bd9Sstevel@tonic-gate 	**  mailer and with commas.
20087c478bd9Sstevel@tonic-gate 	*/
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 	if (tTd(14, 2))
20117c478bd9Sstevel@tonic-gate 		sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
20147c478bd9Sstevel@tonic-gate 		putflags |= PXLF_STRIP8BIT;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	obp = obuf;
2017058561cbSjbeck 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2018058561cbSjbeck 	/* opos = strlen(obp); instead of the next 3 lines? */
2019058561cbSjbeck 	opos = strlen(h->h_field) + 1;
2020058561cbSjbeck 	if (opos > 201)
2021058561cbSjbeck 		opos = 201;
20227c478bd9Sstevel@tonic-gate 	obp += opos;
2023058561cbSjbeck 
2024058561cbSjbeck 	spaces = 0;
2025058561cbSjbeck 	while (*p != '\0' && isascii(*p) && isspace(*p))
2026058561cbSjbeck 	{
2027058561cbSjbeck 		++spaces;
2028058561cbSjbeck 		++p;
2029058561cbSjbeck 	}
2030058561cbSjbeck 	if (spaces > 0)
2031058561cbSjbeck 	{
2032058561cbSjbeck 		SM_ASSERT(sizeof(obuf) > opos  * 2);
2033058561cbSjbeck 
2034058561cbSjbeck 		/*
2035058561cbSjbeck 		**  Restrict number of spaces to half the length of buffer
2036058561cbSjbeck 		**  so the header field body can be put in here too.
2037058561cbSjbeck 		**  Note: this is a hack...
2038058561cbSjbeck 		*/
2039058561cbSjbeck 
2040058561cbSjbeck 		if (spaces > sizeof(obuf) / 2)
2041058561cbSjbeck 			spaces = sizeof(obuf) / 2;
2042058561cbSjbeck 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2043058561cbSjbeck 				"");
2044058561cbSjbeck 		opos += spaces;
2045058561cbSjbeck 		obp += spaces;
2046058561cbSjbeck 		SM_ASSERT(obp < &obuf[MAXLINE]);
2047058561cbSjbeck 	}
2048058561cbSjbeck 
20497c478bd9Sstevel@tonic-gate 	omax = mci->mci_mailer->m_linelimit - 2;
20507c478bd9Sstevel@tonic-gate 	if (omax < 0 || omax > 78)
20517c478bd9Sstevel@tonic-gate 		omax = 78;
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	/*
20547c478bd9Sstevel@tonic-gate 	**  Run through the list of values.
20557c478bd9Sstevel@tonic-gate 	*/
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	while (*p != '\0')
20587c478bd9Sstevel@tonic-gate 	{
20597c478bd9Sstevel@tonic-gate 		register char *name;
20607c478bd9Sstevel@tonic-gate 		register int c;
20617c478bd9Sstevel@tonic-gate 		char savechar;
20627c478bd9Sstevel@tonic-gate 		int flags;
20637c478bd9Sstevel@tonic-gate 		auto int status;
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 		/*
20667c478bd9Sstevel@tonic-gate 		**  Find the end of the name.  New style names
20677c478bd9Sstevel@tonic-gate 		**  end with a comma, old style names end with
20687c478bd9Sstevel@tonic-gate 		**  a space character.  However, spaces do not
20697c478bd9Sstevel@tonic-gate 		**  necessarily delimit an old-style name -- at
20707c478bd9Sstevel@tonic-gate 		**  signs mean keep going.
20717c478bd9Sstevel@tonic-gate 		*/
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 		/* find end of name */
20747c478bd9Sstevel@tonic-gate 		while ((isascii(*p) && isspace(*p)) || *p == ',')
20757c478bd9Sstevel@tonic-gate 			p++;
20767c478bd9Sstevel@tonic-gate 		name = p;
20777c478bd9Sstevel@tonic-gate 		res = NULL;
20787c478bd9Sstevel@tonic-gate 		for (;;)
20797c478bd9Sstevel@tonic-gate 		{
20807c478bd9Sstevel@tonic-gate 			auto char *oldp;
20817c478bd9Sstevel@tonic-gate 			char pvpbuf[PSBUFSIZE];
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2084058561cbSjbeck 				      sizeof(pvpbuf), &oldp, ExtTokenTab, false);
20857c478bd9Sstevel@tonic-gate 			p = oldp;
20867c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_BOGUS_ADDR
20877c478bd9Sstevel@tonic-gate 			/* ignore addresses that can't be parsed */
20887c478bd9Sstevel@tonic-gate 			if (res == NULL)
20897c478bd9Sstevel@tonic-gate 			{
20907c478bd9Sstevel@tonic-gate 				name = p;
20917c478bd9Sstevel@tonic-gate 				continue;
20927c478bd9Sstevel@tonic-gate 			}
20937c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_BOGUS_ADDR */
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 			/* look to see if we have an at sign */
20967c478bd9Sstevel@tonic-gate 			while (*p != '\0' && isascii(*p) && isspace(*p))
20977c478bd9Sstevel@tonic-gate 				p++;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 			if (*p != '@')
21007c478bd9Sstevel@tonic-gate 			{
21017c478bd9Sstevel@tonic-gate 				p = oldp;
21027c478bd9Sstevel@tonic-gate 				break;
21037c478bd9Sstevel@tonic-gate 			}
21047c478bd9Sstevel@tonic-gate 			++p;
21057c478bd9Sstevel@tonic-gate 			while (*p != '\0' && isascii(*p) && isspace(*p))
21067c478bd9Sstevel@tonic-gate 				p++;
21077c478bd9Sstevel@tonic-gate 		}
21087c478bd9Sstevel@tonic-gate 		/* at the end of one complete name */
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 		/* strip off trailing white space */
21117c478bd9Sstevel@tonic-gate 		while (p >= name &&
21127c478bd9Sstevel@tonic-gate 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
21137c478bd9Sstevel@tonic-gate 			p--;
21147c478bd9Sstevel@tonic-gate 		if (++p == name)
21157c478bd9Sstevel@tonic-gate 			continue;
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 		/*
21187c478bd9Sstevel@tonic-gate 		**  if prescan() failed go a bit backwards; this is a hack,
21197c478bd9Sstevel@tonic-gate 		**  there should be some better error recovery.
21207c478bd9Sstevel@tonic-gate 		*/
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 		if (res == NULL && p > name &&
21237c478bd9Sstevel@tonic-gate 		    !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
21247c478bd9Sstevel@tonic-gate 			--p;
21257c478bd9Sstevel@tonic-gate 		savechar = *p;
21267c478bd9Sstevel@tonic-gate 		*p = '\0';
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 		/* translate the name to be relative */
21297c478bd9Sstevel@tonic-gate 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
21307c478bd9Sstevel@tonic-gate 		if (bitset(H_FROM, h->h_flags))
21317c478bd9Sstevel@tonic-gate 			flags |= RF_SENDERADDR;
21327c478bd9Sstevel@tonic-gate #if USERDB
21337c478bd9Sstevel@tonic-gate 		else if (e->e_from.q_mailer != NULL &&
21347c478bd9Sstevel@tonic-gate 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
21357c478bd9Sstevel@tonic-gate 		{
21367c478bd9Sstevel@tonic-gate 			char *q;
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 			q = udbsender(name, e->e_rpool);
21397c478bd9Sstevel@tonic-gate 			if (q != NULL)
21407c478bd9Sstevel@tonic-gate 				name = q;
21417c478bd9Sstevel@tonic-gate 		}
21427c478bd9Sstevel@tonic-gate #endif /* USERDB */
21437c478bd9Sstevel@tonic-gate 		status = EX_OK;
21447c478bd9Sstevel@tonic-gate 		name = remotename(name, mci->mci_mailer, flags, &status, e);
21457c478bd9Sstevel@tonic-gate 		if (*name == '\0')
21467c478bd9Sstevel@tonic-gate 		{
21477c478bd9Sstevel@tonic-gate 			*p = savechar;
21487c478bd9Sstevel@tonic-gate 			continue;
21497c478bd9Sstevel@tonic-gate 		}
21507c478bd9Sstevel@tonic-gate 		name = denlstring(name, false, true);
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 		/* output the name with nice formatting */
21537c478bd9Sstevel@tonic-gate 		opos += strlen(name);
21547c478bd9Sstevel@tonic-gate 		if (!firstone)
21557c478bd9Sstevel@tonic-gate 			opos += 2;
21567c478bd9Sstevel@tonic-gate 		if (opos > omax && !firstone)
21577c478bd9Sstevel@tonic-gate 		{
21587c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2159445f2479Sjbeck 			if (!putxline(obuf, strlen(obuf), mci, putflags))
2160445f2479Sjbeck 				goto writeerr;
21617c478bd9Sstevel@tonic-gate 			obp = obuf;
2162058561cbSjbeck 			(void) sm_strlcpy(obp, "        ", sizeof(obuf));
21637c478bd9Sstevel@tonic-gate 			opos = strlen(obp);
21647c478bd9Sstevel@tonic-gate 			obp += opos;
21657c478bd9Sstevel@tonic-gate 			opos += strlen(name);
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate 		else if (!firstone)
21687c478bd9Sstevel@tonic-gate 		{
21697c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
21707c478bd9Sstevel@tonic-gate 			obp += 2;
21717c478bd9Sstevel@tonic-gate 		}
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
21747c478bd9Sstevel@tonic-gate 			*obp++ = c;
21757c478bd9Sstevel@tonic-gate 		firstone = false;
21767c478bd9Sstevel@tonic-gate 		*p = savechar;
21777c478bd9Sstevel@tonic-gate 	}
2178058561cbSjbeck 	if (obp < &obuf[sizeof(obuf)])
21797c478bd9Sstevel@tonic-gate 		*obp = '\0';
21807c478bd9Sstevel@tonic-gate 	else
2181058561cbSjbeck 		obuf[sizeof(obuf) - 1] = '\0';
2182445f2479Sjbeck 	return putxline(obuf, strlen(obuf), mci, putflags);
2183445f2479Sjbeck 
2184445f2479Sjbeck   writeerr:
2185445f2479Sjbeck 	return false;
21867c478bd9Sstevel@tonic-gate }
2187445f2479Sjbeck 
21887c478bd9Sstevel@tonic-gate /*
21897c478bd9Sstevel@tonic-gate **  COPYHEADER -- copy header list
21907c478bd9Sstevel@tonic-gate **
21917c478bd9Sstevel@tonic-gate **	This routine is the equivalent of newstr for header lists
21927c478bd9Sstevel@tonic-gate **
21937c478bd9Sstevel@tonic-gate **	Parameters:
21947c478bd9Sstevel@tonic-gate **		header -- list of header structures to copy.
21957c478bd9Sstevel@tonic-gate **		rpool -- resource pool, or NULL
21967c478bd9Sstevel@tonic-gate **
21977c478bd9Sstevel@tonic-gate **	Returns:
21987c478bd9Sstevel@tonic-gate **		a copy of 'header'.
21997c478bd9Sstevel@tonic-gate **
22007c478bd9Sstevel@tonic-gate **	Side Effects:
22017c478bd9Sstevel@tonic-gate **		none.
22027c478bd9Sstevel@tonic-gate */
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate HDR *
22057c478bd9Sstevel@tonic-gate copyheader(header, rpool)
22067c478bd9Sstevel@tonic-gate 	register HDR *header;
22077c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
22087c478bd9Sstevel@tonic-gate {
22097c478bd9Sstevel@tonic-gate 	register HDR *newhdr;
22107c478bd9Sstevel@tonic-gate 	HDR *ret;
22117c478bd9Sstevel@tonic-gate 	register HDR **tail = &ret;
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	while (header != NULL)
22147c478bd9Sstevel@tonic-gate 	{
2215058561cbSjbeck 		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
22167c478bd9Sstevel@tonic-gate 		STRUCTCOPY(*header, *newhdr);
22177c478bd9Sstevel@tonic-gate 		*tail = newhdr;
22187c478bd9Sstevel@tonic-gate 		tail = &newhdr->h_link;
22197c478bd9Sstevel@tonic-gate 		header = header->h_link;
22207c478bd9Sstevel@tonic-gate 	}
22217c478bd9Sstevel@tonic-gate 	*tail = NULL;
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	return ret;
22247c478bd9Sstevel@tonic-gate }
2225058561cbSjbeck 
22267c478bd9Sstevel@tonic-gate /*
22277c478bd9Sstevel@tonic-gate **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
22287c478bd9Sstevel@tonic-gate **
22297c478bd9Sstevel@tonic-gate **	Run through all of the parameters of a MIME header and
22307c478bd9Sstevel@tonic-gate **	possibly truncate and rebalance the parameter according
22317c478bd9Sstevel@tonic-gate **	to MaxMimeFieldLength.
22327c478bd9Sstevel@tonic-gate **
22337c478bd9Sstevel@tonic-gate **	Parameters:
22347c478bd9Sstevel@tonic-gate **		h -- the header to truncate/rebalance
22357c478bd9Sstevel@tonic-gate **		e -- the current envelope
22367c478bd9Sstevel@tonic-gate **
22377c478bd9Sstevel@tonic-gate **	Returns:
22387c478bd9Sstevel@tonic-gate **		length of last offending field, 0 if all ok.
22397c478bd9Sstevel@tonic-gate **
22407c478bd9Sstevel@tonic-gate **	Side Effects:
22417c478bd9Sstevel@tonic-gate **		string modified in place
22427c478bd9Sstevel@tonic-gate */
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate static size_t
22457c478bd9Sstevel@tonic-gate fix_mime_header(h, e)
22467c478bd9Sstevel@tonic-gate 	HDR *h;
22477c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
22487c478bd9Sstevel@tonic-gate {
22497c478bd9Sstevel@tonic-gate 	char *begin = h->h_value;
22507c478bd9Sstevel@tonic-gate 	char *end;
22517c478bd9Sstevel@tonic-gate 	size_t len = 0;
22527c478bd9Sstevel@tonic-gate 	size_t retlen = 0;
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	if (begin == NULL || *begin == '\0')
22557c478bd9Sstevel@tonic-gate 		return 0;
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	/* Split on each ';' */
22587c478bd9Sstevel@tonic-gate 	/* find_character() never returns NULL */
22597c478bd9Sstevel@tonic-gate 	while ((end = find_character(begin, ';')) != NULL)
22607c478bd9Sstevel@tonic-gate 	{
22617c478bd9Sstevel@tonic-gate 		char save = *end;
22627c478bd9Sstevel@tonic-gate 		char *bp;
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate 		*end = '\0';
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 		len = strlen(begin);
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 		/* Shorten individual parameter */
22697c478bd9Sstevel@tonic-gate 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
22707c478bd9Sstevel@tonic-gate 		{
22717c478bd9Sstevel@tonic-gate 			if (len < MaxMimeFieldLength)
22727c478bd9Sstevel@tonic-gate 			{
22737c478bd9Sstevel@tonic-gate 				/* we only rebalanced a bogus field */
22747c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ALERT, e->e_id,
22757c478bd9Sstevel@tonic-gate 					  "Fixed MIME %s header field (possible attack)",
22767c478bd9Sstevel@tonic-gate 					  h->h_field);
22777c478bd9Sstevel@tonic-gate 				if (tTd(34, 11))
22787c478bd9Sstevel@tonic-gate 					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
22797c478bd9Sstevel@tonic-gate 						   h->h_field);
22807c478bd9Sstevel@tonic-gate 			}
22817c478bd9Sstevel@tonic-gate 			else
22827c478bd9Sstevel@tonic-gate 			{
22837c478bd9Sstevel@tonic-gate 				/* we actually shortened the header */
22847c478bd9Sstevel@tonic-gate 				retlen = len;
22857c478bd9Sstevel@tonic-gate 			}
22867c478bd9Sstevel@tonic-gate 		}
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 		/* Collapse the possibly shortened string with rest */
22897c478bd9Sstevel@tonic-gate 		bp = begin + strlen(begin);
22907c478bd9Sstevel@tonic-gate 		if (bp != end)
22917c478bd9Sstevel@tonic-gate 		{
22927c478bd9Sstevel@tonic-gate 			char *ep = end;
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 			*end = save;
22957c478bd9Sstevel@tonic-gate 			end = bp;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 			/* copy character by character due to overlap */
22987c478bd9Sstevel@tonic-gate 			while (*ep != '\0')
22997c478bd9Sstevel@tonic-gate 				*bp++ = *ep++;
23007c478bd9Sstevel@tonic-gate 			*bp = '\0';
23017c478bd9Sstevel@tonic-gate 		}
23027c478bd9Sstevel@tonic-gate 		else
23037c478bd9Sstevel@tonic-gate 			*end = save;
23047c478bd9Sstevel@tonic-gate 		if (*end == '\0')
23057c478bd9Sstevel@tonic-gate 			break;
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 		/* Move past ';' */
23087c478bd9Sstevel@tonic-gate 		begin = end + 1;
23097c478bd9Sstevel@tonic-gate 	}
23107c478bd9Sstevel@tonic-gate 	return retlen;
23117c478bd9Sstevel@tonic-gate }
2312