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