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