2 * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, Inc. and its suppliers.
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.
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.
15 #include <sm/sendmail.h>
18 SM_RCSID("@(#)$Id: headers.c,v 8.320 2013-11-22 20:51:55 ca Exp $")
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 *));
26 ** SETUPHEADERS -- initialize headers in symbol table
41 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
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;
50 ** DOCHOMPHEADER -- process and save a header line.
52 ** Called by chompheader.
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.
61 ** flags for this header.
64 ** The header is saved on the header list.
65 ** Contents of 'line' are destroyed.
68 static struct hdrinfo NormalHeader = { NULL, 0, NULL };
69 static unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *));
72 dochompheader(line, pflag, hdrp, e)
78 unsigned char mid = '\0';
89 bool nullheader = false;
92 headeronly = hdrp != NULL;
96 /* strip off options */
99 if (!bitset(pflag, CHHDR_USER) && *p == '?')
104 q = strchr(++p, '?');
111 /* possibly macro conditional */
112 if (c == MACROEXPAND)
121 mid = (unsigned char) *p++;
139 mid = (unsigned char) macid(p);
140 if (bitset(0200, mid))
142 p += strlen(macname(mid)) + 2;
165 setbitn(bitidx(*p), mopts);
173 /* find canonical name */
175 while (isascii(*p) && isgraph(*p) && *p != ':')
178 while (SM_ISSPACE(*p))
180 if (*p++ != ':' || fname == fvalue)
183 syserr("553 5.3.0 header syntax error, line \"%s\"", line);
189 /* if the field is null, go ahead and use the default */
190 while (SM_ISSPACE(*p))
195 /* security scan: long field names are end-of-header */
196 if (strlen(fname) > 100)
199 /* check to see if it represents a ruleset call */
200 if (bitset(pflag, CHHDR_DEF))
204 (void) expand(fvalue, hbuf, sizeof(hbuf), e);
205 for (p = hbuf; SM_ISSPACE(*p); )
207 if ((*p++ & 0377) == CALLSUBR)
212 strc = *p == '+'; /* strip comments? */
215 if (strtorwset(p, &endp, ST_ENTER) > 0)
218 s = stab(fname, ST_HEADER, ST_ENTER);
220 s->s_header.hi_ruleset != NULL)
221 sm_syslog(LOG_WARNING, NOQID,
222 "Warning: redefined ruleset for header=%s, old=%s, new=%s",
224 s->s_header.hi_ruleset, p);
225 s->s_header.hi_ruleset = newstr(p);
227 s->s_header.hi_flags |= H_STRIPCOMM;
233 /* see if it is a known type */
234 s = stab(fname, ST_HEADER, ST_FIND);
243 sm_dprintf("no header flags match\n");
245 sm_dprintf("header match, flags=%lx, ruleset=%s\n",
247 hi->hi_ruleset == NULL ? "<NULL>"
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;
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);
261 /* if this means "end of header" quit now */
262 if (!headeronly && bitset(H_EOH, hi->hi_flags))
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.
273 if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
275 while ((p = strchr(fvalue, '\n')) != NULL)
280 ** If there is a check ruleset, verify it against the header.
283 if (bitset(pflag, CHHDR_CHECK))
288 rscheckflags = RSF_COUNT;
289 if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
290 rscheckflags |= RSF_UNSTRUCTURED;
292 /* no ruleset? look for default */
296 s = stab("*", ST_HEADER, ST_FIND);
299 rs = (&s->s_header)->hi_ruleset;
300 if (bitset((&s->s_header)->hi_flags,
302 rscheckflags |= RSF_RMCOMM;
305 else if (bitset(hi->hi_flags, H_STRIPCOMM))
306 rscheckflags |= RSF_RMCOMM;
310 char qval[MAXNAME_I];
317 /* - 3 to avoid problems with " at the end */
319 fvalue[k] != '\0' && l < sizeof(qval) - 3
320 && xlen < MAXNAME - 3;
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 */
335 qval[l++] = fvalue[k];
338 qval[l++] = fvalue[k];
345 qval[l++] = fvalue[k];
349 /* just for "completeness": xlen not used afterwards */
353 l = strlen(fvalue + k);
356 ** If there is something left in fvalue
357 ** then it has been truncated.
358 ** Note: the log entry might not be correct
359 ** in the EAI case: to get the "real" length
360 ** ilenx() would have to be applied to fvalue.
366 sm_syslog(LOG_WARNING, e->e_id,
367 "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
368 fname, rs, xlen + l, MAXNAME);
370 macdefine(&e->e_macro, A_TEMP,
371 macid("{currHeader}"), qval);
372 macdefine(&e->e_macro, A_TEMP,
373 macid("{hdr_name}"), fname);
375 (void) sm_snprintf(qval, sizeof(qval), "%d", k);
376 macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
377 if (bitset(H_FROM, hi->hi_flags))
378 macdefine(&e->e_macro, A_PERM,
379 macid("{addr_type}"), "h s");
380 else if (bitset(H_RCPT, hi->hi_flags))
381 macdefine(&e->e_macro, A_PERM,
382 macid("{addr_type}"), "h r");
384 macdefine(&e->e_macro, A_PERM,
385 macid("{addr_type}"), "h");
386 (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
387 NULL, e->e_id, NULL, NULL);
392 ** Drop explicit From: if same as what we would generate.
393 ** This is to make MH (which doesn't always give a full name)
394 ** insert the full name information in all circumstances.
399 if (!bitset(EF_RESENT, e->e_flags))
401 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
402 !bitset(EF_QUEUERUN, e->e_flags) && SM_STRCASEEQ(fname, p))
404 if (e->e_from.q_paddr != NULL &&
405 e->e_from.q_mailer != NULL &&
406 bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
407 (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
408 strcmp(fvalue, e->e_from.q_user) == 0))
412 sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n",
413 fvalue, e->e_from.q_paddr, e->e_from.q_user,
418 /* delete default value for this header */
419 for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
421 if (SM_STRCASEEQ(fname, h->h_field) &&
422 !bitset(H_USER, h->h_flags) &&
423 !bitset(H_FORCE, h->h_flags))
427 /* user-supplied value was null */
432 /* make this look like the user entered it */
433 h->h_flags |= H_USER;
436 ** If the MH hack is selected, allow to turn
437 ** it off via a mailer flag to avoid problems
438 ** with setups that remove the F flag from
442 if (bitnset(M_NOMHHACK,
443 e->e_from.q_mailer->m_flags))
445 h->h_flags &= ~H_CHECK;
452 /* copy conditions from default case */
453 memmove((char *) mopts, (char *) h->h_mflags,
460 /* create a new node */
461 h = (HDR *) sm_rpool_malloc_tagged_x(e->e_rpool, sizeof(*h), "header",
462 pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
463 h->h_field = sm_rpool_strdup_tagged_x(e->e_rpool, fname, "h_field",
464 pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
465 h->h_value = sm_rpool_strdup_tagged_x(e->e_rpool, fvalue, "h_value",
466 pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
468 memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
471 h->h_flags = hi->hi_flags;
472 if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
473 h->h_flags |= H_USER;
475 /* strip EOH flag if parsing MIME headers */
477 h->h_flags &= ~H_EOH;
478 if (bitset(pflag, CHHDR_DEF))
479 h->h_flags |= H_DEFAULT;
480 if (cond || mid != '\0')
481 h->h_flags |= H_CHECK;
483 /* hack to see if this is a new format message */
484 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
485 bitset(H_RCPT|H_FROM, h->h_flags) &&
486 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
487 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
489 e->e_flags &= ~EF_OLDSTYLE;
496 ** CHOMPHEADER -- process and save a header line.
498 ** Called by collect, readcf, and readqf to deal with header lines.
499 ** This is just a wrapper for dochompheader().
502 ** line -- header as a text line.
503 ** pflag -- flags for chompheader() (from sendmail.h)
504 ** hdrp -- a pointer to the place to save the header.
505 ** e -- the envelope including this header.
508 ** flags for this header.
511 ** The header is saved on the header list.
512 ** Contents of 'line' are destroyed.
516 chompheader(line, pflag, hdrp, e)
520 register ENVELOPE *e;
526 sm_dprintf("chompheader: ");
527 xputs(sm_debug_file(), line);
531 /* quote this if user (not config file) input */
532 if (bitset(pflag, CHHDR_USER))
534 char xbuf[MAXLINE]; /* EAI:ok; actual buffer might be greater */
538 xbufs = sizeof(xbuf);
539 xbp = quote_internal_chars(line, xbuf, &xbufs, NULL);
542 sm_dprintf("chompheader: quoted: ");
543 xputs(sm_debug_file(), xbp);
546 rval = dochompheader(xbp, pflag, hdrp, e);
551 rval = dochompheader(line, pflag, hdrp, e);
557 ** ALLOCHEADER -- allocate a header entry
560 ** field -- the name of the header field (will not be copied).
561 ** value -- the value of the field (will be copied).
562 ** flags -- flags to add to h_flags.
563 ** rp -- resource pool for allocations
564 ** space -- add leading space?
567 ** Pointer to a newly allocated and populated HDR.
570 ** o field and value must be in internal format, i.e.,
571 ** metacharacters must be "quoted", see quote_internal_chars().
572 ** o maybe add more flags to decide:
573 ** - what to copy (field/value)
574 ** - whether to convert value to an internal format
578 allocheader(field, value, flags, rp, space)
588 /* find info struct */
589 s = stab(field, ST_HEADER, ST_FIND);
591 /* allocate space for new header */
592 h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
600 SM_ASSERT(l + 2 > l);
601 n = sm_rpool_malloc_x(rp, l + 2);
604 sm_strlcpy(n + 1, value, l + 1);
608 h->h_value = sm_rpool_strdup_x(rp, value);
611 h->h_flags |= s->s_header.hi_flags;
612 clrbitmap(h->h_mflags);
619 ** ADDHEADER -- add a header entry to the end of the queue.
621 ** This bypasses the special checking of chompheader.
624 ** field -- the name of the header field (will not be copied).
625 ** value -- the value of the field (will be copied).
626 ** flags -- flags to add to h_flags.
628 ** space -- add leading space?
634 ** adds the field on the list of headers for this envelope.
636 ** Notes: field and value must be in internal format, i.e.,
637 ** metacharacters must be "quoted", see quote_internal_chars().
641 addheader(field, value, flags, e, space)
650 HDR **hdrlist = &e->e_header;
652 /* find current place in list -- keep back pointer? */
653 for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
655 if (SM_STRCASEEQ(field, h->h_field))
659 /* allocate space for new header */
660 h = allocheader(field, value, flags, e->e_rpool, space);
666 ** INSHEADER -- insert a header entry at the specified index
667 ** This bypasses the special checking of chompheader.
670 ** idx -- index into the header list at which to insert
671 ** field -- the name of the header field (will be copied).
672 ** value -- the value of the field (will be copied).
673 ** flags -- flags to add to h_flags.
675 ** space -- add leading space?
681 ** inserts the field on the list of headers for this envelope.
684 ** - field and value must be in internal format, i.e.,
685 ** metacharacters must be "quoted", see quote_internal_chars().
686 ** - the header list contains headers that might not be
687 ** sent "out" (see putheader(): "skip"), hence there is no
688 ** reliable way to insert a header at an exact position
689 ** (except at the front or end).
693 insheader(idx, field, value, flags, e, space)
701 HDR *h, *srch, *last = NULL;
703 /* allocate space for new header */
704 h = allocheader(field, value, flags, e->e_rpool, space);
706 /* find insertion position */
707 for (srch = e->e_header; srch != NULL && idx > 0;
708 srch = srch->h_link, idx--)
711 if (e->e_header == NULL)
716 else if (srch == NULL)
718 SM_ASSERT(last != NULL);
724 h->h_link = srch->h_link;
730 ** HVALUE -- return value of a header.
732 ** Only "real" fields (i.e., ones that have not been supplied
733 ** as a default) are used.
736 ** field -- the field name.
737 ** header -- the header list.
740 ** pointer to the value part (internal format).
741 ** NULL if not found.
748 hvalue(field, header)
754 for (h = header; h != NULL; h = h->h_link)
756 if (!bitset(H_DEFAULT, h->h_flags) &&
757 SM_STRCASEEQ(h->h_field, field))
764 while (SM_ISSPACE(*s))
773 ** ISHEADER -- predicate telling if argument is a header.
775 ** A line is a header if it has a single word followed by
776 ** optional white space followed by a colon.
778 ** Header fields beginning with two dashes, although technically
779 ** permitted by RFC822, are automatically rejected in order
780 ** to make MIME work out. Without this we could have a technically
781 ** legal header such as ``--"foo:bar"'' that would also be a legal
785 ** h -- string to check for possible headerness.
788 ** true if h is a header.
802 if (s[0] == '-' && s[1] == '-')
805 while (*s > ' ' && *s != ':' && *s != '\0')
811 /* following technically violates RFC822 */
812 while (SM_ISSPACE(*s))
819 ** EATHEADER -- run through the stored header and extract info.
822 ** e -- the envelope to process.
823 ** full -- if set, do full processing (e.g., compute
824 ** message priority). This should not be set
825 ** when reading a queue file because some info
826 ** needed to compute the priority is wrong.
827 ** log -- call logsender()?
833 ** Sets a bunch of global variables from information
834 ** in the collected header.
838 eatheader(e, full, log)
839 register ENVELOPE *e;
849 ** Set up macros for possible expansion in headers.
852 macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
853 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
854 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
855 macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
857 macdefine(&e->e_macro, A_PERM, 'u', NULL);
859 /* full name of from person */
860 p = hvalue("full-name", e->e_header);
863 if (!rfc822_string(p))
866 ** Quote a full name with special characters
867 ** as a comment so crackaddr() doesn't destroy
868 ** the name portion of the address.
871 p = addquotes(p, e->e_rpool);
873 macdefine(&e->e_macro, A_PERM, 'x', p);
877 sm_dprintf("----- collected header -----\n");
879 for (h = e->e_header; h != NULL; h = h->h_link)
882 sm_dprintf("%s:", h->h_field);
883 if (h->h_value == NULL)
886 sm_dprintf("<NULL>\n");
890 /* do early binding */
891 if (bitset(H_DEFAULT, h->h_flags) &&
892 !bitset(H_BINDLATE, h->h_flags))
897 xputs(sm_debug_file(), h->h_value);
900 expand(h->h_value, buf, sizeof(buf), e);
901 if (buf[0] != '\0' &&
902 (buf[0] != ' ' || buf[1] != '\0'))
904 if (bitset(H_FROM, h->h_flags))
905 expand(crackaddr(buf, e),
906 buf, sizeof(buf), e);
907 h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
908 h->h_flags &= ~H_DEFAULT;
913 xputs(sm_debug_file(), h->h_value);
917 /* count the number of times it has been processed */
918 if (bitset(H_TRACE, h->h_flags))
921 /* send to this person if we so desire */
922 if (GrabTo && bitset(H_RCPT, h->h_flags) &&
923 !bitset(H_DEFAULT, h->h_flags) &&
924 (!bitset(EF_RESENT, e->e_flags) ||
925 bitset(H_RESENT, h->h_flags)))
928 int saveflags = e->e_flags;
931 (void) sendtolist(denlstring(h->h_value, true, false),
932 NULLADDR, &e->e_sendqueue, 0, e);
936 ** Change functionality so a fatal error on an
937 ** address doesn't affect the entire envelope.
940 /* delete fatal errors generated by this address */
941 if (!bitset(EF_FATALERRS, saveflags))
942 e->e_flags &= ~EF_FATALERRS;
946 /* save the message-id for logging */
947 p = "resent-message-id";
948 if (!bitset(EF_RESENT, e->e_flags))
950 if (SM_STRCASEEQ(h->h_field, p))
952 e->e_msgid = h->h_value;
953 while (SM_ISSPACE(*e->e_msgid))
955 macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
960 sm_dprintf("----------------------------\n");
962 /* if we are just verifying (that is, sendmail -t -bv), drop out now */
963 if (OpMode == MD_VERIFY)
966 /* store hop count */
967 if (hopcnt > e->e_hopcount)
969 e->e_hopcount = hopcnt;
970 (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
971 macdefine(&e->e_macro, A_TEMP, 'c', buf);
974 /* message priority */
975 p = hvalue("precedence", e->e_header);
977 e->e_class = priencode(p);
979 e->e_timeoutclass = TOC_NONURGENT;
980 else if (e->e_class > 0)
981 e->e_timeoutclass = TOC_URGENT;
984 e->e_msgpriority = e->e_msgsize
985 - e->e_class * WkClassFact
986 + e->e_nrcpts * WkRecipFact;
989 /* check for DSN to properly set e_timeoutclass */
990 p = hvalue("content-type", e->e_header);
995 char pvpbuf[MAXLINE];
996 extern unsigned char MimeTokenTab[256];
998 /* tokenize header */
1001 pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
1002 MimeTokenTab, false);
1005 /* Check if multipart/report */
1006 if (pvp != NULL && pvp[0] != NULL &&
1007 pvp[1] != NULL && pvp[2] != NULL &&
1008 SM_STRCASEEQ(*pvp++, "multipart") &&
1009 strcmp(*pvp++, "/") == 0 &&
1010 SM_STRCASEEQ(*pvp++, "report"))
1012 /* Look for report-type=delivery-status */
1013 while (*pvp != NULL)
1015 /* skip to semicolon separator */
1016 while (*pvp != NULL && strcmp(*pvp, ";") != 0)
1019 /* skip semicolon */
1020 if (*pvp++ == NULL || *pvp == NULL)
1023 /* look for report-type */
1024 if (!SM_STRCASEEQ(*pvp++, "report-type"))
1028 if (*pvp == NULL || strcmp(*pvp, "=") != 0)
1032 if (*++pvp != NULL &&
1033 SM_STRCASEEQ(*pvp, "delivery-status"))
1034 e->e_timeoutclass = TOC_DSN;
1036 /* found report-type, no need to continue */
1042 /* message timeout priority */
1043 p = hvalue("priority", e->e_header);
1046 /* (this should be in the configuration file) */
1047 if (SM_STRCASEEQ(p, "urgent"))
1048 e->e_timeoutclass = TOC_URGENT;
1049 else if (SM_STRCASEEQ(p, "normal"))
1050 e->e_timeoutclass = TOC_NORMAL;
1051 else if (SM_STRCASEEQ(p, "non-urgent"))
1052 e->e_timeoutclass = TOC_NONURGENT;
1053 else if (bitset(EF_RESPONSE, e->e_flags))
1054 e->e_timeoutclass = TOC_DSN;
1056 else if (bitset(EF_RESPONSE, e->e_flags))
1057 e->e_timeoutclass = TOC_DSN;
1059 /* date message originated */
1060 p = hvalue("posted-date", e->e_header);
1062 p = hvalue("date", e->e_header);
1064 macdefine(&e->e_macro, A_PERM, 'a', p);
1066 /* check to see if this is a MIME message */
1067 if ((e->e_bodytype != NULL &&
1068 SM_STRCASEEQ(e->e_bodytype, "8bitmime")) ||
1069 hvalue("MIME-Version", e->e_header) != NULL)
1071 e->e_flags |= EF_IS_MIME;
1073 e->e_bodytype = "8BITMIME";
1075 else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
1077 /* this may be an RFC 1049 message */
1078 p = strpbrk(p, ";/");
1079 if (p == NULL || *p == ';')
1082 e->e_flags |= EF_DONT_MIME;
1087 ** From person in antiquated ARPANET mode
1088 ** required by UK Grey Book e-mail gateways (sigh)
1091 if (OpMode == MD_ARPAFTP)
1093 register struct hdrinfo *hi;
1095 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
1097 if (bitset(H_FROM, hi->hi_flags) &&
1098 (!bitset(H_RESENT, hi->hi_flags) ||
1099 bitset(EF_RESENT, e->e_flags)) &&
1100 (p = hvalue(hi->hi_field, e->e_header)) != NULL)
1103 if (hi->hi_field != NULL)
1106 sm_dprintf("eatheader: setsender(*%s == %s)\n",
1108 setsender(p, e, NULL, '\0', true);
1113 ** Log collection information.
1117 sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n",
1118 e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel,
1120 if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
1122 logsender(e, e->e_msgid);
1123 e->e_flags &= ~EF_LOGSENDER;
1128 ** LOGSENDER -- log sender information
1131 ** e -- the envelope to log
1132 ** msgid -- the message id
1138 #define XBUFLEN MAXNAME
1139 #if (SYSLOG_BUFSIZE) >= 256
1140 # ifndef MSGIDLOGLEN
1141 # define MSGIDLOGLEN 100
1142 # define FIRSTLOGLEN 850
1144 # if MSGIDLOGLEN < 100
1145 # error "MSGIDLOGLEN too short"
1147 /* XREF: this is "sizeof(sbuf)", see above */
1148 # if MSGIDLOGLEN >= MAXLINE / 2
1149 # error "MSGIDLOGLEN too long"
1152 /* 850 - 100 for original MSGIDLOGLEN */
1153 # define FIRSTLOGLEN (750 + MSGIDLOGLEN)
1155 /* check that total length is ok */
1156 # if FIRSTLOGLEN + 200 >= MAXLINE
1157 # error "MSGIDLOGLEN too long"
1159 # if MSGIDLOGLEN > MAXNAME
1161 # define XBUFLEN MSGIDLOGLEN
1164 #endif /* (SYSLOG_BUFSIZE) >= 256 */
1168 register ENVELOPE *e;
1174 char hbuf[MAXNAME + 1]; /* EAI:ok; restricted to short size */
1175 char sbuf[MAXLINE + 1]; /* EAI:ok; XREF: see also MSGIDLOGLEN */
1176 #if _FFR_8BITENVADDR
1177 char xbuf[XBUFLEN + 1]; /* EAI:ok */
1181 if (bitset(EF_RESPONSE, e->e_flags))
1182 name = "[RESPONSE]";
1183 else if ((name = macvalue('_', e)) != NULL)
1186 else if (RealHostName == NULL)
1188 else if (RealHostName[0] == '[')
1189 name = RealHostName;
1193 (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
1194 if (RealHostAddr.sa.sa_family != 0)
1196 p = &hbuf[strlen(hbuf)];
1197 (void) sm_snprintf(p, SPACELEFT(hbuf, p),
1199 anynet_ntoa(&RealHostAddr));
1203 #if (SYSLOG_BUFSIZE) >= 256
1205 if (NULL != e->e_from.q_paddr)
1207 xstr = e->e_from.q_paddr;
1208 # if _FFR_8BITENVADDR
1209 (void) dequote_internal_chars(e->e_from.q_paddr, xbuf, sizeof(xbuf));
1215 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1216 "from=%.200s, size=%ld, class=%d, nrcpts=%d", xstr,
1217 PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1221 # if _FFR_8BITENVADDR
1222 (void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf));
1225 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1226 ", msgid=%.*s", MSGIDLOGLEN, msgid);
1229 if (e->e_bodytype != NULL)
1231 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1232 ", bodytype=%.20s", e->e_bodytype);
1235 p = macvalue('r', e);
1238 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1239 ", proto=%.20s", p);
1242 p = macvalue(macid("{daemon_name}"), e);
1245 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1246 ", daemon=%.20s", p);
1250 LOG_MORE(sbuf, sbp);
1252 p = macvalue(macid("{auth_type}"), e);
1255 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p);
1258 # endif /* _FFR_LOG_MORE1 */
1259 sm_syslog(LOG_INFO, e->e_id, "%.*s, relay=%s", FIRSTLOGLEN, sbuf, name);
1261 #else /* (SYSLOG_BUFSIZE) >= 256 */
1263 sm_syslog(LOG_INFO, e->e_id,
1265 e->e_from.q_paddr == NULL ? "<NONE>"
1266 : shortenstring(e->e_from.q_paddr,
1268 sm_syslog(LOG_INFO, e->e_id,
1269 "size=%ld, class=%ld, nrcpts=%d",
1270 PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1273 # if _FFR_8BITENVADDR
1274 (void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf));
1277 sm_syslog(LOG_INFO, e->e_id,
1279 shortenstring(msgid, 83));
1283 if (e->e_bodytype != NULL)
1285 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1286 "bodytype=%.20s, ", e->e_bodytype);
1289 p = macvalue('r', e);
1292 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1293 "proto=%.20s, ", p);
1296 sm_syslog(LOG_INFO, e->e_id,
1297 "%.400srelay=%s", sbuf, name);
1298 #endif /* (SYSLOG_BUFSIZE) >= 256 */
1302 ** PRIENCODE -- encode external priority names into internal values.
1305 ** p -- priority in ascii.
1308 ** priority as a numeric level.
1320 for (i = 0; i < NumPriorities; i++)
1322 if (SM_STRCASEEQ(p, Priorities[i].pri_name))
1323 return Priorities[i].pri_val;
1326 /* unknown priority */
1331 ** CRACKADDR -- parse an address and turn it into a macro
1333 ** This doesn't actually parse the address -- it just extracts
1334 ** it and replaces it with "$g". The parse is totally ad hoc
1335 ** and isn't even guaranteed to leave something syntactically
1336 ** identical to what it started with. However, it does leave
1337 ** something semantically identical if possible, else at least
1338 ** syntactically correct.
1340 ** For example, it changes "Real Name <real@example.com> (Comment)"
1341 ** to "Real Name <$g> (Comment)".
1343 ** This algorithm has been cleaned up to handle a wider range
1344 ** of cases -- notably quoted and backslash escaped strings.
1345 ** This modification makes it substantially better at preserving
1346 ** the original syntax.
1349 ** addr -- the address to be cracked. [A]
1350 ** e -- the current envelope.
1353 ** a pointer to the new version.
1359 ** The return value is saved in static storage and should
1360 ** be copied if it is to be reused.
1363 #define SM_HAVE_ROOMB ((bp < buflim) && (buflim <= bufend))
1365 # define SM_HAVE_ROOM ((xlen < MAXNAME) && SM_HAVE_ROOMB)
1367 # define SM_HAVE_ROOM SM_HAVE_ROOMB
1371 ** Append a character to bp if we have room.
1372 ** If not, punt and return $g.
1375 #define SM_APPEND_CHAR(c) \
1386 # error "MAXNAME must be at least 10"
1391 register char *addr;
1396 int cmtlev; /* comment level in input string */
1397 int realcmtlev; /* comment level in output string */
1398 int anglelev; /* angle level in input string */
1399 int copylev; /* 0 == in address, >0 copying */
1400 int bracklev; /* bracket level for IPv6 addr check */
1401 bool addangle; /* put closing angle in output */
1402 bool qmode; /* quoting in original string? */
1403 bool realqmode; /* quoting in output string? */
1404 bool putgmac = false; /* already wrote $g */
1405 bool quoteit = false; /* need to quote next character */
1406 bool gotangle = false; /* found first '<' */
1407 bool gotcolon = false; /* found a ':' */
1413 static char buf[MAXNAME_I + 1]; /* XXX: EAI? */
1417 sm_dprintf("crackaddr(%s)\n", addr);
1419 buflim = bufend = &buf[sizeof(buf) - 1];
1422 /* skip over leading spaces but preserve them */
1423 while (*addr != '\0' && SM_ISSPACE(*addr))
1425 SM_APPEND_CHAR(*addr);
1431 ** Start by assuming we have no angle brackets. This will be
1432 ** adjusted later if we find them.
1435 p = addrhead = addr;
1436 copylev = anglelev = cmtlev = realcmtlev = 0;
1438 qmode = realqmode = addangle = false;
1440 while ((c = *p++) != '\0')
1443 ** Try to keep legal syntax using spare buffer space
1444 ** (maintained by buflim).
1450 /* check for backslash escapes */
1453 /* arrange to quote the address */
1454 if (cmtlev <= 0 && !qmode)
1457 if ((c = *p++) == '\0')
1468 /* check for quoted strings */
1469 if (c == '"' && cmtlev <= 0)
1472 if (copylev > 0 && SM_HAVE_ROOM)
1478 realqmode = !realqmode;
1485 /* check for comments */
1490 /* allow space for closing paren */
1498 SM_APPEND_CHAR(' ');
1519 /* syntax error: unmatched ) */
1520 if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1524 /* count nesting on [ ... ] (for IPv6 domain literals) */
1530 /* check for group: list; syntax */
1531 if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1532 !gotcolon && !ColonOkInAddr)
1537 ** Check for DECnet phase IV ``::'' (host::user)
1538 ** or DECnet phase V ``:.'' syntaxes. The latter
1539 ** covers ``user@DEC:.tay.myhost'' and
1540 ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
1543 if (*p == ':' || *p == '.')
1545 if (cmtlev <= 0 && !qmode)
1561 SM_APPEND_CHAR('"');
1563 /* back up over the ':' and any spaces */
1566 isascii(*--p) && isspace(*p))
1570 for (q = addrhead; q < p; )
1573 if (quoteit && c == '"')
1574 SM_APPEND_CHAR('\\');
1579 if (bp == &bufhead[1])
1582 SM_APPEND_CHAR('"');
1583 while ((c = *p++) != ':')
1588 /* any trailing white space is part of group: */
1589 while (SM_ISSPACE(*p))
1595 putgmac = quoteit = false;
1601 if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1604 /* check for characters that may have to be quoted */
1605 if (strchr(MustQuoteChars, c) != NULL)
1608 ** If these occur as the phrase part of a <>
1609 ** construct, but are not inside of () or already
1610 ** quoted, they will have to be quoted. Note that
1611 ** now (but don't actually do the quoting).
1614 if (cmtlev <= 0 && !qmode)
1618 /* check for angle brackets */
1623 /* assume first of two angles is bogus */
1628 /* oops -- have to change our mind */
1640 SM_APPEND_CHAR('"');
1642 /* back up over the '<' and any spaces */
1645 isascii(*--p) && isspace(*p))
1649 for (q = addrhead; q < p; )
1652 if (quoteit && c == '"')
1654 SM_APPEND_CHAR('\\');
1665 SM_APPEND_CHAR('"');
1666 while ((c = *p++) != '<')
1671 putgmac = quoteit = false;
1687 else if (SM_HAVE_ROOM)
1689 /* syntax error: unmatched > */
1690 if (copylev > 0 && bp > bufhead)
1700 /* must be a real address character */
1702 if (copylev <= 0 && !putgmac)
1704 if (bp > buf && bp[-1] == ')')
1705 SM_APPEND_CHAR(' ');
1706 SM_APPEND_CHAR(MACROEXPAND);
1707 SM_APPEND_CHAR('g');
1712 /* repair any syntactic damage */
1713 if (realqmode && bp < bufend)
1715 while (realcmtlev-- > 0 && bp < bufend)
1717 if (addangle && bp < bufend)
1724 /* String too long, punt */
1726 buf[1] = MACROEXPAND;
1730 sm_syslog(LOG_ALERT, e->e_id,
1731 "Dropped invalid comments from header address");
1736 sm_dprintf("crackaddr=>`");
1737 xputs(sm_debug_file(), buf);
1744 ** PUTHEADER -- put the header part of a message from the in-core copy
1747 ** mci -- the connection information.
1748 ** hdr -- the header to put.
1749 ** e -- envelope to use.
1750 ** flags -- MIME conversion flags.
1753 ** true iff header part was written successfully
1760 putheader(mci, hdr, e, flags)
1763 register ENVELOPE *e;
1767 char buf[SM_MAX(MAXLINE,BUFSIZ)];
1771 sm_dprintf("--- putheader, mailer = %s ---\n",
1772 mci->mci_mailer->m_name);
1775 ** If we're in MIME mode, we're not really in the header of the
1776 ** message, just the header of one of the parts of the body of
1777 ** the message. Therefore MCIF_INHEADER should not be turned on.
1780 if (!bitset(MCIF_INMIME, mci->mci_flags))
1781 mci->mci_flags |= MCIF_INHEADER;
1783 for (h = hdr; h != NULL; h = h->h_link)
1785 register char *p = h->h_value;
1790 sm_dprintf(" %s:", h->h_field);
1791 xputs(sm_debug_file(), p);
1794 /* Skip empty headers */
1797 #if _FFR_8BITENVADDR
1798 (void) dequote_internal_chars(p, buf, sizeof(buf));
1801 /* heuristic shortening of MIME fields to avoid MUA overflows */
1802 if (MaxMimeFieldLength > 0 &&
1803 wordinclass(h->h_field,
1804 macid("{checkMIMEFieldHeaders}")))
1808 len = fix_mime_header(h, e);
1811 sm_syslog(LOG_ALERT, e->e_id,
1812 "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1813 h->h_field, (unsigned long) len);
1815 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
1817 (unsigned long) len);
1821 if (MaxMimeHeaderLength > 0 &&
1822 wordinclass(h->h_field,
1823 macid("{checkMIMETextHeaders}")))
1828 if (len > (size_t) MaxMimeHeaderLength)
1830 h->h_value[MaxMimeHeaderLength - 1] = '\0';
1831 sm_syslog(LOG_ALERT, e->e_id,
1832 "Truncated long MIME %s header (length = %ld) (possible attack)",
1833 h->h_field, (unsigned long) len);
1835 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1837 (unsigned long) len);
1841 if (MaxMimeHeaderLength > 0 &&
1842 wordinclass(h->h_field,
1843 macid("{checkMIMEHeaders}")))
1847 len = strlen(h->h_value);
1848 if (shorten_rfc822_string(h->h_value,
1849 MaxMimeHeaderLength))
1851 if (len < MaxMimeHeaderLength)
1853 /* we only rebalanced a bogus header */
1854 sm_syslog(LOG_ALERT, e->e_id,
1855 "Fixed MIME %s header (possible attack)",
1858 sm_dprintf(" fixed MIME %s header (possible attack)\n",
1863 /* we actually shortened header */
1864 sm_syslog(LOG_ALERT, e->e_id,
1865 "Truncated long MIME %s header (length = %ld) (possible attack)",
1867 (unsigned long) len);
1869 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1871 (unsigned long) len);
1877 ** Suppress Content-Transfer-Encoding: if we are MIMEing
1878 ** and we are potentially converting from 8 bit to 7 bit
1879 ** MIME. If converting, add a new CTE header in
1883 if (bitset(H_CTE, h->h_flags) &&
1884 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1886 !bitset(M87F_NO8TO7, flags))
1889 sm_dprintf(" (skipped (content-transfer-encoding))\n");
1893 if (bitset(MCIF_INMIME, mci->mci_flags))
1897 if (!put_vanilla_header(h, p, mci))
1902 if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1903 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1904 (h->h_macro == '\0' ||
1905 (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1909 sm_dprintf(" (skipped)\n");
1913 /* handle Resent-... headers specially */
1914 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1917 sm_dprintf(" (skipped (resent))\n");
1921 /* suppress return receipts if requested */
1922 if (bitset(H_RECEIPTTO, h->h_flags) &&
1923 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1926 sm_dprintf(" (skipped (receipt))\n");
1930 /* macro expand value if generated internally */
1931 if (bitset(H_DEFAULT, h->h_flags) ||
1932 bitset(H_BINDLATE, h->h_flags))
1934 expand(p, buf, sizeof(buf), e);
1939 sm_dprintf(" (skipped -- null value)\n");
1944 if (bitset(H_BCC, h->h_flags) && !KeepBcc)
1946 /* Bcc: field -- either truncate or delete */
1947 if (bitset(EF_DELETE_BCC, e->e_flags))
1950 sm_dprintf(" (skipped -- bcc)\n");
1954 /* no other recipient headers: truncate value */
1955 (void) sm_strlcpyn(obuf, sizeof(obuf), 2,
1957 if (!putline(obuf, mci))
1966 if (bitset(H_FROM|H_RCPT, h->h_flags))
1969 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1971 if (bitset(H_FROM, h->h_flags))
1973 if (!commaize(h, p, oldstyle, mci, e,
1974 PXLF_HEADER | PXLF_STRIPMQUOTE)
1975 && bitnset(M_xSMTP, mci->mci_mailer->m_flags))
1980 if (!put_vanilla_header(h, p, mci))
1986 ** If we are converting this to a MIME message, add the
1987 ** MIME headers (but not in MIME mode!).
1991 if (bitset(MM_MIME8BIT, MimeMode) &&
1992 bitset(EF_HAS8BIT, e->e_flags) &&
1993 !bitset(EF_DONT_MIME, e->e_flags) &&
1994 !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1995 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1996 hvalue("MIME-Version", e->e_header) == NULL)
1998 if (!putline("MIME-Version: 1.0", mci))
2000 if (hvalue("Content-Type", e->e_header) == NULL)
2002 (void) sm_snprintf(obuf, sizeof(obuf),
2003 "Content-Type: text/plain; charset=%s",
2005 if (!putline(obuf, mci))
2008 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
2009 && !putline("Content-Transfer-Encoding: 8bit", mci))
2012 #endif /* MIME8TO7 */
2020 ** PUT_VANILLA_HEADER -- output a fairly ordinary header
2023 ** h -- the structure describing this header
2024 ** v -- the value of this header
2025 ** mci -- the connection info for output
2028 ** true iff header was written successfully
2032 put_vanilla_header(h, v, mci)
2040 char obuf[MAXLINE + 256]; /* additional length for h_field */
2042 putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
2043 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2044 putflags |= PXLF_STRIP8BIT;
2045 (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
2046 obp = obuf + strlen(obuf);
2047 while ((nlp = strchr(v, '\n')) != NULL)
2054 ** XXX This is broken for SPACELEFT()==0
2055 ** However, SPACELEFT() is always > 0 unless MAXLINE==1.
2058 if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
2059 l = SPACELEFT(obuf, obp) - 1;
2061 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
2062 if (!putxline(obuf, strlen(obuf), mci, putflags))
2066 if (*v != ' ' && *v != '\t')
2070 /* XXX This is broken for SPACELEFT()==0 */
2071 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
2072 (int) (SPACELEFT(obuf, obp) - 1), v);
2073 return putxline(obuf, strlen(obuf), mci, putflags);
2080 ** COMMAIZE -- output a header field, making a comma-translated list.
2083 ** h -- the header field to output.
2084 ** p -- the value to put in it.
2085 ** oldstyle -- true if this is an old style header.
2086 ** mci -- the connection information.
2087 ** e -- the envelope containing the message.
2088 ** putflags -- flags for putxline()
2091 ** true iff header field was written successfully
2094 ** outputs "p" to "mci".
2098 commaize(h, p, oldstyle, mci, e, putflags)
2103 register ENVELOPE *e;
2107 int opos, omax, spaces;
2108 bool firstone = true;
2110 char obuf[MAXLINE + 3];
2113 ** Output the address list translated by the
2114 ** mailer and with commas.
2118 sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
2120 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2121 putflags |= PXLF_STRIP8BIT;
2124 /* activate this per mailer? */
2125 if (bitset(H_FROM, h->h_flags) && bitset(H_ASIS, h->h_flags))
2127 (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:%s", h->h_field,
2129 return putxline(obuf, strlen(obuf), mci, putflags);
2134 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2135 /* opos = strlen(obp); instead of the next 3 lines? */
2136 opos = strlen(h->h_field) + 1;
2142 while (*p != '\0' && SM_ISSPACE(*p))
2149 SM_ASSERT(sizeof(obuf) > opos * 2);
2152 ** Restrict number of spaces to half the length of buffer
2153 ** so the header field body can be put in here too.
2154 ** Note: this is a hack...
2157 if (spaces > sizeof(obuf) / 2)
2158 spaces = sizeof(obuf) / 2;
2159 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2163 SM_ASSERT(obp < &obuf[MAXLINE]);
2166 omax = mci->mci_mailer->m_linelimit - 2;
2167 if (omax < 0 || omax > 78)
2171 ** Run through the list of values.
2176 register char *name;
2183 ** Find the end of the name. New style names
2184 ** end with a comma, old style names end with
2185 ** a space character. However, spaces do not
2186 ** necessarily delimit an old-style name -- at
2187 ** signs mean keep going.
2190 /* find end of name */
2191 while ((SM_ISSPACE(*p)) || *p == ',')
2198 char pvpbuf[PSBUFSIZE];
2200 res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2201 sizeof(pvpbuf), &oldp, ExtTokenTab, false);
2203 #if _FFR_IGNORE_BOGUS_ADDR
2204 /* ignore addresses that can't be parsed */
2210 #endif /* _FFR_IGNORE_BOGUS_ADDR */
2212 /* look to see if we have an at sign */
2213 while (*p != '\0' && SM_ISSPACE(*p))
2222 while (*p != '\0' && SM_ISSPACE(*p))
2225 /* at the end of one complete name */
2227 /* strip off trailing white space */
2229 ((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
2235 ** if prescan() failed go a bit backwards; this is a hack,
2236 ** there should be some better error recovery.
2239 if (res == NULL && p > name &&
2240 !((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
2245 /* translate the name to be relative */
2246 flags = RF_HEADERADDR|RF_ADDDOMAIN;
2247 if (bitset(H_FROM, h->h_flags))
2248 flags |= RF_SENDERADDR;
2250 else if (e->e_from.q_mailer != NULL &&
2251 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
2255 q = udbsender(name, e->e_rpool);
2261 name = remotename(name, mci->mci_mailer, flags, &status, e);
2262 if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags))
2264 if (status == EX_TEMPFAIL)
2265 mci->mci_flags |= MCIF_NOTSTICKY;
2273 name = denlstring(name, false, true);
2275 /* output the name with nice formatting */
2276 opos += strlen(name);
2279 if (opos > omax && !firstone)
2281 (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2282 if (!putxline(obuf, strlen(obuf), mci, putflags))
2285 (void) sm_strlcpy(obp, " ", sizeof(obuf));
2288 opos += strlen(name);
2292 (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2296 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2301 if (obp < &obuf[sizeof(obuf)])
2304 obuf[sizeof(obuf) - 1] = '\0';
2305 return putxline(obuf, strlen(obuf), mci, putflags);
2312 ** COPYHEADER -- copy header list
2314 ** This routine is the equivalent of newstr for header lists
2317 ** header -- list of header structures to copy.
2318 ** rpool -- resource pool, or NULL
2321 ** a copy of 'header'.
2328 copyheader(header, rpool)
2329 register HDR *header;
2332 register HDR *newhdr;
2334 register HDR **tail = &ret;
2336 while (header != NULL)
2338 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
2339 STRUCTCOPY(*header, *newhdr);
2341 tail = &newhdr->h_link;
2342 header = header->h_link;
2350 ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
2352 ** Run through all of the parameters of a MIME header and
2353 ** possibly truncate and rebalance the parameter according
2354 ** to MaxMimeFieldLength.
2357 ** h -- the header to truncate/rebalance
2358 ** e -- the current envelope
2361 ** length of last offending field, 0 if all ok.
2364 ** string modified in place
2368 fix_mime_header(h, e)
2372 char *begin = h->h_value;
2377 if (SM_IS_EMPTY(begin))
2380 /* Split on each ';' */
2381 /* find_character() never returns NULL */
2382 while ((end = find_character(begin, ';')) != NULL)
2389 len = strlen(begin);
2391 /* Shorten individual parameter */
2392 if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2394 if (len < MaxMimeFieldLength)
2396 /* we only rebalanced a bogus field */
2397 sm_syslog(LOG_ALERT, e->e_id,
2398 "Fixed MIME %s header field (possible attack)",
2401 sm_dprintf(" fixed MIME %s header field (possible attack)\n",
2406 /* we actually shortened the header */
2411 /* Collapse the possibly shortened string with rest */
2412 bp = begin + strlen(begin);
2420 /* copy character by character due to overlap */