xref: /freebsd/contrib/sendmail/src/headers.c (revision e0c27215058b5786c78fcfb3963eebe61a989511)
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.5 2003/03/12 22:42:52 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 #if _FFR_QUEUERETURN_DSN
775 	/* If no timeoutclass picked and it's a DSN, use that timeoutclass */
776 	if (e->e_timeoutclass == TOC_NORMAL && bitset(EF_RESPONSE, e->e_flags))
777 		e->e_timeoutclass = TOC_DSN;
778 #endif /* _FFR_QUEUERETURN_DSN */
779 
780 	/* date message originated */
781 	p = hvalue("posted-date", e->e_header);
782 	if (p == NULL)
783 		p = hvalue("date", e->e_header);
784 	if (p != NULL)
785 		macdefine(&e->e_macro, A_PERM, 'a', p);
786 
787 	/* check to see if this is a MIME message */
788 	if ((e->e_bodytype != NULL &&
789 	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
790 	    hvalue("MIME-Version", e->e_header) != NULL)
791 	{
792 		e->e_flags |= EF_IS_MIME;
793 		if (HasEightBits)
794 			e->e_bodytype = "8BITMIME";
795 	}
796 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
797 	{
798 		/* this may be an RFC 1049 message */
799 		p = strpbrk(p, ";/");
800 		if (p == NULL || *p == ';')
801 		{
802 			/* yep, it is */
803 			e->e_flags |= EF_DONT_MIME;
804 		}
805 	}
806 
807 	/*
808 	**  From person in antiquated ARPANET mode
809 	**	required by UK Grey Book e-mail gateways (sigh)
810 	*/
811 
812 	if (OpMode == MD_ARPAFTP)
813 	{
814 		register struct hdrinfo *hi;
815 
816 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
817 		{
818 			if (bitset(H_FROM, hi->hi_flags) &&
819 			    (!bitset(H_RESENT, hi->hi_flags) ||
820 			     bitset(EF_RESENT, e->e_flags)) &&
821 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
822 				break;
823 		}
824 		if (hi->hi_field != NULL)
825 		{
826 			if (tTd(32, 2))
827 				sm_dprintf("eatheader: setsender(*%s == %s)\n",
828 					hi->hi_field, p);
829 			setsender(p, e, NULL, '\0', true);
830 		}
831 	}
832 
833 	/*
834 	**  Log collection information.
835 	*/
836 
837 	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
838 	{
839 		logsender(e, e->e_msgid);
840 		e->e_flags &= ~EF_LOGSENDER;
841 	}
842 }
843 /*
844 **  LOGSENDER -- log sender information
845 **
846 **	Parameters:
847 **		e -- the envelope to log
848 **		msgid -- the message id
849 **
850 **	Returns:
851 **		none
852 */
853 
854 void
855 logsender(e, msgid)
856 	register ENVELOPE *e;
857 	char *msgid;
858 {
859 	char *name;
860 	register char *sbp;
861 	register char *p;
862 	int l;
863 	char hbuf[MAXNAME + 1];
864 	char sbuf[MAXLINE + 1];
865 	char mbuf[MAXNAME + 1];
866 
867 	/* don't allow newlines in the message-id */
868 	/* XXX do we still need this? sm_syslog() replaces control chars */
869 	if (msgid != NULL)
870 	{
871 		l = strlen(msgid);
872 		if (l > sizeof mbuf - 1)
873 			l = sizeof mbuf - 1;
874 		memmove(mbuf, msgid, l);
875 		mbuf[l] = '\0';
876 		p = mbuf;
877 		while ((p = strchr(p, '\n')) != NULL)
878 			*p++ = ' ';
879 	}
880 
881 	if (bitset(EF_RESPONSE, e->e_flags))
882 		name = "[RESPONSE]";
883 	else if ((name = macvalue('_', e)) != NULL)
884 		/* EMPTY */
885 		;
886 	else if (RealHostName == NULL)
887 		name = "localhost";
888 	else if (RealHostName[0] == '[')
889 		name = RealHostName;
890 	else
891 	{
892 		name = hbuf;
893 		(void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
894 		if (RealHostAddr.sa.sa_family != 0)
895 		{
896 			p = &hbuf[strlen(hbuf)];
897 			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
898 					   " (%.100s)",
899 					   anynet_ntoa(&RealHostAddr));
900 		}
901 	}
902 
903 	/* some versions of syslog only take 5 printf args */
904 #if (SYSLOG_BUFSIZE) >= 256
905 	sbp = sbuf;
906 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
907 		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
908 		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
909 		e->e_msgsize, e->e_class, e->e_nrcpts);
910 	sbp += strlen(sbp);
911 	if (msgid != NULL)
912 	{
913 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
914 				", msgid=%.100s", mbuf);
915 		sbp += strlen(sbp);
916 	}
917 	if (e->e_bodytype != NULL)
918 	{
919 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
920 				", bodytype=%.20s", e->e_bodytype);
921 		sbp += strlen(sbp);
922 	}
923 	p = macvalue('r', e);
924 	if (p != NULL)
925 	{
926 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
927 				", proto=%.20s", p);
928 		sbp += strlen(sbp);
929 	}
930 	p = macvalue(macid("{daemon_name}"), e);
931 	if (p != NULL)
932 	{
933 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
934 				", daemon=%.20s", p);
935 		sbp += strlen(sbp);
936 	}
937 	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
938 
939 #else /* (SYSLOG_BUFSIZE) >= 256 */
940 
941 	sm_syslog(LOG_INFO, e->e_id,
942 		  "from=%s",
943 		  e->e_from.q_paddr == NULL ? "<NONE>"
944 					    : shortenstring(e->e_from.q_paddr,
945 							    83));
946 	sm_syslog(LOG_INFO, e->e_id,
947 		  "size=%ld, class=%ld, nrcpts=%d",
948 		  e->e_msgsize, e->e_class, e->e_nrcpts);
949 	if (msgid != NULL)
950 		sm_syslog(LOG_INFO, e->e_id,
951 			  "msgid=%s",
952 			  shortenstring(mbuf, 83));
953 	sbp = sbuf;
954 	*sbp = '\0';
955 	if (e->e_bodytype != NULL)
956 	{
957 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
958 				"bodytype=%.20s, ", e->e_bodytype);
959 		sbp += strlen(sbp);
960 	}
961 	p = macvalue('r', e);
962 	if (p != NULL)
963 	{
964 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
965 				"proto=%.20s, ", p);
966 		sbp += strlen(sbp);
967 	}
968 	sm_syslog(LOG_INFO, e->e_id,
969 		  "%.400srelay=%s", sbuf, name);
970 #endif /* (SYSLOG_BUFSIZE) >= 256 */
971 }
972 /*
973 **  PRIENCODE -- encode external priority names into internal values.
974 **
975 **	Parameters:
976 **		p -- priority in ascii.
977 **
978 **	Returns:
979 **		priority as a numeric level.
980 **
981 **	Side Effects:
982 **		none.
983 */
984 
985 static int
986 priencode(p)
987 	char *p;
988 {
989 	register int i;
990 
991 	for (i = 0; i < NumPriorities; i++)
992 	{
993 		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
994 			return Priorities[i].pri_val;
995 	}
996 
997 	/* unknown priority */
998 	return 0;
999 }
1000 /*
1001 **  CRACKADDR -- parse an address and turn it into a macro
1002 **
1003 **	This doesn't actually parse the address -- it just extracts
1004 **	it and replaces it with "$g".  The parse is totally ad hoc
1005 **	and isn't even guaranteed to leave something syntactically
1006 **	identical to what it started with.  However, it does leave
1007 **	something semantically identical if possible, else at least
1008 **	syntactically correct.
1009 **
1010 **	For example, it changes "Real Name <real@example.com> (Comment)"
1011 **	to "Real Name <$g> (Comment)".
1012 **
1013 **	This algorithm has been cleaned up to handle a wider range
1014 **	of cases -- notably quoted and backslash escaped strings.
1015 **	This modification makes it substantially better at preserving
1016 **	the original syntax.
1017 **
1018 **	Parameters:
1019 **		addr -- the address to be cracked.
1020 **		e -- the current envelope.
1021 **
1022 **	Returns:
1023 **		a pointer to the new version.
1024 **
1025 **	Side Effects:
1026 **		none.
1027 **
1028 **	Warning:
1029 **		The return value is saved in local storage and should
1030 **		be copied if it is to be reused.
1031 */
1032 
1033 #define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1034 
1035 /*
1036 **  Append a character to bp if we have room.
1037 **  If not, punt and return $g.
1038 */
1039 
1040 #define SM_APPEND_CHAR(c)					\
1041 	do							\
1042 	{							\
1043 		if (SM_HAVE_ROOM)				\
1044 			*bp++ = (c);				\
1045 		else						\
1046 			goto returng;				\
1047 	} while (0)
1048 
1049 #if MAXNAME < 10
1050 ERROR MAXNAME must be at least 10
1051 #endif /* MAXNAME < 10 */
1052 
1053 char *
1054 crackaddr(addr, e)
1055 	register char *addr;
1056 	ENVELOPE *e;
1057 {
1058 	register char *p;
1059 	register char c;
1060 	int cmtlev;			/* comment level in input string */
1061 	int realcmtlev;			/* comment level in output string */
1062 	int anglelev;			/* angle level in input string */
1063 	int copylev;			/* 0 == in address, >0 copying */
1064 	int bracklev;			/* bracket level for IPv6 addr check */
1065 	bool addangle;			/* put closing angle in output */
1066 	bool qmode;			/* quoting in original string? */
1067 	bool realqmode;			/* quoting in output string? */
1068 	bool putgmac = false;		/* already wrote $g */
1069 	bool quoteit = false;		/* need to quote next character */
1070 	bool gotangle = false;		/* found first '<' */
1071 	bool gotcolon = false;		/* found a ':' */
1072 	register char *bp;
1073 	char *buflim;
1074 	char *bufhead;
1075 	char *addrhead;
1076 	char *bufend;
1077 	static char buf[MAXNAME + 1];
1078 
1079 	if (tTd(33, 1))
1080 		sm_dprintf("crackaddr(%s)\n", addr);
1081 
1082 	/* strip leading spaces */
1083 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1084 		addr++;
1085 
1086 	/*
1087 	**  Start by assuming we have no angle brackets.  This will be
1088 	**  adjusted later if we find them.
1089 	*/
1090 
1091 	buflim = bufend = &buf[sizeof(buf) - 1];
1092 	bp = bufhead = buf;
1093 	p = addrhead = addr;
1094 	copylev = anglelev = cmtlev = realcmtlev = 0;
1095 	bracklev = 0;
1096 	qmode = realqmode = addangle = false;
1097 
1098 	while ((c = *p++) != '\0')
1099 	{
1100 		/*
1101 		**  Try to keep legal syntax using spare buffer space
1102 		**  (maintained by buflim).
1103 		*/
1104 
1105 		if (copylev > 0)
1106 			SM_APPEND_CHAR(c);
1107 
1108 		/* check for backslash escapes */
1109 		if (c == '\\')
1110 		{
1111 			/* arrange to quote the address */
1112 			if (cmtlev <= 0 && !qmode)
1113 				quoteit = true;
1114 
1115 			if ((c = *p++) == '\0')
1116 			{
1117 				/* too far */
1118 				p--;
1119 				goto putg;
1120 			}
1121 			if (copylev > 0)
1122 				SM_APPEND_CHAR(c);
1123 			goto putg;
1124 		}
1125 
1126 		/* check for quoted strings */
1127 		if (c == '"' && cmtlev <= 0)
1128 		{
1129 			qmode = !qmode;
1130 			if (copylev > 0 && SM_HAVE_ROOM)
1131 			{
1132 				if (realqmode)
1133 					buflim--;
1134 				else
1135 					buflim++;
1136 				realqmode = !realqmode;
1137 			}
1138 			continue;
1139 		}
1140 		if (qmode)
1141 			goto putg;
1142 
1143 		/* check for comments */
1144 		if (c == '(')
1145 		{
1146 			cmtlev++;
1147 
1148 			/* allow space for closing paren */
1149 			if (SM_HAVE_ROOM)
1150 			{
1151 				buflim--;
1152 				realcmtlev++;
1153 				if (copylev++ <= 0)
1154 				{
1155 					if (bp != bufhead)
1156 						SM_APPEND_CHAR(' ');
1157 					SM_APPEND_CHAR(c);
1158 				}
1159 			}
1160 		}
1161 		if (cmtlev > 0)
1162 		{
1163 			if (c == ')')
1164 			{
1165 				cmtlev--;
1166 				copylev--;
1167 				if (SM_HAVE_ROOM)
1168 				{
1169 					realcmtlev--;
1170 					buflim++;
1171 				}
1172 			}
1173 			continue;
1174 		}
1175 		else if (c == ')')
1176 		{
1177 			/* syntax error: unmatched ) */
1178 			if (copylev > 0 && SM_HAVE_ROOM)
1179 				bp--;
1180 		}
1181 
1182 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1183 		if (c == '[')
1184 			bracklev++;
1185 		else if (c == ']')
1186 			bracklev--;
1187 
1188 		/* check for group: list; syntax */
1189 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1190 		    !gotcolon && !ColonOkInAddr)
1191 		{
1192 			register char *q;
1193 
1194 			/*
1195 			**  Check for DECnet phase IV ``::'' (host::user)
1196 			**  or DECnet phase V ``:.'' syntaxes.  The latter
1197 			**  covers ``user@DEC:.tay.myhost'' and
1198 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1199 			*/
1200 
1201 			if (*p == ':' || *p == '.')
1202 			{
1203 				if (cmtlev <= 0 && !qmode)
1204 					quoteit = true;
1205 				if (copylev > 0)
1206 				{
1207 					SM_APPEND_CHAR(c);
1208 					SM_APPEND_CHAR(*p);
1209 				}
1210 				p++;
1211 				goto putg;
1212 			}
1213 
1214 			gotcolon = true;
1215 
1216 			bp = bufhead;
1217 			if (quoteit)
1218 			{
1219 				SM_APPEND_CHAR('"');
1220 
1221 				/* back up over the ':' and any spaces */
1222 				--p;
1223 				while (p > addr &&
1224 				       isascii(*--p) && isspace(*p))
1225 					continue;
1226 				p++;
1227 			}
1228 			for (q = addrhead; q < p; )
1229 			{
1230 				c = *q++;
1231 				if (quoteit && c == '"')
1232 				{
1233 					SM_APPEND_CHAR('\\');
1234 					SM_APPEND_CHAR(c);
1235 				}
1236 				else
1237 					SM_APPEND_CHAR(c);
1238 			}
1239 			if (quoteit)
1240 			{
1241 				if (bp == &bufhead[1])
1242 					bp--;
1243 				else
1244 					SM_APPEND_CHAR('"');
1245 				while ((c = *p++) != ':')
1246 					SM_APPEND_CHAR(c);
1247 				SM_APPEND_CHAR(c);
1248 			}
1249 
1250 			/* any trailing white space is part of group: */
1251 			while (isascii(*p) && isspace(*p))
1252 			{
1253 				SM_APPEND_CHAR(*p);
1254 				p++;
1255 			}
1256 			copylev = 0;
1257 			putgmac = quoteit = false;
1258 			bufhead = bp;
1259 			addrhead = p;
1260 			continue;
1261 		}
1262 
1263 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1264 			SM_APPEND_CHAR(c);
1265 
1266 		/* check for characters that may have to be quoted */
1267 		if (strchr(MustQuoteChars, c) != NULL)
1268 		{
1269 			/*
1270 			**  If these occur as the phrase part of a <>
1271 			**  construct, but are not inside of () or already
1272 			**  quoted, they will have to be quoted.  Note that
1273 			**  now (but don't actually do the quoting).
1274 			*/
1275 
1276 			if (cmtlev <= 0 && !qmode)
1277 				quoteit = true;
1278 		}
1279 
1280 		/* check for angle brackets */
1281 		if (c == '<')
1282 		{
1283 			register char *q;
1284 
1285 			/* assume first of two angles is bogus */
1286 			if (gotangle)
1287 				quoteit = true;
1288 			gotangle = true;
1289 
1290 			/* oops -- have to change our mind */
1291 			anglelev = 1;
1292 			if (SM_HAVE_ROOM)
1293 			{
1294 				if (!addangle)
1295 					buflim--;
1296 				addangle = true;
1297 			}
1298 
1299 			bp = bufhead;
1300 			if (quoteit)
1301 			{
1302 				SM_APPEND_CHAR('"');
1303 
1304 				/* back up over the '<' and any spaces */
1305 				--p;
1306 				while (p > addr &&
1307 				       isascii(*--p) && isspace(*p))
1308 					continue;
1309 				p++;
1310 			}
1311 			for (q = addrhead; q < p; )
1312 			{
1313 				c = *q++;
1314 				if (quoteit && c == '"')
1315 				{
1316 					SM_APPEND_CHAR('\\');
1317 					SM_APPEND_CHAR(c);
1318 				}
1319 				else
1320 					SM_APPEND_CHAR(c);
1321 			}
1322 			if (quoteit)
1323 			{
1324 				if (bp == &buf[1])
1325 					bp--;
1326 				else
1327 					SM_APPEND_CHAR('"');
1328 				while ((c = *p++) != '<')
1329 					SM_APPEND_CHAR(c);
1330 				SM_APPEND_CHAR(c);
1331 			}
1332 			copylev = 0;
1333 			putgmac = quoteit = false;
1334 			continue;
1335 		}
1336 
1337 		if (c == '>')
1338 		{
1339 			if (anglelev > 0)
1340 			{
1341 				anglelev--;
1342 				if (SM_HAVE_ROOM)
1343 				{
1344 					if (addangle)
1345 						buflim++;
1346 					addangle = false;
1347 				}
1348 			}
1349 			else if (SM_HAVE_ROOM)
1350 			{
1351 				/* syntax error: unmatched > */
1352 				if (copylev > 0)
1353 					bp--;
1354 				quoteit = true;
1355 				continue;
1356 			}
1357 			if (copylev++ <= 0)
1358 				SM_APPEND_CHAR(c);
1359 			continue;
1360 		}
1361 
1362 		/* must be a real address character */
1363 	putg:
1364 		if (copylev <= 0 && !putgmac)
1365 		{
1366 			if (bp > buf && bp[-1] == ')')
1367 				SM_APPEND_CHAR(' ');
1368 			SM_APPEND_CHAR(MACROEXPAND);
1369 			SM_APPEND_CHAR('g');
1370 			putgmac = true;
1371 		}
1372 	}
1373 
1374 	/* repair any syntactic damage */
1375 	if (realqmode && bp < bufend)
1376 		*bp++ = '"';
1377 	while (realcmtlev-- > 0 && bp < bufend)
1378 		*bp++ = ')';
1379 	if (addangle && bp < bufend)
1380 		*bp++ = '>';
1381 	*bp = '\0';
1382 	if (bp < bufend)
1383 		goto success;
1384 
1385  returng:
1386 	/* String too long, punt */
1387 	buf[0] = '<';
1388 	buf[1] = MACROEXPAND;
1389 	buf[2]= 'g';
1390 	buf[3] = '>';
1391 	buf[4]= '\0';
1392 	sm_syslog(LOG_ALERT, e->e_id,
1393 		  "Dropped invalid comments from header address");
1394 
1395  success:
1396 	if (tTd(33, 1))
1397 	{
1398 		sm_dprintf("crackaddr=>`");
1399 		xputs(buf);
1400 		sm_dprintf("'\n");
1401 	}
1402 	return buf;
1403 }
1404 /*
1405 **  PUTHEADER -- put the header part of a message from the in-core copy
1406 **
1407 **	Parameters:
1408 **		mci -- the connection information.
1409 **		hdr -- the header to put.
1410 **		e -- envelope to use.
1411 **		flags -- MIME conversion flags.
1412 **
1413 **	Returns:
1414 **		none.
1415 **
1416 **	Side Effects:
1417 **		none.
1418 */
1419 
1420 void
1421 putheader(mci, hdr, e, flags)
1422 	register MCI *mci;
1423 	HDR *hdr;
1424 	register ENVELOPE *e;
1425 	int flags;
1426 {
1427 	register HDR *h;
1428 	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1429 	char obuf[MAXLINE];
1430 
1431 	if (tTd(34, 1))
1432 		sm_dprintf("--- putheader, mailer = %s ---\n",
1433 			mci->mci_mailer->m_name);
1434 
1435 	/*
1436 	**  If we're in MIME mode, we're not really in the header of the
1437 	**  message, just the header of one of the parts of the body of
1438 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1439 	*/
1440 
1441 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1442 		mci->mci_flags |= MCIF_INHEADER;
1443 
1444 	for (h = hdr; h != NULL; h = h->h_link)
1445 	{
1446 		register char *p = h->h_value;
1447 		char *q;
1448 
1449 		if (tTd(34, 11))
1450 		{
1451 			sm_dprintf("  %s: ", h->h_field);
1452 			xputs(p);
1453 		}
1454 
1455 		/* Skip empty headers */
1456 		if (h->h_value == NULL)
1457 			continue;
1458 
1459 		/* heuristic shortening of MIME fields to avoid MUA overflows */
1460 		if (MaxMimeFieldLength > 0 &&
1461 		    wordinclass(h->h_field,
1462 				macid("{checkMIMEFieldHeaders}")))
1463 		{
1464 			size_t len;
1465 
1466 			len = fix_mime_header(h, e);
1467 			if (len > 0)
1468 			{
1469 				sm_syslog(LOG_ALERT, e->e_id,
1470 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1471 					  h->h_field, (unsigned long) len);
1472 				if (tTd(34, 11))
1473 					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1474 						   h->h_field,
1475 						   (unsigned long) len);
1476 			}
1477 		}
1478 
1479 		if (MaxMimeHeaderLength > 0 &&
1480 		    wordinclass(h->h_field,
1481 				macid("{checkMIMETextHeaders}")))
1482 		{
1483 			size_t len;
1484 
1485 			len = strlen(h->h_value);
1486 			if (len > (size_t) MaxMimeHeaderLength)
1487 			{
1488 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
1489 				sm_syslog(LOG_ALERT, e->e_id,
1490 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1491 					  h->h_field, (unsigned long) len);
1492 				if (tTd(34, 11))
1493 					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1494 						   h->h_field,
1495 						   (unsigned long) len);
1496 			}
1497 		}
1498 
1499 		if (MaxMimeHeaderLength > 0 &&
1500 		    wordinclass(h->h_field,
1501 				macid("{checkMIMEHeaders}")))
1502 		{
1503 			size_t len;
1504 
1505 			len = strlen(h->h_value);
1506 			if (shorten_rfc822_string(h->h_value,
1507 						  MaxMimeHeaderLength))
1508 			{
1509 				if (len < MaxMimeHeaderLength)
1510 				{
1511 					/* we only rebalanced a bogus header */
1512 					sm_syslog(LOG_ALERT, e->e_id,
1513 						  "Fixed MIME %s header (possible attack)",
1514 						  h->h_field);
1515 					if (tTd(34, 11))
1516 						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1517 							   h->h_field);
1518 				}
1519 				else
1520 				{
1521 					/* we actually shortened header */
1522 					sm_syslog(LOG_ALERT, e->e_id,
1523 						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1524 						  h->h_field,
1525 						  (unsigned long) len);
1526 					if (tTd(34, 11))
1527 						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1528 							   h->h_field,
1529 							   (unsigned long) len);
1530 				}
1531 			}
1532 		}
1533 
1534 		/*
1535 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1536 		**  and we are potentially converting from 8 bit to 7 bit
1537 		**  MIME.  If converting, add a new CTE header in
1538 		**  mime8to7().
1539 		*/
1540 
1541 		if (bitset(H_CTE, h->h_flags) &&
1542 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1543 			   mci->mci_flags) &&
1544 		    !bitset(M87F_NO8TO7, flags))
1545 		{
1546 			if (tTd(34, 11))
1547 				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1548 			continue;
1549 		}
1550 
1551 		if (bitset(MCIF_INMIME, mci->mci_flags))
1552 		{
1553 			if (tTd(34, 11))
1554 				sm_dprintf("\n");
1555 			put_vanilla_header(h, p, mci);
1556 			continue;
1557 		}
1558 
1559 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1560 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1561 		    (h->h_macro == '\0' ||
1562 		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1563 		     *q == '\0'))
1564 		{
1565 			if (tTd(34, 11))
1566 				sm_dprintf(" (skipped)\n");
1567 			continue;
1568 		}
1569 
1570 		/* handle Resent-... headers specially */
1571 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1572 		{
1573 			if (tTd(34, 11))
1574 				sm_dprintf(" (skipped (resent))\n");
1575 			continue;
1576 		}
1577 
1578 		/* suppress return receipts if requested */
1579 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1580 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1581 		{
1582 			if (tTd(34, 11))
1583 				sm_dprintf(" (skipped (receipt))\n");
1584 			continue;
1585 		}
1586 
1587 		/* macro expand value if generated internally */
1588 		if (bitset(H_DEFAULT, h->h_flags) ||
1589 		    bitset(H_BINDLATE, h->h_flags))
1590 		{
1591 			expand(p, buf, sizeof buf, e);
1592 			p = buf;
1593 			if (*p == '\0')
1594 			{
1595 				if (tTd(34, 11))
1596 					sm_dprintf(" (skipped -- null value)\n");
1597 				continue;
1598 			}
1599 		}
1600 
1601 		if (bitset(H_BCC, h->h_flags))
1602 		{
1603 			/* Bcc: field -- either truncate or delete */
1604 			if (bitset(EF_DELETE_BCC, e->e_flags))
1605 			{
1606 				if (tTd(34, 11))
1607 					sm_dprintf(" (skipped -- bcc)\n");
1608 			}
1609 			else
1610 			{
1611 				/* no other recipient headers: truncate value */
1612 				(void) sm_strlcpyn(obuf, sizeof obuf, 2,
1613 						   h->h_field, ":");
1614 				putline(obuf, mci);
1615 			}
1616 			continue;
1617 		}
1618 
1619 		if (tTd(34, 11))
1620 			sm_dprintf("\n");
1621 
1622 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1623 		{
1624 			/* address field */
1625 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1626 
1627 			if (bitset(H_FROM, h->h_flags))
1628 				oldstyle = false;
1629 			commaize(h, p, oldstyle, mci, e);
1630 		}
1631 		else
1632 		{
1633 			put_vanilla_header(h, p, mci);
1634 		}
1635 	}
1636 
1637 	/*
1638 	**  If we are converting this to a MIME message, add the
1639 	**  MIME headers (but not in MIME mode!).
1640 	*/
1641 
1642 #if MIME8TO7
1643 	if (bitset(MM_MIME8BIT, MimeMode) &&
1644 	    bitset(EF_HAS8BIT, e->e_flags) &&
1645 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1646 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1647 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1648 	    hvalue("MIME-Version", e->e_header) == NULL)
1649 	{
1650 		putline("MIME-Version: 1.0", mci);
1651 		if (hvalue("Content-Type", e->e_header) == NULL)
1652 		{
1653 			(void) sm_snprintf(obuf, sizeof obuf,
1654 					"Content-Type: text/plain; charset=%s",
1655 					defcharset(e));
1656 			putline(obuf, mci);
1657 		}
1658 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1659 			putline("Content-Transfer-Encoding: 8bit", mci);
1660 	}
1661 #endif /* MIME8TO7 */
1662 }
1663 /*
1664 **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1665 **
1666 **	Parameters:
1667 **		h -- the structure describing this header
1668 **		v -- the value of this header
1669 **		mci -- the connection info for output
1670 **
1671 **	Returns:
1672 **		none.
1673 */
1674 
1675 static void
1676 put_vanilla_header(h, v, mci)
1677 	HDR *h;
1678 	char *v;
1679 	MCI *mci;
1680 {
1681 	register char *nlp;
1682 	register char *obp;
1683 	int putflags;
1684 	char obuf[MAXLINE];
1685 
1686 	putflags = PXLF_HEADER;
1687 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1688 		putflags |= PXLF_STRIP8BIT;
1689 	(void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1690 	obp = obuf + strlen(obuf);
1691 	while ((nlp = strchr(v, '\n')) != NULL)
1692 	{
1693 		int l;
1694 
1695 		l = nlp - v;
1696 		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1697 			l = SPACELEFT(obuf, obp) - 1;
1698 
1699 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1700 		putxline(obuf, strlen(obuf), mci, putflags);
1701 		v += l + 1;
1702 		obp = obuf;
1703 		if (*v != ' ' && *v != '\t')
1704 			*obp++ = ' ';
1705 	}
1706 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1707 			   (int) (SPACELEFT(obuf, obp) - 1), v);
1708 	putxline(obuf, strlen(obuf), mci, putflags);
1709 }
1710 /*
1711 **  COMMAIZE -- output a header field, making a comma-translated list.
1712 **
1713 **	Parameters:
1714 **		h -- the header field to output.
1715 **		p -- the value to put in it.
1716 **		oldstyle -- true if this is an old style header.
1717 **		mci -- the connection information.
1718 **		e -- the envelope containing the message.
1719 **
1720 **	Returns:
1721 **		none.
1722 **
1723 **	Side Effects:
1724 **		outputs "p" to file "fp".
1725 */
1726 
1727 void
1728 commaize(h, p, oldstyle, mci, e)
1729 	register HDR *h;
1730 	register char *p;
1731 	bool oldstyle;
1732 	register MCI *mci;
1733 	register ENVELOPE *e;
1734 {
1735 	register char *obp;
1736 	int opos;
1737 	int omax;
1738 	bool firstone = true;
1739 	int putflags = PXLF_HEADER;
1740 	char obuf[MAXLINE + 3];
1741 
1742 	/*
1743 	**  Output the address list translated by the
1744 	**  mailer and with commas.
1745 	*/
1746 
1747 	if (tTd(14, 2))
1748 		sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1749 
1750 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1751 		putflags |= PXLF_STRIP8BIT;
1752 
1753 	obp = obuf;
1754 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
1755 			h->h_field);
1756 	opos = strlen(h->h_field) + 2;
1757 	if (opos > 202)
1758 		opos = 202;
1759 	obp += opos;
1760 	omax = mci->mci_mailer->m_linelimit - 2;
1761 	if (omax < 0 || omax > 78)
1762 		omax = 78;
1763 
1764 	/*
1765 	**  Run through the list of values.
1766 	*/
1767 
1768 	while (*p != '\0')
1769 	{
1770 		register char *name;
1771 		register int c;
1772 		char savechar;
1773 		int flags;
1774 		auto int status;
1775 
1776 		/*
1777 		**  Find the end of the name.  New style names
1778 		**  end with a comma, old style names end with
1779 		**  a space character.  However, spaces do not
1780 		**  necessarily delimit an old-style name -- at
1781 		**  signs mean keep going.
1782 		*/
1783 
1784 		/* find end of name */
1785 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1786 			p++;
1787 		name = p;
1788 		for (;;)
1789 		{
1790 			auto char *oldp;
1791 			char pvpbuf[PSBUFSIZE];
1792 
1793 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1794 				       sizeof pvpbuf, &oldp, NULL);
1795 			p = oldp;
1796 
1797 			/* look to see if we have an at sign */
1798 			while (*p != '\0' && isascii(*p) && isspace(*p))
1799 				p++;
1800 
1801 			if (*p != '@')
1802 			{
1803 				p = oldp;
1804 				break;
1805 			}
1806 			++p;
1807 			while (*p != '\0' && isascii(*p) && isspace(*p))
1808 				p++;
1809 		}
1810 		/* at the end of one complete name */
1811 
1812 		/* strip off trailing white space */
1813 		while (p >= name &&
1814 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1815 			p--;
1816 		if (++p == name)
1817 			continue;
1818 		savechar = *p;
1819 		*p = '\0';
1820 
1821 		/* translate the name to be relative */
1822 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1823 		if (bitset(H_FROM, h->h_flags))
1824 			flags |= RF_SENDERADDR;
1825 #if USERDB
1826 		else if (e->e_from.q_mailer != NULL &&
1827 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1828 		{
1829 			char *q;
1830 
1831 			q = udbsender(name, e->e_rpool);
1832 			if (q != NULL)
1833 				name = q;
1834 		}
1835 #endif /* USERDB */
1836 		status = EX_OK;
1837 		name = remotename(name, mci->mci_mailer, flags, &status, e);
1838 		if (*name == '\0')
1839 		{
1840 			*p = savechar;
1841 			continue;
1842 		}
1843 		name = denlstring(name, false, true);
1844 
1845 		/*
1846 		**  record data progress so DNS timeouts
1847 		**  don't cause DATA timeouts
1848 		*/
1849 
1850 		DataProgress = true;
1851 
1852 		/* output the name with nice formatting */
1853 		opos += strlen(name);
1854 		if (!firstone)
1855 			opos += 2;
1856 		if (opos > omax && !firstone)
1857 		{
1858 			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
1859 			putxline(obuf, strlen(obuf), mci, putflags);
1860 			obp = obuf;
1861 			(void) sm_strlcpy(obp, "        ", sizeof obp);
1862 			opos = strlen(obp);
1863 			obp += opos;
1864 			opos += strlen(name);
1865 		}
1866 		else if (!firstone)
1867 		{
1868 			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
1869 			obp += 2;
1870 		}
1871 
1872 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1873 			*obp++ = c;
1874 		firstone = false;
1875 		*p = savechar;
1876 	}
1877 	*obp = '\0';
1878 	putxline(obuf, strlen(obuf), mci, putflags);
1879 }
1880 /*
1881 **  COPYHEADER -- copy header list
1882 **
1883 **	This routine is the equivalent of newstr for header lists
1884 **
1885 **	Parameters:
1886 **		header -- list of header structures to copy.
1887 **		rpool -- resource pool, or NULL
1888 **
1889 **	Returns:
1890 **		a copy of 'header'.
1891 **
1892 **	Side Effects:
1893 **		none.
1894 */
1895 
1896 HDR *
1897 copyheader(header, rpool)
1898 	register HDR *header;
1899 	SM_RPOOL_T *rpool;
1900 {
1901 	register HDR *newhdr;
1902 	HDR *ret;
1903 	register HDR **tail = &ret;
1904 
1905 	while (header != NULL)
1906 	{
1907 		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
1908 		STRUCTCOPY(*header, *newhdr);
1909 		*tail = newhdr;
1910 		tail = &newhdr->h_link;
1911 		header = header->h_link;
1912 	}
1913 	*tail = NULL;
1914 
1915 	return ret;
1916 }
1917 /*
1918 **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
1919 **
1920 **	Run through all of the parameters of a MIME header and
1921 **	possibly truncate and rebalance the parameter according
1922 **	to MaxMimeFieldLength.
1923 **
1924 **	Parameters:
1925 **		h -- the header to truncate/rebalance
1926 **		e -- the current envelope
1927 **
1928 **	Returns:
1929 **		length of last offending field, 0 if all ok.
1930 **
1931 **	Side Effects:
1932 **		string modified in place
1933 */
1934 
1935 static size_t
1936 fix_mime_header(h, e)
1937 	HDR *h;
1938 	ENVELOPE *e;
1939 {
1940 	char *begin = h->h_value;
1941 	char *end;
1942 	size_t len = 0;
1943 	size_t retlen = 0;
1944 
1945 	if (begin == NULL || *begin == '\0')
1946 		return 0;
1947 
1948 	/* Split on each ';' */
1949 	while ((end = find_character(begin, ';')) != NULL)
1950 	{
1951 		char save = *end;
1952 		char *bp;
1953 
1954 		*end = '\0';
1955 
1956 		len = strlen(begin);
1957 
1958 		/* Shorten individual parameter */
1959 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
1960 		{
1961 			if (len < MaxMimeFieldLength)
1962 			{
1963 				/* we only rebalanced a bogus field */
1964 				sm_syslog(LOG_ALERT, e->e_id,
1965 					  "Fixed MIME %s header field (possible attack)",
1966 					  h->h_field);
1967 				if (tTd(34, 11))
1968 					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
1969 						   h->h_field);
1970 			}
1971 			else
1972 			{
1973 				/* we actually shortened the header */
1974 				retlen = len;
1975 			}
1976 		}
1977 
1978 		/* Collapse the possibly shortened string with rest */
1979 		bp = begin + strlen(begin);
1980 		if (bp != end)
1981 		{
1982 			char *ep = end;
1983 
1984 			*end = save;
1985 			end = bp;
1986 
1987 			/* copy character by character due to overlap */
1988 			while (*ep != '\0')
1989 				*bp++ = *ep++;
1990 			*bp = '\0';
1991 		}
1992 		else
1993 			*end = save;
1994 		if (*end == '\0')
1995 			break;
1996 
1997 		/* Move past ';' */
1998 		begin = end + 1;
1999 	}
2000 	return retlen;
2001 }
2002