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