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