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