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