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