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