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