138032Speter/*
2168520Sgshapiro * Copyright (c) 1998-2004, 2006, 2007 Sendmail, Inc. and its suppliers.
364565Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1490795Sgshapiro#include <sendmail.h>
15168520Sgshapiro#include <sm/sendmail.h>
1638032Speter
17244833SgshapiroSM_RCSID("@(#)$Id: headers.c,v 8.318 2012/06/14 23:54:02 ca Exp $")
1864565Sgshapiro
19168520Sgshapirostatic HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *, bool));
20111826Sgshapirostatic size_t	fix_mime_header __P((HDR *, ENVELOPE *));
2164565Sgshapirostatic int	priencode __P((char *));
22157006Sgshapirostatic bool	put_vanilla_header __P((HDR *, char *, MCI *));
2364565Sgshapiro
2438032Speter/*
2538032Speter**  SETUPHEADERS -- initialize headers in symbol table
2638032Speter**
2738032Speter**	Parameters:
2838032Speter**		none
2938032Speter**
3038032Speter**	Returns:
3138032Speter**		none
3238032Speter*/
3338032Speter
3438032Spetervoid
3538032Spetersetupheaders()
3638032Speter{
3738032Speter	struct hdrinfo *hi;
3838032Speter	STAB *s;
3938032Speter
4038032Speter	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
4138032Speter	{
4238032Speter		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
4338032Speter		s->s_header.hi_flags = hi->hi_flags;
4438032Speter		s->s_header.hi_ruleset = NULL;
4538032Speter	}
4638032Speter}
47168520Sgshapiro
4890795Sgshapiro/*
49168520Sgshapiro**  DOCHOMPHEADER -- process and save a header line.
5038032Speter**
51168520Sgshapiro**	Called by chompheader.
5238032Speter**
5338032Speter**	Parameters:
5438032Speter**		line -- header as a text line.
5566497Sgshapiro**		pflag -- flags for chompheader() (from sendmail.h)
5638032Speter**		hdrp -- a pointer to the place to save the header.
5738032Speter**		e -- the envelope including this header.
5838032Speter**
5938032Speter**	Returns:
6038032Speter**		flags for this header.
6138032Speter**
6238032Speter**	Side Effects:
6338032Speter**		The header is saved on the header list.
6438032Speter**		Contents of 'line' are destroyed.
6538032Speter*/
6638032Speter
6764565Sgshapirostatic struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
68168520Sgshapirostatic unsigned long	dochompheader __P((char *, int, HDR **, ENVELOPE *));
6938032Speter
70168520Sgshapirostatic unsigned long
71168520Sgshapirodochompheader(line, pflag, hdrp, e)
7238032Speter	char *line;
7364565Sgshapiro	int pflag;
7438032Speter	HDR **hdrp;
75168520Sgshapiro	ENVELOPE *e;
7638032Speter{
7790795Sgshapiro	unsigned char mid = '\0';
7838032Speter	register char *p;
7938032Speter	register HDR *h;
8038032Speter	HDR **hp;
8138032Speter	char *fname;
8238032Speter	char *fvalue;
8390795Sgshapiro	bool cond = false;
8464565Sgshapiro	bool dropfrom;
8538032Speter	bool headeronly;
8638032Speter	STAB *s;
8738032Speter	struct hdrinfo *hi;
8890795Sgshapiro	bool nullheader = false;
8964565Sgshapiro	BITMAP256 mopts;
9038032Speter
9138032Speter	headeronly = hdrp != NULL;
9238032Speter	if (!headeronly)
9338032Speter		hdrp = &e->e_header;
9438032Speter
9538032Speter	/* strip off options */
9638032Speter	clrbitmap(mopts);
9738032Speter	p = line;
9864565Sgshapiro	if (!bitset(pflag, CHHDR_USER) && *p == '?')
9938032Speter	{
10064565Sgshapiro		int c;
10164565Sgshapiro		register char *q;
10264565Sgshapiro
10364565Sgshapiro		q = strchr(++p, '?');
10464565Sgshapiro		if (q == NULL)
10564565Sgshapiro			goto hse;
10664565Sgshapiro
10764565Sgshapiro		*q = '\0';
10864565Sgshapiro		c = *p & 0377;
10964565Sgshapiro
11064565Sgshapiro		/* possibly macro conditional */
11164565Sgshapiro		if (c == MACROEXPAND)
11238032Speter		{
11364565Sgshapiro			/* catch ?$? */
11464565Sgshapiro			if (*++p == '\0')
11564565Sgshapiro			{
11664565Sgshapiro				*q = '?';
11764565Sgshapiro				goto hse;
11864565Sgshapiro			}
11964565Sgshapiro
12090795Sgshapiro			mid = (unsigned char) *p++;
12164565Sgshapiro
12264565Sgshapiro			/* catch ?$abc? */
12364565Sgshapiro			if (*p != '\0')
12464565Sgshapiro			{
12564565Sgshapiro				*q = '?';
12664565Sgshapiro				goto hse;
12764565Sgshapiro			}
12864565Sgshapiro		}
12964565Sgshapiro		else if (*p == '$')
13064565Sgshapiro		{
13164565Sgshapiro			/* catch ?$? */
13264565Sgshapiro			if (*++p == '\0')
13364565Sgshapiro			{
13464565Sgshapiro				*q = '?';
13564565Sgshapiro				goto hse;
13664565Sgshapiro			}
13764565Sgshapiro
13890795Sgshapiro			mid = (unsigned char) macid(p);
13964565Sgshapiro			if (bitset(0200, mid))
140120259Sgshapiro			{
14164565Sgshapiro				p += strlen(macname(mid)) + 2;
142120259Sgshapiro				SM_ASSERT(p <= q);
143120259Sgshapiro			}
14464565Sgshapiro			else
14564565Sgshapiro				p++;
14664565Sgshapiro
14764565Sgshapiro			/* catch ?$abc? */
14864565Sgshapiro			if (*p != '\0')
14964565Sgshapiro			{
15064565Sgshapiro				*q = '?';
15164565Sgshapiro				goto hse;
15264565Sgshapiro			}
15364565Sgshapiro		}
15464565Sgshapiro		else
15564565Sgshapiro		{
15664565Sgshapiro			while (*p != '\0')
15764565Sgshapiro			{
15864565Sgshapiro				if (!isascii(*p))
15964565Sgshapiro				{
16064565Sgshapiro					*q = '?';
16164565Sgshapiro					goto hse;
16264565Sgshapiro				}
16364565Sgshapiro
16471348Sgshapiro				setbitn(bitidx(*p), mopts);
16590795Sgshapiro				cond = true;
16664565Sgshapiro				p++;
16764565Sgshapiro			}
16838032Speter		}
16964565Sgshapiro		p = q + 1;
17038032Speter	}
17138032Speter
17238032Speter	/* find canonical name */
17338032Speter	fname = p;
17438032Speter	while (isascii(*p) && isgraph(*p) && *p != ':')
17538032Speter		p++;
17638032Speter	fvalue = p;
17738032Speter	while (isascii(*p) && isspace(*p))
17838032Speter		p++;
17938032Speter	if (*p++ != ':' || fname == fvalue)
18038032Speter	{
18164565Sgshapirohse:
18264565Sgshapiro		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
18338032Speter		return 0;
18438032Speter	}
18538032Speter	*fvalue = '\0';
18643733Speter	fvalue = p;
18738032Speter
18843733Speter	/* if the field is null, go ahead and use the default */
18943733Speter	while (isascii(*p) && isspace(*p))
19043733Speter		p++;
19143733Speter	if (*p == '\0')
19290795Sgshapiro		nullheader = true;
19343733Speter
19438032Speter	/* security scan: long field names are end-of-header */
19538032Speter	if (strlen(fname) > 100)
19638032Speter		return H_EOH;
19738032Speter
19838032Speter	/* check to see if it represents a ruleset call */
19964565Sgshapiro	if (bitset(pflag, CHHDR_DEF))
20038032Speter	{
20138032Speter		char hbuf[50];
20238032Speter
203168520Sgshapiro		(void) expand(fvalue, hbuf, sizeof(hbuf), e);
20438032Speter		for (p = hbuf; isascii(*p) && isspace(*p); )
20538032Speter			p++;
20638032Speter		if ((*p++ & 0377) == CALLSUBR)
20738032Speter		{
20838032Speter			auto char *endp;
20964565Sgshapiro			bool strc;
21038032Speter
21164565Sgshapiro			strc = *p == '+';	/* strip comments? */
21264565Sgshapiro			if (strc)
21364565Sgshapiro				++p;
21438032Speter			if (strtorwset(p, &endp, ST_ENTER) > 0)
21538032Speter			{
21638032Speter				*endp = '\0';
21738032Speter				s = stab(fname, ST_HEADER, ST_ENTER);
21890795Sgshapiro				if (LogLevel > 9 &&
21990795Sgshapiro				    s->s_header.hi_ruleset != NULL)
22090795Sgshapiro					sm_syslog(LOG_WARNING, NOQID,
22190795Sgshapiro						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
22290795Sgshapiro						  fname,
22390795Sgshapiro						  s->s_header.hi_ruleset, p);
22438032Speter				s->s_header.hi_ruleset = newstr(p);
22564565Sgshapiro				if (!strc)
22664565Sgshapiro					s->s_header.hi_flags |= H_STRIPCOMM;
22738032Speter			}
22838032Speter			return 0;
22938032Speter		}
23038032Speter	}
23138032Speter
23238032Speter	/* see if it is a known type */
23338032Speter	s = stab(fname, ST_HEADER, ST_FIND);
23438032Speter	if (s != NULL)
23538032Speter		hi = &s->s_header;
23638032Speter	else
23738032Speter		hi = &NormalHeader;
23838032Speter
23938032Speter	if (tTd(31, 9))
24038032Speter	{
24138032Speter		if (s == NULL)
24290795Sgshapiro			sm_dprintf("no header flags match\n");
24338032Speter		else
24490795Sgshapiro			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
24590795Sgshapiro				   hi->hi_flags,
24690795Sgshapiro				   hi->hi_ruleset == NULL ? "<NULL>"
24790795Sgshapiro							  : hi->hi_ruleset);
24838032Speter	}
24938032Speter
25038032Speter	/* see if this is a resent message */
25164565Sgshapiro	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
25264565Sgshapiro	    bitset(H_RESENT, hi->hi_flags))
25338032Speter		e->e_flags |= EF_RESENT;
25438032Speter
25538032Speter	/* if this is an Errors-To: header keep track of it now */
25664565Sgshapiro	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
25738032Speter	    bitset(H_ERRORSTO, hi->hi_flags))
25838032Speter		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
25938032Speter
26038032Speter	/* if this means "end of header" quit now */
26138032Speter	if (!headeronly && bitset(H_EOH, hi->hi_flags))
26238032Speter		return hi->hi_flags;
26338032Speter
26438032Speter	/*
26538032Speter	**  Horrible hack to work around problem with Lotus Notes SMTP
26638032Speter	**  mail gateway, which generates From: headers with newlines in
26738032Speter	**  them and the <address> on the second line.  Although this is
26838032Speter	**  legal RFC 822, many MUAs don't handle this properly and thus
26938032Speter	**  never find the actual address.
27038032Speter	*/
27138032Speter
27238032Speter	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
27338032Speter	{
27438032Speter		while ((p = strchr(fvalue, '\n')) != NULL)
27538032Speter			*p = ' ';
27638032Speter	}
27738032Speter
27838032Speter	/*
27938032Speter	**  If there is a check ruleset, verify it against the header.
28038032Speter	*/
28138032Speter
28264565Sgshapiro	if (bitset(pflag, CHHDR_CHECK))
28364565Sgshapiro	{
284102531Sgshapiro		int rscheckflags;
28564565Sgshapiro		char *rs;
28638032Speter
287102531Sgshapiro		rscheckflags = RSF_COUNT;
288102531Sgshapiro		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
289102531Sgshapiro			rscheckflags |= RSF_UNSTRUCTURED;
290132946Sgshapiro
291132946Sgshapiro		/* no ruleset? look for default */
292132946Sgshapiro		rs = hi->hi_ruleset;
29364565Sgshapiro		if (rs == NULL)
29464565Sgshapiro		{
29564565Sgshapiro			s = stab("*", ST_HEADER, ST_FIND);
29664565Sgshapiro			if (s != NULL)
29764565Sgshapiro			{
29864565Sgshapiro				rs = (&s->s_header)->hi_ruleset;
299102531Sgshapiro				if (bitset((&s->s_header)->hi_flags,
300102531Sgshapiro					   H_STRIPCOMM))
301102531Sgshapiro					rscheckflags |= RSF_RMCOMM;
30264565Sgshapiro			}
30364565Sgshapiro		}
304102531Sgshapiro		else if (bitset(hi->hi_flags, H_STRIPCOMM))
305102531Sgshapiro			rscheckflags |= RSF_RMCOMM;
30664565Sgshapiro		if (rs != NULL)
30764565Sgshapiro		{
30890795Sgshapiro			int l, k;
30964565Sgshapiro			char qval[MAXNAME];
31064565Sgshapiro
31164565Sgshapiro			l = 0;
31290795Sgshapiro			qval[l++] = '"';
31390795Sgshapiro
31490795Sgshapiro			/* - 3 to avoid problems with " at the end */
315120259Sgshapiro			/* should be sizeof(qval), not MAXNAME */
31690795Sgshapiro			for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
31764565Sgshapiro			{
31890795Sgshapiro				switch (fvalue[k])
31964565Sgshapiro				{
32090795Sgshapiro				  /* XXX other control chars? */
32164565Sgshapiro				  case '\011': /* ht */
32264565Sgshapiro				  case '\012': /* nl */
32364565Sgshapiro				  case '\013': /* vt */
32464565Sgshapiro				  case '\014': /* np */
32564565Sgshapiro				  case '\015': /* cr */
32690795Sgshapiro					qval[l++] = ' ';
32764565Sgshapiro					break;
32864565Sgshapiro				  case '"':
32990795Sgshapiro					qval[l++] = '\\';
33064565Sgshapiro					/* FALLTHROUGH */
33164565Sgshapiro				  default:
33290795Sgshapiro					qval[l++] = fvalue[k];
33364565Sgshapiro					break;
33464565Sgshapiro				}
33564565Sgshapiro			}
33690795Sgshapiro			qval[l++] = '"';
33790795Sgshapiro			qval[l] = '\0';
33890795Sgshapiro			k += strlen(fvalue + k);
33990795Sgshapiro			if (k >= MAXNAME)
34064565Sgshapiro			{
34164565Sgshapiro				if (LogLevel > 9)
34264565Sgshapiro					sm_syslog(LOG_WARNING, e->e_id,
34364565Sgshapiro						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
34490795Sgshapiro						  fname, rs, k, MAXNAME - 1);
34564565Sgshapiro			}
34690795Sgshapiro			macdefine(&e->e_macro, A_TEMP,
34790795Sgshapiro				macid("{currHeader}"), qval);
34890795Sgshapiro			macdefine(&e->e_macro, A_TEMP,
34990795Sgshapiro				macid("{hdr_name}"), fname);
35090795Sgshapiro
351168520Sgshapiro			(void) sm_snprintf(qval, sizeof(qval), "%d", k);
35290795Sgshapiro			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
353132946Sgshapiro			if (bitset(H_FROM, hi->hi_flags))
35490795Sgshapiro				macdefine(&e->e_macro, A_PERM,
35590795Sgshapiro					macid("{addr_type}"), "h s");
356132946Sgshapiro			else if (bitset(H_RCPT, hi->hi_flags))
35790795Sgshapiro				macdefine(&e->e_macro, A_PERM,
35890795Sgshapiro					macid("{addr_type}"), "h r");
35990795Sgshapiro			else
36090795Sgshapiro				macdefine(&e->e_macro, A_PERM,
36190795Sgshapiro					macid("{addr_type}"), "h");
362102531Sgshapiro			(void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
363168520Sgshapiro				       NULL, e->e_id, NULL);
36464565Sgshapiro		}
36564565Sgshapiro	}
36664565Sgshapiro
36738032Speter	/*
36838032Speter	**  Drop explicit From: if same as what we would generate.
36938032Speter	**  This is to make MH (which doesn't always give a full name)
37038032Speter	**  insert the full name information in all circumstances.
37138032Speter	*/
37238032Speter
37390795Sgshapiro	dropfrom = false;
37438032Speter	p = "resent-from";
37538032Speter	if (!bitset(EF_RESENT, e->e_flags))
37638032Speter		p += 7;
37764565Sgshapiro	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
37890795Sgshapiro	    !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
37938032Speter	{
38038032Speter		if (tTd(31, 2))
38138032Speter		{
38290795Sgshapiro			sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
38338032Speter				fvalue, e->e_from.q_paddr, e->e_from.q_user);
38438032Speter		}
38538032Speter		if (e->e_from.q_paddr != NULL &&
38664565Sgshapiro		    e->e_from.q_mailer != NULL &&
38764565Sgshapiro		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
38838032Speter		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
38938032Speter		     strcmp(fvalue, e->e_from.q_user) == 0))
39090795Sgshapiro			dropfrom = true;
39138032Speter	}
39238032Speter
39338032Speter	/* delete default value for this header */
39438032Speter	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
39538032Speter	{
39690795Sgshapiro		if (sm_strcasecmp(fname, h->h_field) == 0 &&
39764565Sgshapiro		    !bitset(H_USER, h->h_flags) &&
39838032Speter		    !bitset(H_FORCE, h->h_flags))
39938032Speter		{
40043733Speter			if (nullheader)
40143733Speter			{
40243733Speter				/* user-supplied value was null */
40343733Speter				return 0;
40443733Speter			}
40564565Sgshapiro			if (dropfrom)
40664565Sgshapiro			{
40764565Sgshapiro				/* make this look like the user entered it */
40864565Sgshapiro				h->h_flags |= H_USER;
40964565Sgshapiro				return hi->hi_flags;
41064565Sgshapiro			}
41138032Speter			h->h_value = NULL;
41238032Speter			if (!cond)
41338032Speter			{
41438032Speter				/* copy conditions from default case */
41590795Sgshapiro				memmove((char *) mopts, (char *) h->h_mflags,
416168520Sgshapiro					sizeof(mopts));
41738032Speter			}
41864565Sgshapiro			h->h_macro = mid;
41938032Speter		}
42038032Speter	}
42138032Speter
42238032Speter	/* create a new node */
423168520Sgshapiro	h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h));
42490795Sgshapiro	h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
42590795Sgshapiro	h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
42638032Speter	h->h_link = NULL;
427168520Sgshapiro	memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
42864565Sgshapiro	h->h_macro = mid;
42938032Speter	*hp = h;
43038032Speter	h->h_flags = hi->hi_flags;
43166497Sgshapiro	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
43264565Sgshapiro		h->h_flags |= H_USER;
43338032Speter
43438032Speter	/* strip EOH flag if parsing MIME headers */
43538032Speter	if (headeronly)
43638032Speter		h->h_flags &= ~H_EOH;
43764565Sgshapiro	if (bitset(pflag, CHHDR_DEF))
43838032Speter		h->h_flags |= H_DEFAULT;
43964565Sgshapiro	if (cond || mid != '\0')
44038032Speter		h->h_flags |= H_CHECK;
44138032Speter
44238032Speter	/* hack to see if this is a new format message */
44364565Sgshapiro	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
44464565Sgshapiro	    bitset(H_RCPT|H_FROM, h->h_flags) &&
44538032Speter	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
44638032Speter	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
44738032Speter	{
44838032Speter		e->e_flags &= ~EF_OLDSTYLE;
44938032Speter	}
45038032Speter
45138032Speter	return h->h_flags;
45238032Speter}
453168520Sgshapiro
45490795Sgshapiro/*
455168520Sgshapiro**  CHOMPHEADER -- process and save a header line.
456168520Sgshapiro**
457168520Sgshapiro**	Called by collect, readcf, and readqf to deal with header lines.
458168520Sgshapiro**	This is just a wrapper for dochompheader().
459168520Sgshapiro**
460168520Sgshapiro**	Parameters:
461168520Sgshapiro**		line -- header as a text line.
462168520Sgshapiro**		pflag -- flags for chompheader() (from sendmail.h)
463168520Sgshapiro**		hdrp -- a pointer to the place to save the header.
464168520Sgshapiro**		e -- the envelope including this header.
465168520Sgshapiro**
466168520Sgshapiro**	Returns:
467168520Sgshapiro**		flags for this header.
468168520Sgshapiro**
469168520Sgshapiro**	Side Effects:
470168520Sgshapiro**		The header is saved on the header list.
471168520Sgshapiro**		Contents of 'line' are destroyed.
472168520Sgshapiro*/
473168520Sgshapiro
474168520Sgshapiro
475168520Sgshapirounsigned long
476168520Sgshapirochompheader(line, pflag, hdrp, e)
477168520Sgshapiro	char *line;
478168520Sgshapiro	int pflag;
479168520Sgshapiro	HDR **hdrp;
480168520Sgshapiro	register ENVELOPE *e;
481168520Sgshapiro{
482168520Sgshapiro	unsigned long rval;
483168520Sgshapiro
484168520Sgshapiro	if (tTd(31, 6))
485168520Sgshapiro	{
486168520Sgshapiro		sm_dprintf("chompheader: ");
487168520Sgshapiro		xputs(sm_debug_file(), line);
488168520Sgshapiro		sm_dprintf("\n");
489168520Sgshapiro	}
490168520Sgshapiro
491168520Sgshapiro	/* quote this if user (not config file) input */
492168520Sgshapiro	if (bitset(pflag, CHHDR_USER))
493168520Sgshapiro	{
494168520Sgshapiro		char xbuf[MAXLINE];
495168520Sgshapiro		char *xbp = NULL;
496168520Sgshapiro		int xbufs;
497168520Sgshapiro
498168520Sgshapiro		xbufs = sizeof(xbuf);
499168520Sgshapiro		xbp = quote_internal_chars(line, xbuf, &xbufs);
500168520Sgshapiro		if (tTd(31, 7))
501168520Sgshapiro		{
502168520Sgshapiro			sm_dprintf("chompheader: quoted: ");
503168520Sgshapiro			xputs(sm_debug_file(), xbp);
504168520Sgshapiro			sm_dprintf("\n");
505168520Sgshapiro		}
506168520Sgshapiro		rval = dochompheader(xbp, pflag, hdrp, e);
507168520Sgshapiro		if (xbp != xbuf)
508168520Sgshapiro			sm_free(xbp);
509168520Sgshapiro	}
510168520Sgshapiro	else
511168520Sgshapiro		rval = dochompheader(line, pflag, hdrp, e);
512168520Sgshapiro
513168520Sgshapiro	return rval;
514168520Sgshapiro}
515168520Sgshapiro
516168520Sgshapiro/*
517132946Sgshapiro**  ALLOCHEADER -- allocate a header entry
518132946Sgshapiro**
519132946Sgshapiro**	Parameters:
520168520Sgshapiro**		field -- the name of the header field (will not be copied).
521168520Sgshapiro**		value -- the value of the field (will be copied).
522132946Sgshapiro**		flags -- flags to add to h_flags.
523132946Sgshapiro**		rp -- resource pool for allocations
524168520Sgshapiro**		space -- add leading space?
525132946Sgshapiro**
526132946Sgshapiro**	Returns:
527132946Sgshapiro**		Pointer to a newly allocated and populated HDR.
528168520Sgshapiro**
529168520Sgshapiro**	Notes:
530168520Sgshapiro**		o field and value must be in internal format, i.e.,
531168520Sgshapiro**		metacharacters must be "quoted", see quote_internal_chars().
532168520Sgshapiro**		o maybe add more flags to decide:
533168520Sgshapiro**		  - what to copy (field/value)
534168520Sgshapiro**		  - whether to convert value to an internal format
535132946Sgshapiro*/
536132946Sgshapiro
537132946Sgshapirostatic HDR *
538168520Sgshapiroallocheader(field, value, flags, rp, space)
539132946Sgshapiro	char *field;
540132946Sgshapiro	char *value;
541132946Sgshapiro	int flags;
542132946Sgshapiro	SM_RPOOL_T *rp;
543168520Sgshapiro	bool space;
544132946Sgshapiro{
545132946Sgshapiro	HDR *h;
546132946Sgshapiro	STAB *s;
547132946Sgshapiro
548132946Sgshapiro	/* find info struct */
549132946Sgshapiro	s = stab(field, ST_HEADER, ST_FIND);
550132946Sgshapiro
551132946Sgshapiro	/* allocate space for new header */
552168520Sgshapiro	h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
553132946Sgshapiro	h->h_field = field;
554168520Sgshapiro	if (space)
555168520Sgshapiro	{
556168520Sgshapiro		size_t l;
557168520Sgshapiro		char *n;
558168520Sgshapiro
559168520Sgshapiro		l = strlen(value);
560168520Sgshapiro		SM_ASSERT(l + 2 > l);
561168520Sgshapiro		n = sm_rpool_malloc_x(rp, l + 2);
562168520Sgshapiro		n[0] = ' ';
563168520Sgshapiro		n[1] = '\0';
564168520Sgshapiro		sm_strlcpy(n + 1, value, l + 1);
565168520Sgshapiro		h->h_value = n;
566168520Sgshapiro	}
567168520Sgshapiro	else
568168520Sgshapiro		h->h_value = sm_rpool_strdup_x(rp, value);
569132946Sgshapiro	h->h_flags = flags;
570132946Sgshapiro	if (s != NULL)
571132946Sgshapiro		h->h_flags |= s->s_header.hi_flags;
572132946Sgshapiro	clrbitmap(h->h_mflags);
573132946Sgshapiro	h->h_macro = '\0';
574132946Sgshapiro
575132946Sgshapiro	return h;
576132946Sgshapiro}
577168520Sgshapiro
578132946Sgshapiro/*
57938032Speter**  ADDHEADER -- add a header entry to the end of the queue.
58038032Speter**
58138032Speter**	This bypasses the special checking of chompheader.
58238032Speter**
58338032Speter**	Parameters:
584168520Sgshapiro**		field -- the name of the header field (will not be copied).
585168520Sgshapiro**		value -- the value of the field (will be copied).
58664565Sgshapiro**		flags -- flags to add to h_flags.
58790795Sgshapiro**		e -- envelope.
588168520Sgshapiro**		space -- add leading space?
58938032Speter**
59038032Speter**	Returns:
59138032Speter**		none.
59238032Speter**
59338032Speter**	Side Effects:
59438032Speter**		adds the field on the list of headers for this envelope.
595168520Sgshapiro**
596168520Sgshapiro**	Notes: field and value must be in internal format, i.e.,
597168520Sgshapiro**		metacharacters must be "quoted", see quote_internal_chars().
59838032Speter*/
59938032Speter
60038032Spetervoid
601168520Sgshapiroaddheader(field, value, flags, e, space)
60238032Speter	char *field;
60338032Speter	char *value;
60464565Sgshapiro	int flags;
60590795Sgshapiro	ENVELOPE *e;
606168520Sgshapiro	bool space;
60738032Speter{
60838032Speter	register HDR *h;
60938032Speter	HDR **hp;
61090795Sgshapiro	HDR **hdrlist = &e->e_header;
61138032Speter
61238032Speter	/* find current place in list -- keep back pointer? */
61338032Speter	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
61438032Speter	{
61590795Sgshapiro		if (sm_strcasecmp(field, h->h_field) == 0)
61638032Speter			break;
61738032Speter	}
61838032Speter
61938032Speter	/* allocate space for new header */
620168520Sgshapiro	h = allocheader(field, value, flags, e->e_rpool, space);
62138032Speter	h->h_link = *hp;
62238032Speter	*hp = h;
62338032Speter}
624168520Sgshapiro
62590795Sgshapiro/*
626132946Sgshapiro**  INSHEADER -- insert a header entry at the specified index
627132946Sgshapiro**	This bypasses the special checking of chompheader.
628132946Sgshapiro**
629132946Sgshapiro**	Parameters:
630132946Sgshapiro**		idx -- index into the header list at which to insert
631168520Sgshapiro**		field -- the name of the header field (will be copied).
632168520Sgshapiro**		value -- the value of the field (will be copied).
633132946Sgshapiro**		flags -- flags to add to h_flags.
634132946Sgshapiro**		e -- envelope.
635168520Sgshapiro**		space -- add leading space?
636132946Sgshapiro**
637132946Sgshapiro**	Returns:
638132946Sgshapiro**		none.
639132946Sgshapiro**
640132946Sgshapiro**	Side Effects:
641132946Sgshapiro**		inserts the field on the list of headers for this envelope.
642168520Sgshapiro**
643168520Sgshapiro**	Notes:
644168520Sgshapiro**		- field and value must be in internal format, i.e.,
645168520Sgshapiro**		metacharacters must be "quoted", see quote_internal_chars().
646168520Sgshapiro**		- the header list contains headers that might not be
647168520Sgshapiro**		sent "out" (see putheader(): "skip"), hence there is no
648168520Sgshapiro**		reliable way to insert a header at an exact position
649168520Sgshapiro**		(except at the front or end).
650132946Sgshapiro*/
651132946Sgshapiro
652132946Sgshapirovoid
653168520Sgshapiroinsheader(idx, field, value, flags, e, space)
654132946Sgshapiro	int idx;
655132946Sgshapiro	char *field;
656132946Sgshapiro	char *value;
657132946Sgshapiro	int flags;
658132946Sgshapiro	ENVELOPE *e;
659168520Sgshapiro	bool space;
660132946Sgshapiro{
661132946Sgshapiro	HDR *h, *srch, *last = NULL;
662132946Sgshapiro
663132946Sgshapiro	/* allocate space for new header */
664168520Sgshapiro	h = allocheader(field, value, flags, e->e_rpool, space);
665132946Sgshapiro
666132946Sgshapiro	/* find insertion position */
667132946Sgshapiro	for (srch = e->e_header; srch != NULL && idx > 0;
668132946Sgshapiro	     srch = srch->h_link, idx--)
669132946Sgshapiro		last = srch;
670132946Sgshapiro
671132946Sgshapiro	if (e->e_header == NULL)
672132946Sgshapiro	{
673132946Sgshapiro		e->e_header = h;
674132946Sgshapiro		h->h_link = NULL;
675132946Sgshapiro	}
676132946Sgshapiro	else if (srch == NULL)
677132946Sgshapiro	{
678132946Sgshapiro		SM_ASSERT(last != NULL);
679132946Sgshapiro		last->h_link = h;
680132946Sgshapiro		h->h_link = NULL;
681132946Sgshapiro	}
682132946Sgshapiro	else
683132946Sgshapiro	{
684132946Sgshapiro		h->h_link = srch->h_link;
685132946Sgshapiro		srch->h_link = h;
686132946Sgshapiro	}
687132946Sgshapiro}
688168520Sgshapiro
689132946Sgshapiro/*
69038032Speter**  HVALUE -- return value of a header.
69138032Speter**
69238032Speter**	Only "real" fields (i.e., ones that have not been supplied
69338032Speter**	as a default) are used.
69438032Speter**
69538032Speter**	Parameters:
69638032Speter**		field -- the field name.
69738032Speter**		header -- the header list.
69838032Speter**
69938032Speter**	Returns:
700168520Sgshapiro**		pointer to the value part (internal format).
70138032Speter**		NULL if not found.
70238032Speter**
70338032Speter**	Side Effects:
70438032Speter**		none.
70538032Speter*/
70638032Speter
70738032Speterchar *
70838032Speterhvalue(field, header)
70938032Speter	char *field;
71038032Speter	HDR *header;
71138032Speter{
71238032Speter	register HDR *h;
71338032Speter
71438032Speter	for (h = header; h != NULL; h = h->h_link)
71538032Speter	{
71638032Speter		if (!bitset(H_DEFAULT, h->h_flags) &&
71790795Sgshapiro		    sm_strcasecmp(h->h_field, field) == 0)
718203004Sgshapiro		{
719203004Sgshapiro			char *s;
720203004Sgshapiro
721203004Sgshapiro			s = h->h_value;
722203004Sgshapiro			if (s == NULL)
723203004Sgshapiro				return NULL;
724203004Sgshapiro			while (isascii(*s) && isspace(*s))
725203004Sgshapiro				s++;
726203004Sgshapiro			return s;
727203004Sgshapiro		}
72838032Speter	}
72964565Sgshapiro	return NULL;
73038032Speter}
731168520Sgshapiro
73290795Sgshapiro/*
73338032Speter**  ISHEADER -- predicate telling if argument is a header.
73438032Speter**
73538032Speter**	A line is a header if it has a single word followed by
73638032Speter**	optional white space followed by a colon.
73738032Speter**
73838032Speter**	Header fields beginning with two dashes, although technically
73938032Speter**	permitted by RFC822, are automatically rejected in order
74038032Speter**	to make MIME work out.  Without this we could have a technically
74138032Speter**	legal header such as ``--"foo:bar"'' that would also be a legal
74238032Speter**	MIME separator.
74338032Speter**
74438032Speter**	Parameters:
74538032Speter**		h -- string to check for possible headerness.
74638032Speter**
74738032Speter**	Returns:
74890795Sgshapiro**		true if h is a header.
74990795Sgshapiro**		false otherwise.
75038032Speter**
75138032Speter**	Side Effects:
75238032Speter**		none.
75338032Speter*/
75438032Speter
75538032Speterbool
75638032Speterisheader(h)
75738032Speter	char *h;
75838032Speter{
759168520Sgshapiro	char *s;
76038032Speter
761168520Sgshapiro	s = h;
76238032Speter	if (s[0] == '-' && s[1] == '-')
76390795Sgshapiro		return false;
76438032Speter
76538032Speter	while (*s > ' ' && *s != ':' && *s != '\0')
76638032Speter		s++;
76738032Speter
76838032Speter	if (h == s)
76990795Sgshapiro		return false;
77038032Speter
77138032Speter	/* following technically violates RFC822 */
77238032Speter	while (isascii(*s) && isspace(*s))
77338032Speter		s++;
77438032Speter
77538032Speter	return (*s == ':');
77638032Speter}
777168520Sgshapiro
77890795Sgshapiro/*
77938032Speter**  EATHEADER -- run through the stored header and extract info.
78038032Speter**
78138032Speter**	Parameters:
78238032Speter**		e -- the envelope to process.
78338032Speter**		full -- if set, do full processing (e.g., compute
78438032Speter**			message priority).  This should not be set
78538032Speter**			when reading a queue file because some info
78638032Speter**			needed to compute the priority is wrong.
78790795Sgshapiro**		log -- call logsender()?
78838032Speter**
78938032Speter**	Returns:
79038032Speter**		none.
79138032Speter**
79238032Speter**	Side Effects:
79338032Speter**		Sets a bunch of global variables from information
79438032Speter**			in the collected header.
79538032Speter*/
79638032Speter
79738032Spetervoid
79890795Sgshapiroeatheader(e, full, log)
79938032Speter	register ENVELOPE *e;
80038032Speter	bool full;
80190795Sgshapiro	bool log;
80238032Speter{
80338032Speter	register HDR *h;
80438032Speter	register char *p;
80538032Speter	int hopcnt = 0;
80638032Speter	char buf[MAXLINE];
80738032Speter
80838032Speter	/*
80938032Speter	**  Set up macros for possible expansion in headers.
81038032Speter	*/
81138032Speter
81290795Sgshapiro	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
81390795Sgshapiro	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
81438032Speter	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
81590795Sgshapiro		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
81638032Speter	else
81790795Sgshapiro		macdefine(&e->e_macro, A_PERM, 'u', NULL);
81838032Speter
81938032Speter	/* full name of from person */
82038032Speter	p = hvalue("full-name", e->e_header);
82138032Speter	if (p != NULL)
82238032Speter	{
82338032Speter		if (!rfc822_string(p))
82438032Speter		{
82538032Speter			/*
82638032Speter			**  Quote a full name with special characters
82738032Speter			**  as a comment so crackaddr() doesn't destroy
82838032Speter			**  the name portion of the address.
82938032Speter			*/
83090795Sgshapiro
83190795Sgshapiro			p = addquotes(p, e->e_rpool);
83238032Speter		}
83390795Sgshapiro		macdefine(&e->e_macro, A_PERM, 'x', p);
83438032Speter	}
83538032Speter
83638032Speter	if (tTd(32, 1))
83790795Sgshapiro		sm_dprintf("----- collected header -----\n");
83890795Sgshapiro	e->e_msgid = NULL;
83938032Speter	for (h = e->e_header; h != NULL; h = h->h_link)
84038032Speter	{
84138032Speter		if (tTd(32, 1))
842168520Sgshapiro			sm_dprintf("%s:", h->h_field);
84338032Speter		if (h->h_value == NULL)
84438032Speter		{
84538032Speter			if (tTd(32, 1))
84690795Sgshapiro				sm_dprintf("<NULL>\n");
84738032Speter			continue;
84838032Speter		}
84938032Speter
85038032Speter		/* do early binding */
85164565Sgshapiro		if (bitset(H_DEFAULT, h->h_flags) &&
85264565Sgshapiro		    !bitset(H_BINDLATE, h->h_flags))
85338032Speter		{
85438032Speter			if (tTd(32, 1))
85538032Speter			{
85690795Sgshapiro				sm_dprintf("(");
857132946Sgshapiro				xputs(sm_debug_file(), h->h_value);
85890795Sgshapiro				sm_dprintf(") ");
85938032Speter			}
860168520Sgshapiro			expand(h->h_value, buf, sizeof(buf), e);
861168520Sgshapiro			if (buf[0] != '\0' &&
862168520Sgshapiro			    (buf[0] != ' ' || buf[1] != '\0'))
86338032Speter			{
86438032Speter				if (bitset(H_FROM, h->h_flags))
865111826Sgshapiro					expand(crackaddr(buf, e),
866168520Sgshapiro					       buf, sizeof(buf), e);
86790795Sgshapiro				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
86838032Speter				h->h_flags &= ~H_DEFAULT;
86938032Speter			}
87038032Speter		}
87138032Speter		if (tTd(32, 1))
87238032Speter		{
873132946Sgshapiro			xputs(sm_debug_file(), h->h_value);
87490795Sgshapiro			sm_dprintf("\n");
87538032Speter		}
87638032Speter
87738032Speter		/* count the number of times it has been processed */
87838032Speter		if (bitset(H_TRACE, h->h_flags))
87938032Speter			hopcnt++;
88038032Speter
88138032Speter		/* send to this person if we so desire */
88238032Speter		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
88338032Speter		    !bitset(H_DEFAULT, h->h_flags) &&
88490795Sgshapiro		    (!bitset(EF_RESENT, e->e_flags) ||
88590795Sgshapiro		     bitset(H_RESENT, h->h_flags)))
88638032Speter		{
88738032Speter#if 0
88838032Speter			int saveflags = e->e_flags;
88964565Sgshapiro#endif /* 0 */
89038032Speter
89190795Sgshapiro			(void) sendtolist(denlstring(h->h_value, true, false),
89290795Sgshapiro					  NULLADDR, &e->e_sendqueue, 0, e);
89338032Speter
89438032Speter#if 0
89538032Speter			/*
89642580Speter			**  Change functionality so a fatal error on an
89742580Speter			**  address doesn't affect the entire envelope.
89838032Speter			*/
89964565Sgshapiro
90038032Speter			/* delete fatal errors generated by this address */
90138032Speter			if (!bitset(EF_FATALERRS, saveflags))
90238032Speter				e->e_flags &= ~EF_FATALERRS;
90364565Sgshapiro#endif /* 0 */
90438032Speter		}
90538032Speter
90638032Speter		/* save the message-id for logging */
90738032Speter		p = "resent-message-id";
90838032Speter		if (!bitset(EF_RESENT, e->e_flags))
90938032Speter			p += 7;
91090795Sgshapiro		if (sm_strcasecmp(h->h_field, p) == 0)
91138032Speter		{
91290795Sgshapiro			e->e_msgid = h->h_value;
91390795Sgshapiro			while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
91490795Sgshapiro				e->e_msgid++;
915125823Sgshapiro			macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
916132946Sgshapiro				  e->e_msgid);
91738032Speter		}
91838032Speter	}
91938032Speter	if (tTd(32, 1))
92090795Sgshapiro		sm_dprintf("----------------------------\n");
92138032Speter
92238032Speter	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
92338032Speter	if (OpMode == MD_VERIFY)
92438032Speter		return;
92538032Speter
92638032Speter	/* store hop count */
92738032Speter	if (hopcnt > e->e_hopcount)
92890795Sgshapiro	{
92938032Speter		e->e_hopcount = hopcnt;
930168520Sgshapiro		(void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
93190795Sgshapiro		macdefine(&e->e_macro, A_TEMP, 'c', buf);
93290795Sgshapiro	}
93338032Speter
93438032Speter	/* message priority */
93538032Speter	p = hvalue("precedence", e->e_header);
93638032Speter	if (p != NULL)
93738032Speter		e->e_class = priencode(p);
93838032Speter	if (e->e_class < 0)
93938032Speter		e->e_timeoutclass = TOC_NONURGENT;
94038032Speter	else if (e->e_class > 0)
94138032Speter		e->e_timeoutclass = TOC_URGENT;
94238032Speter	if (full)
94338032Speter	{
94438032Speter		e->e_msgpriority = e->e_msgsize
94538032Speter				 - e->e_class * WkClassFact
94638032Speter				 + e->e_nrcpts * WkRecipFact;
94738032Speter	}
94838032Speter
949132946Sgshapiro	/* check for DSN to properly set e_timeoutclass */
950132946Sgshapiro	p = hvalue("content-type", e->e_header);
951132946Sgshapiro	if (p != NULL)
952132946Sgshapiro	{
953132946Sgshapiro		bool oldsupr;
954132946Sgshapiro		char **pvp;
955132946Sgshapiro		char pvpbuf[MAXLINE];
956132946Sgshapiro		extern unsigned char MimeTokenTab[256];
957132946Sgshapiro
958132946Sgshapiro		/* tokenize header */
959132946Sgshapiro		oldsupr = SuprErrs;
960132946Sgshapiro		SuprErrs = true;
961168520Sgshapiro		pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
962132946Sgshapiro			      MimeTokenTab, false);
963132946Sgshapiro		SuprErrs = oldsupr;
964132946Sgshapiro
965132946Sgshapiro		/* Check if multipart/report */
966132946Sgshapiro		if (pvp != NULL && pvp[0] != NULL &&
967132946Sgshapiro		    pvp[1] != NULL && pvp[2] != NULL &&
968132946Sgshapiro		    sm_strcasecmp(*pvp++, "multipart") == 0 &&
969132946Sgshapiro		    strcmp(*pvp++, "/") == 0 &&
970132946Sgshapiro		    sm_strcasecmp(*pvp++, "report") == 0)
971132946Sgshapiro		{
972132946Sgshapiro			/* Look for report-type=delivery-status */
973132946Sgshapiro			while (*pvp != NULL)
974132946Sgshapiro			{
975132946Sgshapiro				/* skip to semicolon separator */
976132946Sgshapiro				while (*pvp != NULL && strcmp(*pvp, ";") != 0)
977132946Sgshapiro					pvp++;
978132946Sgshapiro
979132946Sgshapiro				/* skip semicolon */
980132946Sgshapiro				if (*pvp++ == NULL || *pvp == NULL)
981132946Sgshapiro					break;
982132946Sgshapiro
983132946Sgshapiro				/* look for report-type */
984132946Sgshapiro				if (sm_strcasecmp(*pvp++, "report-type") != 0)
985132946Sgshapiro					continue;
986132946Sgshapiro
987132946Sgshapiro				/* skip equal */
988132946Sgshapiro				if (*pvp == NULL || strcmp(*pvp, "=") != 0)
989132946Sgshapiro					continue;
990132946Sgshapiro
991132946Sgshapiro				/* check value */
992132946Sgshapiro				if (*++pvp != NULL &&
993132946Sgshapiro				    sm_strcasecmp(*pvp,
994132946Sgshapiro						  "delivery-status") == 0)
995132946Sgshapiro					e->e_timeoutclass = TOC_DSN;
996132946Sgshapiro
997132946Sgshapiro				/* found report-type, no need to continue */
998132946Sgshapiro				break;
999132946Sgshapiro			}
1000132946Sgshapiro		}
1001132946Sgshapiro	}
1002132946Sgshapiro
100338032Speter	/* message timeout priority */
100438032Speter	p = hvalue("priority", e->e_header);
100538032Speter	if (p != NULL)
100638032Speter	{
100738032Speter		/* (this should be in the configuration file) */
100890795Sgshapiro		if (sm_strcasecmp(p, "urgent") == 0)
100938032Speter			e->e_timeoutclass = TOC_URGENT;
101090795Sgshapiro		else if (sm_strcasecmp(p, "normal") == 0)
101138032Speter			e->e_timeoutclass = TOC_NORMAL;
101290795Sgshapiro		else if (sm_strcasecmp(p, "non-urgent") == 0)
101338032Speter			e->e_timeoutclass = TOC_NONURGENT;
1014125823Sgshapiro		else if (bitset(EF_RESPONSE, e->e_flags))
1015125823Sgshapiro			e->e_timeoutclass = TOC_DSN;
101638032Speter	}
1017125823Sgshapiro	else if (bitset(EF_RESPONSE, e->e_flags))
1018112813Sgshapiro		e->e_timeoutclass = TOC_DSN;
1019112813Sgshapiro
102038032Speter	/* date message originated */
102138032Speter	p = hvalue("posted-date", e->e_header);
102238032Speter	if (p == NULL)
102338032Speter		p = hvalue("date", e->e_header);
102438032Speter	if (p != NULL)
102590795Sgshapiro		macdefine(&e->e_macro, A_PERM, 'a', p);
102638032Speter
102738032Speter	/* check to see if this is a MIME message */
102838032Speter	if ((e->e_bodytype != NULL &&
102990795Sgshapiro	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
103038032Speter	    hvalue("MIME-Version", e->e_header) != NULL)
103138032Speter	{
103238032Speter		e->e_flags |= EF_IS_MIME;
103338032Speter		if (HasEightBits)
103438032Speter			e->e_bodytype = "8BITMIME";
103538032Speter	}
103638032Speter	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
103738032Speter	{
103838032Speter		/* this may be an RFC 1049 message */
103938032Speter		p = strpbrk(p, ";/");
104038032Speter		if (p == NULL || *p == ';')
104138032Speter		{
104238032Speter			/* yep, it is */
104338032Speter			e->e_flags |= EF_DONT_MIME;
104438032Speter		}
104538032Speter	}
104638032Speter
104738032Speter	/*
104838032Speter	**  From person in antiquated ARPANET mode
104938032Speter	**	required by UK Grey Book e-mail gateways (sigh)
105038032Speter	*/
105138032Speter
105238032Speter	if (OpMode == MD_ARPAFTP)
105338032Speter	{
105438032Speter		register struct hdrinfo *hi;
105538032Speter
105638032Speter		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
105738032Speter		{
105838032Speter			if (bitset(H_FROM, hi->hi_flags) &&
105938032Speter			    (!bitset(H_RESENT, hi->hi_flags) ||
106038032Speter			     bitset(EF_RESENT, e->e_flags)) &&
106138032Speter			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
106238032Speter				break;
106338032Speter		}
106438032Speter		if (hi->hi_field != NULL)
106538032Speter		{
106638032Speter			if (tTd(32, 2))
106790795Sgshapiro				sm_dprintf("eatheader: setsender(*%s == %s)\n",
106838032Speter					hi->hi_field, p);
106990795Sgshapiro			setsender(p, e, NULL, '\0', true);
107038032Speter		}
107138032Speter	}
107238032Speter
107338032Speter	/*
107438032Speter	**  Log collection information.
107538032Speter	*/
107638032Speter
1077203004Sgshapiro	if (tTd(92, 2))
1078203004Sgshapiro		sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n",
1079203004Sgshapiro			e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel,
1080203004Sgshapiro			log);
108190795Sgshapiro	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
108290795Sgshapiro	{
108390795Sgshapiro		logsender(e, e->e_msgid);
108490795Sgshapiro		e->e_flags &= ~EF_LOGSENDER;
108590795Sgshapiro	}
108638032Speter}
1087168520Sgshapiro
108890795Sgshapiro/*
108938032Speter**  LOGSENDER -- log sender information
109038032Speter**
109138032Speter**	Parameters:
109238032Speter**		e -- the envelope to log
109338032Speter**		msgid -- the message id
109438032Speter**
109538032Speter**	Returns:
109638032Speter**		none
109738032Speter*/
109838032Speter
109938032Spetervoid
110038032Speterlogsender(e, msgid)
110138032Speter	register ENVELOPE *e;
110238032Speter	char *msgid;
110338032Speter{
110438032Speter	char *name;
110538032Speter	register char *sbp;
110638032Speter	register char *p;
110738032Speter	char hbuf[MAXNAME + 1];
110838032Speter	char sbuf[MAXLINE + 1];
110938032Speter	char mbuf[MAXNAME + 1];
111038032Speter
111138032Speter	/* don't allow newlines in the message-id */
111290795Sgshapiro	/* XXX do we still need this? sm_syslog() replaces control chars */
111338032Speter	if (msgid != NULL)
111438032Speter	{
1115157006Sgshapiro		size_t l;
1116157006Sgshapiro
111738032Speter		l = strlen(msgid);
1118168520Sgshapiro		if (l > sizeof(mbuf) - 1)
1119168520Sgshapiro			l = sizeof(mbuf) - 1;
112064565Sgshapiro		memmove(mbuf, msgid, l);
112138032Speter		mbuf[l] = '\0';
112238032Speter		p = mbuf;
112338032Speter		while ((p = strchr(p, '\n')) != NULL)
112438032Speter			*p++ = ' ';
112538032Speter	}
112638032Speter
112738032Speter	if (bitset(EF_RESPONSE, e->e_flags))
112838032Speter		name = "[RESPONSE]";
112938032Speter	else if ((name = macvalue('_', e)) != NULL)
113064565Sgshapiro		/* EMPTY */
113138032Speter		;
113238032Speter	else if (RealHostName == NULL)
113338032Speter		name = "localhost";
113438032Speter	else if (RealHostName[0] == '[')
113538032Speter		name = RealHostName;
113638032Speter	else
113738032Speter	{
113838032Speter		name = hbuf;
1139168520Sgshapiro		(void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
114038032Speter		if (RealHostAddr.sa.sa_family != 0)
114138032Speter		{
114238032Speter			p = &hbuf[strlen(hbuf)];
114390795Sgshapiro			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
114490795Sgshapiro					   " (%.100s)",
114590795Sgshapiro					   anynet_ntoa(&RealHostAddr));
114638032Speter		}
114738032Speter	}
114838032Speter
114938032Speter	/* some versions of syslog only take 5 printf args */
115064565Sgshapiro#if (SYSLOG_BUFSIZE) >= 256
115138032Speter	sbp = sbuf;
115290795Sgshapiro	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
115390795Sgshapiro		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
115490795Sgshapiro		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
1155244833Sgshapiro		PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
115638032Speter	sbp += strlen(sbp);
115738032Speter	if (msgid != NULL)
115838032Speter	{
115990795Sgshapiro		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
116090795Sgshapiro				", msgid=%.100s", mbuf);
116138032Speter		sbp += strlen(sbp);
116238032Speter	}
116338032Speter	if (e->e_bodytype != NULL)
116438032Speter	{
116590795Sgshapiro		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
116690795Sgshapiro				", bodytype=%.20s", e->e_bodytype);
116738032Speter		sbp += strlen(sbp);
116838032Speter	}
116938032Speter	p = macvalue('r', e);
117038032Speter	if (p != NULL)
117164565Sgshapiro	{
117290795Sgshapiro		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
117390795Sgshapiro				", proto=%.20s", p);
117464565Sgshapiro		sbp += strlen(sbp);
117564565Sgshapiro	}
117690795Sgshapiro	p = macvalue(macid("{daemon_name}"), e);
117764565Sgshapiro	if (p != NULL)
117864565Sgshapiro	{
117990795Sgshapiro		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
118090795Sgshapiro				", daemon=%.20s", p);
118164565Sgshapiro		sbp += strlen(sbp);
118264565Sgshapiro	}
1183110563Sgshapiro	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
118438032Speter
118564565Sgshapiro#else /* (SYSLOG_BUFSIZE) >= 256 */
118638032Speter
118738032Speter	sm_syslog(LOG_INFO, e->e_id,
118864565Sgshapiro		  "from=%s",
118964565Sgshapiro		  e->e_from.q_paddr == NULL ? "<NONE>"
119090795Sgshapiro					    : shortenstring(e->e_from.q_paddr,
119190795Sgshapiro							    83));
119238032Speter	sm_syslog(LOG_INFO, e->e_id,
119364565Sgshapiro		  "size=%ld, class=%ld, nrcpts=%d",
1194244833Sgshapiro		  PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
119538032Speter	if (msgid != NULL)
119638032Speter		sm_syslog(LOG_INFO, e->e_id,
119764565Sgshapiro			  "msgid=%s",
119864565Sgshapiro			  shortenstring(mbuf, 83));
119938032Speter	sbp = sbuf;
120038032Speter	*sbp = '\0';
120138032Speter	if (e->e_bodytype != NULL)
120238032Speter	{
120390795Sgshapiro		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
120490795Sgshapiro				"bodytype=%.20s, ", e->e_bodytype);
120538032Speter		sbp += strlen(sbp);
120638032Speter	}
120738032Speter	p = macvalue('r', e);
120838032Speter	if (p != NULL)
120938032Speter	{
121090795Sgshapiro		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
121190795Sgshapiro				"proto=%.20s, ", p);
121238032Speter		sbp += strlen(sbp);
121338032Speter	}
121438032Speter	sm_syslog(LOG_INFO, e->e_id,
1215110563Sgshapiro		  "%.400srelay=%s", sbuf, name);
121664565Sgshapiro#endif /* (SYSLOG_BUFSIZE) >= 256 */
121738032Speter}
1218168520Sgshapiro
121990795Sgshapiro/*
122038032Speter**  PRIENCODE -- encode external priority names into internal values.
122138032Speter**
122238032Speter**	Parameters:
122338032Speter**		p -- priority in ascii.
122438032Speter**
122538032Speter**	Returns:
122638032Speter**		priority as a numeric level.
122738032Speter**
122838032Speter**	Side Effects:
122938032Speter**		none.
123038032Speter*/
123138032Speter
123264565Sgshapirostatic int
123338032Speterpriencode(p)
123438032Speter	char *p;
123538032Speter{
123638032Speter	register int i;
123738032Speter
123838032Speter	for (i = 0; i < NumPriorities; i++)
123938032Speter	{
124090795Sgshapiro		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
124164565Sgshapiro			return Priorities[i].pri_val;
124238032Speter	}
124338032Speter
124438032Speter	/* unknown priority */
124564565Sgshapiro	return 0;
124638032Speter}
1247168520Sgshapiro
124890795Sgshapiro/*
124938032Speter**  CRACKADDR -- parse an address and turn it into a macro
125038032Speter**
125138032Speter**	This doesn't actually parse the address -- it just extracts
125238032Speter**	it and replaces it with "$g".  The parse is totally ad hoc
125338032Speter**	and isn't even guaranteed to leave something syntactically
125438032Speter**	identical to what it started with.  However, it does leave
1255111826Sgshapiro**	something semantically identical if possible, else at least
1256111826Sgshapiro**	syntactically correct.
125738032Speter**
1258111826Sgshapiro**	For example, it changes "Real Name <real@example.com> (Comment)"
1259111826Sgshapiro**	to "Real Name <$g> (Comment)".
1260111826Sgshapiro**
126138032Speter**	This algorithm has been cleaned up to handle a wider range
126238032Speter**	of cases -- notably quoted and backslash escaped strings.
126338032Speter**	This modification makes it substantially better at preserving
126438032Speter**	the original syntax.
126538032Speter**
126638032Speter**	Parameters:
126738032Speter**		addr -- the address to be cracked.
1268111826Sgshapiro**		e -- the current envelope.
126938032Speter**
127038032Speter**	Returns:
127138032Speter**		a pointer to the new version.
127238032Speter**
127338032Speter**	Side Effects:
127438032Speter**		none.
127538032Speter**
127638032Speter**	Warning:
127738032Speter**		The return value is saved in local storage and should
127838032Speter**		be copied if it is to be reused.
127938032Speter*/
128038032Speter
1281111826Sgshapiro#define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1282111826Sgshapiro
1283111826Sgshapiro/*
1284111826Sgshapiro**  Append a character to bp if we have room.
1285111826Sgshapiro**  If not, punt and return $g.
1286111826Sgshapiro*/
1287111826Sgshapiro
1288111826Sgshapiro#define SM_APPEND_CHAR(c)					\
1289111826Sgshapiro	do							\
1290111826Sgshapiro	{							\
1291111826Sgshapiro		if (SM_HAVE_ROOM)				\
1292111826Sgshapiro			*bp++ = (c);				\
1293111826Sgshapiro		else						\
1294111826Sgshapiro			goto returng;				\
1295111826Sgshapiro	} while (0)
1296111826Sgshapiro
1297111826Sgshapiro#if MAXNAME < 10
1298111826SgshapiroERROR MAXNAME must be at least 10
1299111826Sgshapiro#endif /* MAXNAME < 10 */
1300111826Sgshapiro
130138032Speterchar *
1302111826Sgshapirocrackaddr(addr, e)
130338032Speter	register char *addr;
1304111826Sgshapiro	ENVELOPE *e;
130538032Speter{
130638032Speter	register char *p;
130738032Speter	register char c;
1308111826Sgshapiro	int cmtlev;			/* comment level in input string */
1309111826Sgshapiro	int realcmtlev;			/* comment level in output string */
1310111826Sgshapiro	int anglelev;			/* angle level in input string */
1311111826Sgshapiro	int copylev;			/* 0 == in address, >0 copying */
1312111826Sgshapiro	int bracklev;			/* bracket level for IPv6 addr check */
1313111826Sgshapiro	bool addangle;			/* put closing angle in output */
1314111826Sgshapiro	bool qmode;			/* quoting in original string? */
1315111826Sgshapiro	bool realqmode;			/* quoting in output string? */
1316111826Sgshapiro	bool putgmac = false;		/* already wrote $g */
1317111826Sgshapiro	bool quoteit = false;		/* need to quote next character */
1318111826Sgshapiro	bool gotangle = false;		/* found first '<' */
1319111826Sgshapiro	bool gotcolon = false;		/* found a ':' */
132038032Speter	register char *bp;
132138032Speter	char *buflim;
132238032Speter	char *bufhead;
132338032Speter	char *addrhead;
1324111826Sgshapiro	char *bufend;
132538032Speter	static char buf[MAXNAME + 1];
132638032Speter
132738032Speter	if (tTd(33, 1))
132890795Sgshapiro		sm_dprintf("crackaddr(%s)\n", addr);
132938032Speter
1330168520Sgshapiro	buflim = bufend = &buf[sizeof(buf) - 1];
1331168520Sgshapiro	bp = bufhead = buf;
1332168520Sgshapiro
1333168520Sgshapiro	/* skip over leading spaces but preserve them */
133438032Speter	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1335168520Sgshapiro	{
1336168520Sgshapiro		SM_APPEND_CHAR(*addr);
133738032Speter		addr++;
1338168520Sgshapiro	}
1339168520Sgshapiro	bufhead = bp;
134038032Speter
134138032Speter	/*
134238032Speter	**  Start by assuming we have no angle brackets.  This will be
134338032Speter	**  adjusted later if we find them.
134438032Speter	*/
134538032Speter
134638032Speter	p = addrhead = addr;
1347111826Sgshapiro	copylev = anglelev = cmtlev = realcmtlev = 0;
134838032Speter	bracklev = 0;
1349111826Sgshapiro	qmode = realqmode = addangle = false;
135038032Speter
135138032Speter	while ((c = *p++) != '\0')
135238032Speter	{
135338032Speter		/*
1354111826Sgshapiro		**  Try to keep legal syntax using spare buffer space
1355111826Sgshapiro		**  (maintained by buflim).
135638032Speter		*/
135738032Speter
1358111826Sgshapiro		if (copylev > 0)
1359111826Sgshapiro			SM_APPEND_CHAR(c);
136038032Speter
136138032Speter		/* check for backslash escapes */
136238032Speter		if (c == '\\')
136338032Speter		{
136438032Speter			/* arrange to quote the address */
136538032Speter			if (cmtlev <= 0 && !qmode)
136690795Sgshapiro				quoteit = true;
136738032Speter
136838032Speter			if ((c = *p++) == '\0')
136938032Speter			{
137038032Speter				/* too far */
137138032Speter				p--;
137238032Speter				goto putg;
137338032Speter			}
1374111826Sgshapiro			if (copylev > 0)
1375111826Sgshapiro				SM_APPEND_CHAR(c);
137638032Speter			goto putg;
137738032Speter		}
137838032Speter
137938032Speter		/* check for quoted strings */
138038032Speter		if (c == '"' && cmtlev <= 0)
138138032Speter		{
138238032Speter			qmode = !qmode;
1383111826Sgshapiro			if (copylev > 0 && SM_HAVE_ROOM)
1384111826Sgshapiro			{
1385111826Sgshapiro				if (realqmode)
1386111826Sgshapiro					buflim--;
1387111826Sgshapiro				else
1388111826Sgshapiro					buflim++;
138938032Speter				realqmode = !realqmode;
1390111826Sgshapiro			}
139138032Speter			continue;
139238032Speter		}
139338032Speter		if (qmode)
139438032Speter			goto putg;
139538032Speter
139638032Speter		/* check for comments */
139738032Speter		if (c == '(')
139838032Speter		{
139938032Speter			cmtlev++;
140038032Speter
140138032Speter			/* allow space for closing paren */
1402111826Sgshapiro			if (SM_HAVE_ROOM)
140338032Speter			{
140438032Speter				buflim--;
140538032Speter				realcmtlev++;
140638032Speter				if (copylev++ <= 0)
140738032Speter				{
140838032Speter					if (bp != bufhead)
1409111826Sgshapiro						SM_APPEND_CHAR(' ');
1410111826Sgshapiro					SM_APPEND_CHAR(c);
141138032Speter				}
141238032Speter			}
141338032Speter		}
141438032Speter		if (cmtlev > 0)
141538032Speter		{
141638032Speter			if (c == ')')
141738032Speter			{
141838032Speter				cmtlev--;
141938032Speter				copylev--;
1420111826Sgshapiro				if (SM_HAVE_ROOM)
142138032Speter				{
142238032Speter					realcmtlev--;
142338032Speter					buflim++;
142438032Speter				}
142538032Speter			}
142638032Speter			continue;
142738032Speter		}
142838032Speter		else if (c == ')')
142938032Speter		{
143038032Speter			/* syntax error: unmatched ) */
1431120259Sgshapiro			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
143238032Speter				bp--;
143338032Speter		}
143438032Speter
143538032Speter		/* count nesting on [ ... ] (for IPv6 domain literals) */
143638032Speter		if (c == '[')
143738032Speter			bracklev++;
143838032Speter		else if (c == ']')
143938032Speter			bracklev--;
144038032Speter
144138032Speter		/* check for group: list; syntax */
144238032Speter		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
144338032Speter		    !gotcolon && !ColonOkInAddr)
144438032Speter		{
144538032Speter			register char *q;
144638032Speter
144738032Speter			/*
144838032Speter			**  Check for DECnet phase IV ``::'' (host::user)
1449111826Sgshapiro			**  or DECnet phase V ``:.'' syntaxes.  The latter
145038032Speter			**  covers ``user@DEC:.tay.myhost'' and
145138032Speter			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
145238032Speter			*/
145338032Speter
145438032Speter			if (*p == ':' || *p == '.')
145538032Speter			{
145638032Speter				if (cmtlev <= 0 && !qmode)
145790795Sgshapiro					quoteit = true;
1458111826Sgshapiro				if (copylev > 0)
145938032Speter				{
1460111826Sgshapiro					SM_APPEND_CHAR(c);
1461111826Sgshapiro					SM_APPEND_CHAR(*p);
146238032Speter				}
146338032Speter				p++;
146438032Speter				goto putg;
146538032Speter			}
146638032Speter
146790795Sgshapiro			gotcolon = true;
146838032Speter
146938032Speter			bp = bufhead;
147038032Speter			if (quoteit)
147138032Speter			{
1472111826Sgshapiro				SM_APPEND_CHAR('"');
147338032Speter
147438032Speter				/* back up over the ':' and any spaces */
147538032Speter				--p;
1476111826Sgshapiro				while (p > addr &&
1477111826Sgshapiro				       isascii(*--p) && isspace(*p))
147838032Speter					continue;
147938032Speter				p++;
148038032Speter			}
148138032Speter			for (q = addrhead; q < p; )
148238032Speter			{
148338032Speter				c = *q++;
1484111826Sgshapiro				if (quoteit && c == '"')
1485111826Sgshapiro					SM_APPEND_CHAR('\\');
1486132946Sgshapiro				SM_APPEND_CHAR(c);
148738032Speter			}
148838032Speter			if (quoteit)
148938032Speter			{
149038032Speter				if (bp == &bufhead[1])
149138032Speter					bp--;
149238032Speter				else
1493111826Sgshapiro					SM_APPEND_CHAR('"');
149438032Speter				while ((c = *p++) != ':')
1495111826Sgshapiro					SM_APPEND_CHAR(c);
1496111826Sgshapiro				SM_APPEND_CHAR(c);
149738032Speter			}
149838032Speter
149938032Speter			/* any trailing white space is part of group: */
1500111826Sgshapiro			while (isascii(*p) && isspace(*p))
1501111826Sgshapiro			{
1502111826Sgshapiro				SM_APPEND_CHAR(*p);
1503111826Sgshapiro				p++;
1504111826Sgshapiro			}
150538032Speter			copylev = 0;
150690795Sgshapiro			putgmac = quoteit = false;
150738032Speter			bufhead = bp;
150838032Speter			addrhead = p;
150938032Speter			continue;
151038032Speter		}
151138032Speter
151238032Speter		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1513111826Sgshapiro			SM_APPEND_CHAR(c);
151438032Speter
151538032Speter		/* check for characters that may have to be quoted */
151638032Speter		if (strchr(MustQuoteChars, c) != NULL)
151738032Speter		{
151838032Speter			/*
151938032Speter			**  If these occur as the phrase part of a <>
152038032Speter			**  construct, but are not inside of () or already
152138032Speter			**  quoted, they will have to be quoted.  Note that
152238032Speter			**  now (but don't actually do the quoting).
152338032Speter			*/
152438032Speter
152538032Speter			if (cmtlev <= 0 && !qmode)
152690795Sgshapiro				quoteit = true;
152738032Speter		}
152838032Speter
152938032Speter		/* check for angle brackets */
153038032Speter		if (c == '<')
153138032Speter		{
153238032Speter			register char *q;
153338032Speter
153438032Speter			/* assume first of two angles is bogus */
153538032Speter			if (gotangle)
153690795Sgshapiro				quoteit = true;
153790795Sgshapiro			gotangle = true;
153838032Speter
153938032Speter			/* oops -- have to change our mind */
154038032Speter			anglelev = 1;
1541111826Sgshapiro			if (SM_HAVE_ROOM)
1542111826Sgshapiro			{
1543111826Sgshapiro				if (!addangle)
1544111826Sgshapiro					buflim--;
1545111826Sgshapiro				addangle = true;
1546111826Sgshapiro			}
154738032Speter
154838032Speter			bp = bufhead;
154938032Speter			if (quoteit)
155038032Speter			{
1551111826Sgshapiro				SM_APPEND_CHAR('"');
155238032Speter
155338032Speter				/* back up over the '<' and any spaces */
155438032Speter				--p;
1555111826Sgshapiro				while (p > addr &&
1556111826Sgshapiro				       isascii(*--p) && isspace(*p))
155738032Speter					continue;
155838032Speter				p++;
155938032Speter			}
156038032Speter			for (q = addrhead; q < p; )
156138032Speter			{
156238032Speter				c = *q++;
1563111826Sgshapiro				if (quoteit && c == '"')
156438032Speter				{
1565111826Sgshapiro					SM_APPEND_CHAR('\\');
1566111826Sgshapiro					SM_APPEND_CHAR(c);
156738032Speter				}
1568111826Sgshapiro				else
1569111826Sgshapiro					SM_APPEND_CHAR(c);
157038032Speter			}
157138032Speter			if (quoteit)
157238032Speter			{
157338032Speter				if (bp == &buf[1])
157438032Speter					bp--;
157538032Speter				else
1576111826Sgshapiro					SM_APPEND_CHAR('"');
157738032Speter				while ((c = *p++) != '<')
1578111826Sgshapiro					SM_APPEND_CHAR(c);
1579111826Sgshapiro				SM_APPEND_CHAR(c);
158038032Speter			}
158138032Speter			copylev = 0;
158290795Sgshapiro			putgmac = quoteit = false;
158338032Speter			continue;
158438032Speter		}
158538032Speter
158638032Speter		if (c == '>')
158738032Speter		{
158838032Speter			if (anglelev > 0)
158938032Speter			{
159038032Speter				anglelev--;
1591111826Sgshapiro				if (SM_HAVE_ROOM)
159238032Speter				{
1593111826Sgshapiro					if (addangle)
1594111826Sgshapiro						buflim++;
1595111826Sgshapiro					addangle = false;
159638032Speter				}
159738032Speter			}
1598111826Sgshapiro			else if (SM_HAVE_ROOM)
159938032Speter			{
160038032Speter				/* syntax error: unmatched > */
1601120259Sgshapiro				if (copylev > 0 && bp > bufhead)
160238032Speter					bp--;
160390795Sgshapiro				quoteit = true;
160438032Speter				continue;
160538032Speter			}
160638032Speter			if (copylev++ <= 0)
1607111826Sgshapiro				SM_APPEND_CHAR(c);
160838032Speter			continue;
160938032Speter		}
161038032Speter
161138032Speter		/* must be a real address character */
161238032Speter	putg:
161338032Speter		if (copylev <= 0 && !putgmac)
161438032Speter		{
1615111826Sgshapiro			if (bp > buf && bp[-1] == ')')
1616111826Sgshapiro				SM_APPEND_CHAR(' ');
1617111826Sgshapiro			SM_APPEND_CHAR(MACROEXPAND);
1618111826Sgshapiro			SM_APPEND_CHAR('g');
161990795Sgshapiro			putgmac = true;
162038032Speter		}
162138032Speter	}
162238032Speter
162338032Speter	/* repair any syntactic damage */
1624111826Sgshapiro	if (realqmode && bp < bufend)
162538032Speter		*bp++ = '"';
1626111826Sgshapiro	while (realcmtlev-- > 0 && bp < bufend)
162738032Speter		*bp++ = ')';
1628111826Sgshapiro	if (addangle && bp < bufend)
162938032Speter		*bp++ = '>';
1630111826Sgshapiro	*bp = '\0';
1631111826Sgshapiro	if (bp < bufend)
1632111826Sgshapiro		goto success;
163338032Speter
1634111826Sgshapiro returng:
1635111826Sgshapiro	/* String too long, punt */
1636111826Sgshapiro	buf[0] = '<';
1637111826Sgshapiro	buf[1] = MACROEXPAND;
1638111826Sgshapiro	buf[2]= 'g';
1639111826Sgshapiro	buf[3] = '>';
1640111826Sgshapiro	buf[4]= '\0';
1641111826Sgshapiro	sm_syslog(LOG_ALERT, e->e_id,
1642111826Sgshapiro		  "Dropped invalid comments from header address");
1643111826Sgshapiro
1644111826Sgshapiro success:
164538032Speter	if (tTd(33, 1))
164638032Speter	{
164790795Sgshapiro		sm_dprintf("crackaddr=>`");
1648132946Sgshapiro		xputs(sm_debug_file(), buf);
164990795Sgshapiro		sm_dprintf("'\n");
165038032Speter	}
165164565Sgshapiro	return buf;
165238032Speter}
1653168520Sgshapiro
165490795Sgshapiro/*
165538032Speter**  PUTHEADER -- put the header part of a message from the in-core copy
165638032Speter**
165738032Speter**	Parameters:
165838032Speter**		mci -- the connection information.
165964565Sgshapiro**		hdr -- the header to put.
166038032Speter**		e -- envelope to use.
166143733Speter**		flags -- MIME conversion flags.
166238032Speter**
166338032Speter**	Returns:
1664159613Sgshapiro**		true iff header part was written successfully
166538032Speter**
166638032Speter**	Side Effects:
166738032Speter**		none.
166838032Speter*/
166938032Speter
1670157006Sgshapirobool
167143733Speterputheader(mci, hdr, e, flags)
167238032Speter	register MCI *mci;
167338032Speter	HDR *hdr;
167438032Speter	register ENVELOPE *e;
167543733Speter	int flags;
167638032Speter{
167738032Speter	register HDR *h;
167890795Sgshapiro	char buf[SM_MAX(MAXLINE,BUFSIZ)];
167938032Speter	char obuf[MAXLINE];
168038032Speter
168138032Speter	if (tTd(34, 1))
168290795Sgshapiro		sm_dprintf("--- putheader, mailer = %s ---\n",
168338032Speter			mci->mci_mailer->m_name);
168438032Speter
168538032Speter	/*
168638032Speter	**  If we're in MIME mode, we're not really in the header of the
168738032Speter	**  message, just the header of one of the parts of the body of
168838032Speter	**  the message.  Therefore MCIF_INHEADER should not be turned on.
168938032Speter	*/
169038032Speter
169138032Speter	if (!bitset(MCIF_INMIME, mci->mci_flags))
169238032Speter		mci->mci_flags |= MCIF_INHEADER;
169338032Speter
169438032Speter	for (h = hdr; h != NULL; h = h->h_link)
169538032Speter	{
169638032Speter		register char *p = h->h_value;
169790795Sgshapiro		char *q;
169838032Speter
169938032Speter		if (tTd(34, 11))
170038032Speter		{
1701168520Sgshapiro			sm_dprintf("  %s:", h->h_field);
1702132946Sgshapiro			xputs(sm_debug_file(), p);
170338032Speter		}
170438032Speter
170564565Sgshapiro		/* Skip empty headers */
170664565Sgshapiro		if (h->h_value == NULL)
170764565Sgshapiro			continue;
170864565Sgshapiro
170942580Speter		/* heuristic shortening of MIME fields to avoid MUA overflows */
171042580Speter		if (MaxMimeFieldLength > 0 &&
171142580Speter		    wordinclass(h->h_field,
171290795Sgshapiro				macid("{checkMIMEFieldHeaders}")))
171342580Speter		{
171471348Sgshapiro			size_t len;
171571348Sgshapiro
1716111826Sgshapiro			len = fix_mime_header(h, e);
171771348Sgshapiro			if (len > 0)
171842580Speter			{
171942580Speter				sm_syslog(LOG_ALERT, e->e_id,
172071348Sgshapiro					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
172171348Sgshapiro					  h->h_field, (unsigned long) len);
172242580Speter				if (tTd(34, 11))
172390795Sgshapiro					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
172490795Sgshapiro						   h->h_field,
172590795Sgshapiro						   (unsigned long) len);
172642580Speter			}
172742580Speter		}
172842580Speter
172942580Speter		if (MaxMimeHeaderLength > 0 &&
173042580Speter		    wordinclass(h->h_field,
173190795Sgshapiro				macid("{checkMIMETextHeaders}")))
173242580Speter		{
173371348Sgshapiro			size_t len;
173471348Sgshapiro
173571348Sgshapiro			len = strlen(h->h_value);
173671348Sgshapiro			if (len > (size_t) MaxMimeHeaderLength)
173742580Speter			{
173842580Speter				h->h_value[MaxMimeHeaderLength - 1] = '\0';
173942580Speter				sm_syslog(LOG_ALERT, e->e_id,
174071348Sgshapiro					  "Truncated long MIME %s header (length = %ld) (possible attack)",
174171348Sgshapiro					  h->h_field, (unsigned long) len);
174242580Speter				if (tTd(34, 11))
174390795Sgshapiro					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
174490795Sgshapiro						   h->h_field,
174590795Sgshapiro						   (unsigned long) len);
174642580Speter			}
174742580Speter		}
174842580Speter
174942580Speter		if (MaxMimeHeaderLength > 0 &&
175042580Speter		    wordinclass(h->h_field,
175190795Sgshapiro				macid("{checkMIMEHeaders}")))
175242580Speter		{
175371348Sgshapiro			size_t len;
175471348Sgshapiro
175571348Sgshapiro			len = strlen(h->h_value);
175671348Sgshapiro			if (shorten_rfc822_string(h->h_value,
175771348Sgshapiro						  MaxMimeHeaderLength))
175842580Speter			{
1759111826Sgshapiro				if (len < MaxMimeHeaderLength)
1760111826Sgshapiro				{
1761111826Sgshapiro					/* we only rebalanced a bogus header */
1762111826Sgshapiro					sm_syslog(LOG_ALERT, e->e_id,
1763111826Sgshapiro						  "Fixed MIME %s header (possible attack)",
1764111826Sgshapiro						  h->h_field);
1765111826Sgshapiro					if (tTd(34, 11))
1766111826Sgshapiro						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1767111826Sgshapiro							   h->h_field);
1768111826Sgshapiro				}
1769111826Sgshapiro				else
1770111826Sgshapiro				{
1771111826Sgshapiro					/* we actually shortened header */
1772111826Sgshapiro					sm_syslog(LOG_ALERT, e->e_id,
1773111826Sgshapiro						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1774111826Sgshapiro						  h->h_field,
1775111826Sgshapiro						  (unsigned long) len);
1776111826Sgshapiro					if (tTd(34, 11))
1777111826Sgshapiro						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1778111826Sgshapiro							   h->h_field,
1779111826Sgshapiro							   (unsigned long) len);
1780111826Sgshapiro				}
178142580Speter			}
178242580Speter		}
178342580Speter
178443733Speter		/*
178543733Speter		**  Suppress Content-Transfer-Encoding: if we are MIMEing
178643733Speter		**  and we are potentially converting from 8 bit to 7 bit
178743733Speter		**  MIME.  If converting, add a new CTE header in
178843733Speter		**  mime8to7().
178943733Speter		*/
179090795Sgshapiro
179138032Speter		if (bitset(H_CTE, h->h_flags) &&
179243733Speter		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
179343733Speter			   mci->mci_flags) &&
179443733Speter		    !bitset(M87F_NO8TO7, flags))
179538032Speter		{
179638032Speter			if (tTd(34, 11))
179790795Sgshapiro				sm_dprintf(" (skipped (content-transfer-encoding))\n");
179838032Speter			continue;
179938032Speter		}
180038032Speter
180138032Speter		if (bitset(MCIF_INMIME, mci->mci_flags))
180238032Speter		{
180338032Speter			if (tTd(34, 11))
180490795Sgshapiro				sm_dprintf("\n");
1805157006Sgshapiro			if (!put_vanilla_header(h, p, mci))
1806157006Sgshapiro				goto writeerr;
180738032Speter			continue;
180838032Speter		}
180938032Speter
181038032Speter		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
181164565Sgshapiro		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
181264565Sgshapiro		    (h->h_macro == '\0' ||
181390795Sgshapiro		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
181490795Sgshapiro		     *q == '\0'))
181538032Speter		{
181638032Speter			if (tTd(34, 11))
181790795Sgshapiro				sm_dprintf(" (skipped)\n");
181838032Speter			continue;
181938032Speter		}
182038032Speter
182138032Speter		/* handle Resent-... headers specially */
182238032Speter		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
182338032Speter		{
182438032Speter			if (tTd(34, 11))
182590795Sgshapiro				sm_dprintf(" (skipped (resent))\n");
182638032Speter			continue;
182738032Speter		}
182838032Speter
182938032Speter		/* suppress return receipts if requested */
183038032Speter		if (bitset(H_RECEIPTTO, h->h_flags) &&
183138032Speter		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
183238032Speter		{
183338032Speter			if (tTd(34, 11))
183490795Sgshapiro				sm_dprintf(" (skipped (receipt))\n");
183538032Speter			continue;
183638032Speter		}
183738032Speter
183838032Speter		/* macro expand value if generated internally */
183964565Sgshapiro		if (bitset(H_DEFAULT, h->h_flags) ||
184064565Sgshapiro		    bitset(H_BINDLATE, h->h_flags))
184138032Speter		{
1842168520Sgshapiro			expand(p, buf, sizeof(buf), e);
184338032Speter			p = buf;
184438032Speter			if (*p == '\0')
184538032Speter			{
184638032Speter				if (tTd(34, 11))
184790795Sgshapiro					sm_dprintf(" (skipped -- null value)\n");
184838032Speter				continue;
184938032Speter			}
185038032Speter		}
185138032Speter
185238032Speter		if (bitset(H_BCC, h->h_flags))
185338032Speter		{
185438032Speter			/* Bcc: field -- either truncate or delete */
185538032Speter			if (bitset(EF_DELETE_BCC, e->e_flags))
185638032Speter			{
185738032Speter				if (tTd(34, 11))
185890795Sgshapiro					sm_dprintf(" (skipped -- bcc)\n");
185938032Speter			}
186038032Speter			else
186138032Speter			{
186238032Speter				/* no other recipient headers: truncate value */
1863168520Sgshapiro				(void) sm_strlcpyn(obuf, sizeof(obuf), 2,
186490795Sgshapiro						   h->h_field, ":");
1865157006Sgshapiro				if (!putline(obuf, mci))
1866157006Sgshapiro					goto writeerr;
186738032Speter			}
186838032Speter			continue;
186938032Speter		}
187038032Speter
187138032Speter		if (tTd(34, 11))
187290795Sgshapiro			sm_dprintf("\n");
187338032Speter
187438032Speter		if (bitset(H_FROM|H_RCPT, h->h_flags))
187538032Speter		{
187638032Speter			/* address field */
187738032Speter			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
187838032Speter
187938032Speter			if (bitset(H_FROM, h->h_flags))
188090795Sgshapiro				oldstyle = false;
1881173343Sgshapiro			commaize(h, p, oldstyle, mci, e,
1882173343Sgshapiro				 PXLF_HEADER | PXLF_STRIPMQUOTE);
188338032Speter		}
188438032Speter		else
188538032Speter		{
1886157006Sgshapiro			if (!put_vanilla_header(h, p, mci))
1887157006Sgshapiro				goto writeerr;
188838032Speter		}
188938032Speter	}
189038032Speter
189138032Speter	/*
189238032Speter	**  If we are converting this to a MIME message, add the
189364565Sgshapiro	**  MIME headers (but not in MIME mode!).
189438032Speter	*/
189538032Speter
189638032Speter#if MIME8TO7
189738032Speter	if (bitset(MM_MIME8BIT, MimeMode) &&
189838032Speter	    bitset(EF_HAS8BIT, e->e_flags) &&
189938032Speter	    !bitset(EF_DONT_MIME, e->e_flags) &&
190038032Speter	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
190164565Sgshapiro	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
190264565Sgshapiro	    hvalue("MIME-Version", e->e_header) == NULL)
190338032Speter	{
1904157006Sgshapiro		if (!putline("MIME-Version: 1.0", mci))
1905157006Sgshapiro			goto writeerr;
190638032Speter		if (hvalue("Content-Type", e->e_header) == NULL)
190738032Speter		{
1908168520Sgshapiro			(void) sm_snprintf(obuf, sizeof(obuf),
190990795Sgshapiro					"Content-Type: text/plain; charset=%s",
191090795Sgshapiro					defcharset(e));
1911157006Sgshapiro			if (!putline(obuf, mci))
1912157006Sgshapiro				goto writeerr;
191338032Speter		}
1914157006Sgshapiro		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1915157006Sgshapiro		    && !putline("Content-Transfer-Encoding: 8bit", mci))
1916157006Sgshapiro			goto writeerr;
191738032Speter	}
191864565Sgshapiro#endif /* MIME8TO7 */
1919157006Sgshapiro	return true;
1920157006Sgshapiro
1921157006Sgshapiro  writeerr:
1922157006Sgshapiro	return false;
192338032Speter}
1924168520Sgshapiro
192590795Sgshapiro/*
192638032Speter**  PUT_VANILLA_HEADER -- output a fairly ordinary header
192738032Speter**
192838032Speter**	Parameters:
192938032Speter**		h -- the structure describing this header
193038032Speter**		v -- the value of this header
193138032Speter**		mci -- the connection info for output
193238032Speter**
193338032Speter**	Returns:
1934159613Sgshapiro**		true iff header was written successfully
193538032Speter*/
193638032Speter
1937157006Sgshapirostatic bool
193838032Speterput_vanilla_header(h, v, mci)
193938032Speter	HDR *h;
194038032Speter	char *v;
194138032Speter	MCI *mci;
194238032Speter{
194338032Speter	register char *nlp;
194438032Speter	register char *obp;
194538032Speter	int putflags;
1946141862Sgshapiro	char obuf[MAXLINE + 256];	/* additional length for h_field */
194738032Speter
1948168520Sgshapiro	putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
194938032Speter	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
195038032Speter		putflags |= PXLF_STRIP8BIT;
1951168520Sgshapiro	(void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
195238032Speter	obp = obuf + strlen(obuf);
195338032Speter	while ((nlp = strchr(v, '\n')) != NULL)
195438032Speter	{
195538032Speter		int l;
195638032Speter
195738032Speter		l = nlp - v;
1958120259Sgshapiro
1959120259Sgshapiro		/*
1960120259Sgshapiro		**  XXX This is broken for SPACELEFT()==0
1961120259Sgshapiro		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
1962120259Sgshapiro		*/
1963120259Sgshapiro
196490795Sgshapiro		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
196538032Speter			l = SPACELEFT(obuf, obp) - 1;
196638032Speter
196790795Sgshapiro		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1968157006Sgshapiro		if (!putxline(obuf, strlen(obuf), mci, putflags))
1969157006Sgshapiro			goto writeerr;
197038032Speter		v += l + 1;
197138032Speter		obp = obuf;
197238032Speter		if (*v != ' ' && *v != '\t')
197338032Speter			*obp++ = ' ';
197438032Speter	}
1975120259Sgshapiro
1976120259Sgshapiro	/* XXX This is broken for SPACELEFT()==0 */
197790795Sgshapiro	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
197890795Sgshapiro			   (int) (SPACELEFT(obuf, obp) - 1), v);
1979157006Sgshapiro	return putxline(obuf, strlen(obuf), mci, putflags);
1980157006Sgshapiro
1981157006Sgshapiro  writeerr:
1982157006Sgshapiro	return false;
198338032Speter}
1984168520Sgshapiro
198590795Sgshapiro/*
198638032Speter**  COMMAIZE -- output a header field, making a comma-translated list.
198738032Speter**
198838032Speter**	Parameters:
198938032Speter**		h -- the header field to output.
199038032Speter**		p -- the value to put in it.
199190795Sgshapiro**		oldstyle -- true if this is an old style header.
199238032Speter**		mci -- the connection information.
199338032Speter**		e -- the envelope containing the message.
1994173343Sgshapiro**		putflags -- flags for putxline()
199538032Speter**
199638032Speter**	Returns:
1997159613Sgshapiro**		true iff header field was written successfully
199838032Speter**
199938032Speter**	Side Effects:
2000168520Sgshapiro**		outputs "p" to "mci".
200138032Speter*/
200238032Speter
2003157006Sgshapirobool
2004173343Sgshapirocommaize(h, p, oldstyle, mci, e, putflags)
200538032Speter	register HDR *h;
200638032Speter	register char *p;
200738032Speter	bool oldstyle;
200838032Speter	register MCI *mci;
200938032Speter	register ENVELOPE *e;
2010173343Sgshapiro	int putflags;
201138032Speter{
201238032Speter	register char *obp;
2013168520Sgshapiro	int opos, omax, spaces;
201490795Sgshapiro	bool firstone = true;
2015120259Sgshapiro	char **res;
201638032Speter	char obuf[MAXLINE + 3];
201738032Speter
201838032Speter	/*
201938032Speter	**  Output the address list translated by the
202038032Speter	**  mailer and with commas.
202138032Speter	*/
202238032Speter
202338032Speter	if (tTd(14, 2))
2024168520Sgshapiro		sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
202538032Speter
202638032Speter	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
202738032Speter		putflags |= PXLF_STRIP8BIT;
202838032Speter
202938032Speter	obp = obuf;
2030168520Sgshapiro	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2031168520Sgshapiro	/* opos = strlen(obp); instead of the next 3 lines? */
2032168520Sgshapiro	opos = strlen(h->h_field) + 1;
2033168520Sgshapiro	if (opos > 201)
2034168520Sgshapiro		opos = 201;
2035168520Sgshapiro	obp += opos;
2036120259Sgshapiro
2037168520Sgshapiro	spaces = 0;
2038168520Sgshapiro	while (*p != '\0' && isascii(*p) && isspace(*p))
2039168520Sgshapiro	{
2040168520Sgshapiro		++spaces;
2041168520Sgshapiro		++p;
2042168520Sgshapiro	}
2043168520Sgshapiro	if (spaces > 0)
2044168520Sgshapiro	{
2045168520Sgshapiro		SM_ASSERT(sizeof(obuf) > opos  * 2);
2046168520Sgshapiro
2047168520Sgshapiro		/*
2048168520Sgshapiro		**  Restrict number of spaces to half the length of buffer
2049168520Sgshapiro		**  so the header field body can be put in here too.
2050168520Sgshapiro		**  Note: this is a hack...
2051168520Sgshapiro		*/
2052168520Sgshapiro
2053168520Sgshapiro		if (spaces > sizeof(obuf) / 2)
2054168520Sgshapiro			spaces = sizeof(obuf) / 2;
2055168520Sgshapiro		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2056168520Sgshapiro				"");
2057168520Sgshapiro		opos += spaces;
2058168520Sgshapiro		obp += spaces;
2059168520Sgshapiro		SM_ASSERT(obp < &obuf[MAXLINE]);
2060168520Sgshapiro	}
2061168520Sgshapiro
206238032Speter	omax = mci->mci_mailer->m_linelimit - 2;
206338032Speter	if (omax < 0 || omax > 78)
206438032Speter		omax = 78;
206538032Speter
206638032Speter	/*
206738032Speter	**  Run through the list of values.
206838032Speter	*/
206938032Speter
207038032Speter	while (*p != '\0')
207138032Speter	{
207238032Speter		register char *name;
207338032Speter		register int c;
207438032Speter		char savechar;
207538032Speter		int flags;
207664565Sgshapiro		auto int status;
207738032Speter
207838032Speter		/*
207938032Speter		**  Find the end of the name.  New style names
208038032Speter		**  end with a comma, old style names end with
208138032Speter		**  a space character.  However, spaces do not
208238032Speter		**  necessarily delimit an old-style name -- at
208338032Speter		**  signs mean keep going.
208438032Speter		*/
208538032Speter
208638032Speter		/* find end of name */
208738032Speter		while ((isascii(*p) && isspace(*p)) || *p == ',')
208838032Speter			p++;
208938032Speter		name = p;
2090120259Sgshapiro		res = NULL;
209138032Speter		for (;;)
209238032Speter		{
209338032Speter			auto char *oldp;
209438032Speter			char pvpbuf[PSBUFSIZE];
209538032Speter
2096120259Sgshapiro			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2097168520Sgshapiro				      sizeof(pvpbuf), &oldp, ExtTokenTab, false);
209838032Speter			p = oldp;
2099120259Sgshapiro#if _FFR_IGNORE_BOGUS_ADDR
2100120259Sgshapiro			/* ignore addresses that can't be parsed */
2101120259Sgshapiro			if (res == NULL)
2102120259Sgshapiro			{
2103120259Sgshapiro				name = p;
2104120259Sgshapiro				continue;
2105120259Sgshapiro			}
2106120259Sgshapiro#endif /* _FFR_IGNORE_BOGUS_ADDR */
210738032Speter
210838032Speter			/* look to see if we have an at sign */
210938032Speter			while (*p != '\0' && isascii(*p) && isspace(*p))
211038032Speter				p++;
211138032Speter
211238032Speter			if (*p != '@')
211338032Speter			{
211438032Speter				p = oldp;
211538032Speter				break;
211638032Speter			}
211790795Sgshapiro			++p;
211838032Speter			while (*p != '\0' && isascii(*p) && isspace(*p))
211938032Speter				p++;
212038032Speter		}
212138032Speter		/* at the end of one complete name */
212238032Speter
212338032Speter		/* strip off trailing white space */
212438032Speter		while (p >= name &&
212538032Speter		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
212638032Speter			p--;
212738032Speter		if (++p == name)
212838032Speter			continue;
2129120259Sgshapiro
2130120259Sgshapiro		/*
2131120259Sgshapiro		**  if prescan() failed go a bit backwards; this is a hack,
2132120259Sgshapiro		**  there should be some better error recovery.
2133120259Sgshapiro		*/
2134120259Sgshapiro
2135120259Sgshapiro		if (res == NULL && p > name &&
2136120259Sgshapiro		    !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
2137120259Sgshapiro			--p;
213838032Speter		savechar = *p;
213938032Speter		*p = '\0';
214038032Speter
214138032Speter		/* translate the name to be relative */
214238032Speter		flags = RF_HEADERADDR|RF_ADDDOMAIN;
214338032Speter		if (bitset(H_FROM, h->h_flags))
214438032Speter			flags |= RF_SENDERADDR;
214538032Speter#if USERDB
214638032Speter		else if (e->e_from.q_mailer != NULL &&
214738032Speter			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
214838032Speter		{
214938032Speter			char *q;
215038032Speter
215190795Sgshapiro			q = udbsender(name, e->e_rpool);
215238032Speter			if (q != NULL)
215338032Speter				name = q;
215438032Speter		}
215564565Sgshapiro#endif /* USERDB */
215664565Sgshapiro		status = EX_OK;
215764565Sgshapiro		name = remotename(name, mci->mci_mailer, flags, &status, e);
215838032Speter		if (*name == '\0')
215938032Speter		{
216038032Speter			*p = savechar;
216138032Speter			continue;
216238032Speter		}
216390795Sgshapiro		name = denlstring(name, false, true);
216438032Speter
216538032Speter		/* output the name with nice formatting */
216638032Speter		opos += strlen(name);
216738032Speter		if (!firstone)
216838032Speter			opos += 2;
216938032Speter		if (opos > omax && !firstone)
217038032Speter		{
217190795Sgshapiro			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2172157006Sgshapiro			if (!putxline(obuf, strlen(obuf), mci, putflags))
2173157006Sgshapiro				goto writeerr;
217438032Speter			obp = obuf;
2175168520Sgshapiro			(void) sm_strlcpy(obp, "        ", sizeof(obuf));
217638032Speter			opos = strlen(obp);
217738032Speter			obp += opos;
217838032Speter			opos += strlen(name);
217938032Speter		}
218038032Speter		else if (!firstone)
218138032Speter		{
218290795Sgshapiro			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
218338032Speter			obp += 2;
218438032Speter		}
218538032Speter
218638032Speter		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
218738032Speter			*obp++ = c;
218890795Sgshapiro		firstone = false;
218938032Speter		*p = savechar;
219038032Speter	}
2191168520Sgshapiro	if (obp < &obuf[sizeof(obuf)])
2192120259Sgshapiro		*obp = '\0';
2193120259Sgshapiro	else
2194168520Sgshapiro		obuf[sizeof(obuf) - 1] = '\0';
2195157006Sgshapiro	return putxline(obuf, strlen(obuf), mci, putflags);
2196157006Sgshapiro
2197157006Sgshapiro  writeerr:
2198157006Sgshapiro	return false;
219938032Speter}
2200157006Sgshapiro
220190795Sgshapiro/*
220238032Speter**  COPYHEADER -- copy header list
220338032Speter**
220438032Speter**	This routine is the equivalent of newstr for header lists
220538032Speter**
220638032Speter**	Parameters:
220738032Speter**		header -- list of header structures to copy.
220890795Sgshapiro**		rpool -- resource pool, or NULL
220938032Speter**
221038032Speter**	Returns:
221138032Speter**		a copy of 'header'.
221238032Speter**
221338032Speter**	Side Effects:
221438032Speter**		none.
221538032Speter*/
221638032Speter
221738032SpeterHDR *
221890795Sgshapirocopyheader(header, rpool)
221938032Speter	register HDR *header;
222090795Sgshapiro	SM_RPOOL_T *rpool;
222138032Speter{
222238032Speter	register HDR *newhdr;
222338032Speter	HDR *ret;
222438032Speter	register HDR **tail = &ret;
222538032Speter
222638032Speter	while (header != NULL)
222738032Speter	{
2228168520Sgshapiro		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
222938032Speter		STRUCTCOPY(*header, *newhdr);
223038032Speter		*tail = newhdr;
223138032Speter		tail = &newhdr->h_link;
223238032Speter		header = header->h_link;
223338032Speter	}
223438032Speter	*tail = NULL;
223564565Sgshapiro
223638032Speter	return ret;
223738032Speter}
2238168520Sgshapiro
223990795Sgshapiro/*
224042580Speter**  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
224142580Speter**
224242580Speter**	Run through all of the parameters of a MIME header and
224342580Speter**	possibly truncate and rebalance the parameter according
224442580Speter**	to MaxMimeFieldLength.
224542580Speter**
224642580Speter**	Parameters:
2247111826Sgshapiro**		h -- the header to truncate/rebalance
2248111826Sgshapiro**		e -- the current envelope
224942580Speter**
225042580Speter**	Returns:
225171348Sgshapiro**		length of last offending field, 0 if all ok.
225242580Speter**
225342580Speter**	Side Effects:
225442580Speter**		string modified in place
225542580Speter*/
225642580Speter
225771348Sgshapirostatic size_t
2258111826Sgshapirofix_mime_header(h, e)
2259111826Sgshapiro	HDR *h;
2260111826Sgshapiro	ENVELOPE *e;
226142580Speter{
2262111826Sgshapiro	char *begin = h->h_value;
226342580Speter	char *end;
226471348Sgshapiro	size_t len = 0;
226571348Sgshapiro	size_t retlen = 0;
226664565Sgshapiro
2267111826Sgshapiro	if (begin == NULL || *begin == '\0')
226871348Sgshapiro		return 0;
226964565Sgshapiro
227042580Speter	/* Split on each ';' */
2271120259Sgshapiro	/* find_character() never returns NULL */
227242580Speter	while ((end = find_character(begin, ';')) != NULL)
227342580Speter	{
227442580Speter		char save = *end;
227542580Speter		char *bp;
227664565Sgshapiro
227742580Speter		*end = '\0';
227864565Sgshapiro
227971348Sgshapiro		len = strlen(begin);
228071348Sgshapiro
228142580Speter		/* Shorten individual parameter */
228242580Speter		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2283111826Sgshapiro		{
2284111826Sgshapiro			if (len < MaxMimeFieldLength)
2285111826Sgshapiro			{
2286111826Sgshapiro				/* we only rebalanced a bogus field */
2287111826Sgshapiro				sm_syslog(LOG_ALERT, e->e_id,
2288111826Sgshapiro					  "Fixed MIME %s header field (possible attack)",
2289111826Sgshapiro					  h->h_field);
2290111826Sgshapiro				if (tTd(34, 11))
2291111826Sgshapiro					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
2292111826Sgshapiro						   h->h_field);
2293111826Sgshapiro			}
2294111826Sgshapiro			else
2295111826Sgshapiro			{
2296111826Sgshapiro				/* we actually shortened the header */
2297111826Sgshapiro				retlen = len;
2298111826Sgshapiro			}
2299111826Sgshapiro		}
230064565Sgshapiro
230142580Speter		/* Collapse the possibly shortened string with rest */
230242580Speter		bp = begin + strlen(begin);
230342580Speter		if (bp != end)
230442580Speter		{
230542580Speter			char *ep = end;
230664565Sgshapiro
230742580Speter			*end = save;
230842580Speter			end = bp;
230964565Sgshapiro
231042580Speter			/* copy character by character due to overlap */
231142580Speter			while (*ep != '\0')
231242580Speter				*bp++ = *ep++;
231342580Speter			*bp = '\0';
231442580Speter		}
231542580Speter		else
231642580Speter			*end = save;
231742580Speter		if (*end == '\0')
231842580Speter			break;
231964565Sgshapiro
232042580Speter		/* Move past ';' */
232142580Speter		begin = end + 1;
232242580Speter	}
232371348Sgshapiro	return retlen;
232442580Speter}
2325