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