2 * Copyright (c) 1998-2004, 2006, 2007 Sendmail, 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>
17 SM_RCSID("@(#)$Id: headers.c,v 8.312 2007/06/19 18:52:11 ca Exp $")
19 static HDR
*allocheader
__P((char *, char *, int, SM_RPOOL_T
*, bool));
20 static size_t fix_mime_header
__P((HDR
*, ENVELOPE
*));
21 static int priencode
__P((char *));
22 static bool put_vanilla_header
__P((HDR
*, char *, MCI
*));
25 ** SETUPHEADERS -- initialize headers in symbol table
40 for (hi
= HdrInfo
; hi
->hi_field
!= NULL
; hi
++)
42 s
= stab(hi
->hi_field
, ST_HEADER
, ST_ENTER
);
43 s
->s_header
.hi_flags
= hi
->hi_flags
;
44 s
->s_header
.hi_ruleset
= NULL
;
49 ** DOCHOMPHEADER -- process and save a header line.
51 ** Called by chompheader.
54 ** line -- header as a text line.
55 ** pflag -- flags for chompheader() (from sendmail.h)
56 ** hdrp -- a pointer to the place to save the header.
57 ** e -- the envelope including this header.
60 ** flags for this header.
63 ** The header is saved on the header list.
64 ** Contents of 'line' are destroyed.
67 static struct hdrinfo NormalHeader
= { NULL
, 0, NULL
};
68 static unsigned long dochompheader
__P((char *, int, HDR
**, ENVELOPE
*));
71 dochompheader(line
, pflag
, hdrp
, e
)
77 unsigned char mid
= '\0';
88 bool nullheader
= false;
91 headeronly
= hdrp
!= NULL
;
95 /* strip off options */
98 if (!bitset(pflag
, CHHDR_USER
) && *p
== '?')
103 q
= strchr(++p
, '?');
110 /* possibly macro conditional */
111 if (c
== MACROEXPAND
)
120 mid
= (unsigned char) *p
++;
138 mid
= (unsigned char) macid(p
);
139 if (bitset(0200, mid
))
141 p
+= strlen(macname(mid
)) + 2;
164 setbitn(bitidx(*p
), mopts
);
172 /* find canonical name */
174 while (isascii(*p
) && isgraph(*p
) && *p
!= ':')
177 while (isascii(*p
) && isspace(*p
))
179 if (*p
++ != ':' || fname
== fvalue
)
182 syserr("553 5.3.0 header syntax error, line \"%s\"", line
);
188 /* if the field is null, go ahead and use the default */
189 while (isascii(*p
) && isspace(*p
))
194 /* security scan: long field names are end-of-header */
195 if (strlen(fname
) > 100)
198 /* check to see if it represents a ruleset call */
199 if (bitset(pflag
, CHHDR_DEF
))
203 (void) expand(fvalue
, hbuf
, sizeof(hbuf
), e
);
204 for (p
= hbuf
; isascii(*p
) && isspace(*p
); )
206 if ((*p
++ & 0377) == CALLSUBR
)
211 strc
= *p
== '+'; /* strip comments? */
214 if (strtorwset(p
, &endp
, ST_ENTER
) > 0)
217 s
= stab(fname
, ST_HEADER
, ST_ENTER
);
219 s
->s_header
.hi_ruleset
!= NULL
)
220 sm_syslog(LOG_WARNING
, NOQID
,
221 "Warning: redefined ruleset for header=%s, old=%s, new=%s",
223 s
->s_header
.hi_ruleset
, p
);
224 s
->s_header
.hi_ruleset
= newstr(p
);
226 s
->s_header
.hi_flags
|= H_STRIPCOMM
;
232 /* see if it is a known type */
233 s
= stab(fname
, ST_HEADER
, ST_FIND
);
242 sm_dprintf("no header flags match\n");
244 sm_dprintf("header match, flags=%lx, ruleset=%s\n",
246 hi
->hi_ruleset
== NULL
? "<NULL>"
250 /* see if this is a resent message */
251 if (!bitset(pflag
, CHHDR_DEF
) && !headeronly
&&
252 bitset(H_RESENT
, hi
->hi_flags
))
253 e
->e_flags
|= EF_RESENT
;
255 /* if this is an Errors-To: header keep track of it now */
256 if (UseErrorsTo
&& !bitset(pflag
, CHHDR_DEF
) && !headeronly
&&
257 bitset(H_ERRORSTO
, hi
->hi_flags
))
258 (void) sendtolist(fvalue
, NULLADDR
, &e
->e_errorqueue
, 0, e
);
260 /* if this means "end of header" quit now */
261 if (!headeronly
&& bitset(H_EOH
, hi
->hi_flags
))
265 ** Horrible hack to work around problem with Lotus Notes SMTP
266 ** mail gateway, which generates From: headers with newlines in
267 ** them and the <address> on the second line. Although this is
268 ** legal RFC 822, many MUAs don't handle this properly and thus
269 ** never find the actual address.
272 if (bitset(H_FROM
, hi
->hi_flags
) && SingleLineFromHeader
)
274 while ((p
= strchr(fvalue
, '\n')) != NULL
)
279 ** If there is a check ruleset, verify it against the header.
282 if (bitset(pflag
, CHHDR_CHECK
))
287 rscheckflags
= RSF_COUNT
;
288 if (!bitset(hi
->hi_flags
, H_FROM
|H_RCPT
))
289 rscheckflags
|= RSF_UNSTRUCTURED
;
291 /* no ruleset? look for default */
295 s
= stab("*", ST_HEADER
, ST_FIND
);
298 rs
= (&s
->s_header
)->hi_ruleset
;
299 if (bitset((&s
->s_header
)->hi_flags
,
301 rscheckflags
|= RSF_RMCOMM
;
304 else if (bitset(hi
->hi_flags
, H_STRIPCOMM
))
305 rscheckflags
|= RSF_RMCOMM
;
314 /* - 3 to avoid problems with " at the end */
315 /* should be sizeof(qval), not MAXNAME */
316 for (k
= 0; fvalue
[k
] != '\0' && l
< MAXNAME
- 3; k
++)
320 /* XXX other control chars? */
321 case '\011': /* ht */
322 case '\012': /* nl */
323 case '\013': /* vt */
324 case '\014': /* np */
325 case '\015': /* cr */
332 qval
[l
++] = fvalue
[k
];
338 k
+= strlen(fvalue
+ k
);
342 sm_syslog(LOG_WARNING
, e
->e_id
,
343 "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
344 fname
, rs
, k
, MAXNAME
- 1);
346 macdefine(&e
->e_macro
, A_TEMP
,
347 macid("{currHeader}"), qval
);
348 macdefine(&e
->e_macro
, A_TEMP
,
349 macid("{hdr_name}"), fname
);
351 (void) sm_snprintf(qval
, sizeof(qval
), "%d", k
);
352 macdefine(&e
->e_macro
, A_TEMP
, macid("{hdrlen}"), qval
);
353 if (bitset(H_FROM
, hi
->hi_flags
))
354 macdefine(&e
->e_macro
, A_PERM
,
355 macid("{addr_type}"), "h s");
356 else if (bitset(H_RCPT
, hi
->hi_flags
))
357 macdefine(&e
->e_macro
, A_PERM
,
358 macid("{addr_type}"), "h r");
360 macdefine(&e
->e_macro
, A_PERM
,
361 macid("{addr_type}"), "h");
362 (void) rscheck(rs
, fvalue
, NULL
, e
, rscheckflags
, 3,
363 NULL
, e
->e_id
, NULL
);
368 ** Drop explicit From: if same as what we would generate.
369 ** This is to make MH (which doesn't always give a full name)
370 ** insert the full name information in all circumstances.
375 if (!bitset(EF_RESENT
, e
->e_flags
))
377 if (!bitset(pflag
, CHHDR_DEF
) && !headeronly
&&
378 !bitset(EF_QUEUERUN
, e
->e_flags
) && sm_strcasecmp(fname
, p
) == 0)
382 sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
383 fvalue
, e
->e_from
.q_paddr
, e
->e_from
.q_user
);
385 if (e
->e_from
.q_paddr
!= NULL
&&
386 e
->e_from
.q_mailer
!= NULL
&&
387 bitnset(M_LOCALMAILER
, e
->e_from
.q_mailer
->m_flags
) &&
388 (strcmp(fvalue
, e
->e_from
.q_paddr
) == 0 ||
389 strcmp(fvalue
, e
->e_from
.q_user
) == 0))
393 /* delete default value for this header */
394 for (hp
= hdrp
; (h
= *hp
) != NULL
; hp
= &h
->h_link
)
396 if (sm_strcasecmp(fname
, h
->h_field
) == 0 &&
397 !bitset(H_USER
, h
->h_flags
) &&
398 !bitset(H_FORCE
, h
->h_flags
))
402 /* user-supplied value was null */
407 /* make this look like the user entered it */
408 h
->h_flags
|= H_USER
;
414 /* copy conditions from default case */
415 memmove((char *) mopts
, (char *) h
->h_mflags
,
422 /* create a new node */
423 h
= (HDR
*) sm_rpool_malloc_x(e
->e_rpool
, sizeof(*h
));
424 h
->h_field
= sm_rpool_strdup_x(e
->e_rpool
, fname
);
425 h
->h_value
= sm_rpool_strdup_x(e
->e_rpool
, fvalue
);
427 memmove((char *) h
->h_mflags
, (char *) mopts
, sizeof(mopts
));
430 h
->h_flags
= hi
->hi_flags
;
431 if (bitset(pflag
, CHHDR_USER
) || bitset(pflag
, CHHDR_QUEUE
))
432 h
->h_flags
|= H_USER
;
434 /* strip EOH flag if parsing MIME headers */
436 h
->h_flags
&= ~H_EOH
;
437 if (bitset(pflag
, CHHDR_DEF
))
438 h
->h_flags
|= H_DEFAULT
;
439 if (cond
|| mid
!= '\0')
440 h
->h_flags
|= H_CHECK
;
442 /* hack to see if this is a new format message */
443 if (!bitset(pflag
, CHHDR_DEF
) && !headeronly
&&
444 bitset(H_RCPT
|H_FROM
, h
->h_flags
) &&
445 (strchr(fvalue
, ',') != NULL
|| strchr(fvalue
, '(') != NULL
||
446 strchr(fvalue
, '<') != NULL
|| strchr(fvalue
, ';') != NULL
))
448 e
->e_flags
&= ~EF_OLDSTYLE
;
455 ** CHOMPHEADER -- process and save a header line.
457 ** Called by collect, readcf, and readqf to deal with header lines.
458 ** This is just a wrapper for dochompheader().
461 ** line -- header as a text line.
462 ** pflag -- flags for chompheader() (from sendmail.h)
463 ** hdrp -- a pointer to the place to save the header.
464 ** e -- the envelope including this header.
467 ** flags for this header.
470 ** The header is saved on the header list.
471 ** Contents of 'line' are destroyed.
476 chompheader(line
, pflag
, hdrp
, e
)
480 register ENVELOPE
*e
;
486 sm_dprintf("chompheader: ");
487 xputs(sm_debug_file(), line
);
491 /* quote this if user (not config file) input */
492 if (bitset(pflag
, CHHDR_USER
))
498 xbufs
= sizeof(xbuf
);
499 xbp
= quote_internal_chars(line
, xbuf
, &xbufs
);
502 sm_dprintf("chompheader: quoted: ");
503 xputs(sm_debug_file(), xbp
);
506 rval
= dochompheader(xbp
, pflag
, hdrp
, e
);
511 rval
= dochompheader(line
, pflag
, hdrp
, e
);
517 ** ALLOCHEADER -- allocate a header entry
520 ** field -- the name of the header field (will not be copied).
521 ** value -- the value of the field (will be copied).
522 ** flags -- flags to add to h_flags.
523 ** rp -- resource pool for allocations
524 ** space -- add leading space?
527 ** Pointer to a newly allocated and populated HDR.
530 ** o field and value must be in internal format, i.e.,
531 ** metacharacters must be "quoted", see quote_internal_chars().
532 ** o maybe add more flags to decide:
533 ** - what to copy (field/value)
534 ** - whether to convert value to an internal format
538 allocheader(field
, value
, flags
, rp
, space
)
548 /* find info struct */
549 s
= stab(field
, ST_HEADER
, ST_FIND
);
551 /* allocate space for new header */
552 h
= (HDR
*) sm_rpool_malloc_x(rp
, sizeof(*h
));
560 SM_ASSERT(l
+ 2 > l
);
561 n
= sm_rpool_malloc_x(rp
, l
+ 2);
564 sm_strlcpy(n
+ 1, value
, l
+ 1);
568 h
->h_value
= sm_rpool_strdup_x(rp
, value
);
571 h
->h_flags
|= s
->s_header
.hi_flags
;
572 clrbitmap(h
->h_mflags
);
579 ** ADDHEADER -- add a header entry to the end of the queue.
581 ** This bypasses the special checking of chompheader.
584 ** field -- the name of the header field (will not be copied).
585 ** value -- the value of the field (will be copied).
586 ** flags -- flags to add to h_flags.
588 ** space -- add leading space?
594 ** adds the field on the list of headers for this envelope.
596 ** Notes: field and value must be in internal format, i.e.,
597 ** metacharacters must be "quoted", see quote_internal_chars().
601 addheader(field
, value
, flags
, e
, space
)
610 HDR
**hdrlist
= &e
->e_header
;
612 /* find current place in list -- keep back pointer? */
613 for (hp
= hdrlist
; (h
= *hp
) != NULL
; hp
= &h
->h_link
)
615 if (sm_strcasecmp(field
, h
->h_field
) == 0)
619 /* allocate space for new header */
620 h
= allocheader(field
, value
, flags
, e
->e_rpool
, space
);
626 ** INSHEADER -- insert a header entry at the specified index
627 ** This bypasses the special checking of chompheader.
630 ** idx -- index into the header list at which to insert
631 ** field -- the name of the header field (will be copied).
632 ** value -- the value of the field (will be copied).
633 ** flags -- flags to add to h_flags.
635 ** space -- add leading space?
641 ** inserts the field on the list of headers for this envelope.
644 ** - field and value must be in internal format, i.e.,
645 ** metacharacters must be "quoted", see quote_internal_chars().
646 ** - the header list contains headers that might not be
647 ** sent "out" (see putheader(): "skip"), hence there is no
648 ** reliable way to insert a header at an exact position
649 ** (except at the front or end).
653 insheader(idx
, field
, value
, flags
, e
, space
)
661 HDR
*h
, *srch
, *last
= NULL
;
663 /* allocate space for new header */
664 h
= allocheader(field
, value
, flags
, e
->e_rpool
, space
);
666 /* find insertion position */
667 for (srch
= e
->e_header
; srch
!= NULL
&& idx
> 0;
668 srch
= srch
->h_link
, idx
--)
671 if (e
->e_header
== NULL
)
676 else if (srch
== NULL
)
678 SM_ASSERT(last
!= NULL
);
684 h
->h_link
= srch
->h_link
;
690 ** HVALUE -- return value of a header.
692 ** Only "real" fields (i.e., ones that have not been supplied
693 ** as a default) are used.
696 ** field -- the field name.
697 ** header -- the header list.
700 ** pointer to the value part (internal format).
701 ** NULL if not found.
708 hvalue(field
, header
)
714 for (h
= header
; h
!= NULL
; h
= h
->h_link
)
716 if (!bitset(H_DEFAULT
, h
->h_flags
) &&
717 sm_strcasecmp(h
->h_field
, field
) == 0)
724 ** ISHEADER -- predicate telling if argument is a header.
726 ** A line is a header if it has a single word followed by
727 ** optional white space followed by a colon.
729 ** Header fields beginning with two dashes, although technically
730 ** permitted by RFC822, are automatically rejected in order
731 ** to make MIME work out. Without this we could have a technically
732 ** legal header such as ``--"foo:bar"'' that would also be a legal
736 ** h -- string to check for possible headerness.
739 ** true if h is a header.
753 if (s
[0] == '-' && s
[1] == '-')
756 while (*s
> ' ' && *s
!= ':' && *s
!= '\0')
762 /* following technically violates RFC822 */
763 while (isascii(*s
) && isspace(*s
))
770 ** EATHEADER -- run through the stored header and extract info.
773 ** e -- the envelope to process.
774 ** full -- if set, do full processing (e.g., compute
775 ** message priority). This should not be set
776 ** when reading a queue file because some info
777 ** needed to compute the priority is wrong.
778 ** log -- call logsender()?
784 ** Sets a bunch of global variables from information
785 ** in the collected header.
789 eatheader(e
, full
, log
)
790 register ENVELOPE
*e
;
800 ** Set up macros for possible expansion in headers.
803 macdefine(&e
->e_macro
, A_PERM
, 'f', e
->e_sender
);
804 macdefine(&e
->e_macro
, A_PERM
, 'g', e
->e_sender
);
805 if (e
->e_origrcpt
!= NULL
&& *e
->e_origrcpt
!= '\0')
806 macdefine(&e
->e_macro
, A_PERM
, 'u', e
->e_origrcpt
);
808 macdefine(&e
->e_macro
, A_PERM
, 'u', NULL
);
810 /* full name of from person */
811 p
= hvalue("full-name", e
->e_header
);
814 if (!rfc822_string(p
))
817 ** Quote a full name with special characters
818 ** as a comment so crackaddr() doesn't destroy
819 ** the name portion of the address.
822 p
= addquotes(p
, e
->e_rpool
);
824 macdefine(&e
->e_macro
, A_PERM
, 'x', p
);
828 sm_dprintf("----- collected header -----\n");
830 for (h
= e
->e_header
; h
!= NULL
; h
= h
->h_link
)
833 sm_dprintf("%s:", h
->h_field
);
834 if (h
->h_value
== NULL
)
837 sm_dprintf("<NULL>\n");
841 /* do early binding */
842 if (bitset(H_DEFAULT
, h
->h_flags
) &&
843 !bitset(H_BINDLATE
, h
->h_flags
))
848 xputs(sm_debug_file(), h
->h_value
);
851 expand(h
->h_value
, buf
, sizeof(buf
), e
);
852 if (buf
[0] != '\0' &&
853 (buf
[0] != ' ' || buf
[1] != '\0'))
855 if (bitset(H_FROM
, h
->h_flags
))
856 expand(crackaddr(buf
, e
),
857 buf
, sizeof(buf
), e
);
858 h
->h_value
= sm_rpool_strdup_x(e
->e_rpool
, buf
);
859 h
->h_flags
&= ~H_DEFAULT
;
864 xputs(sm_debug_file(), h
->h_value
);
868 /* count the number of times it has been processed */
869 if (bitset(H_TRACE
, h
->h_flags
))
872 /* send to this person if we so desire */
873 if (GrabTo
&& bitset(H_RCPT
, h
->h_flags
) &&
874 !bitset(H_DEFAULT
, h
->h_flags
) &&
875 (!bitset(EF_RESENT
, e
->e_flags
) ||
876 bitset(H_RESENT
, h
->h_flags
)))
879 int saveflags
= e
->e_flags
;
882 (void) sendtolist(denlstring(h
->h_value
, true, false),
883 NULLADDR
, &e
->e_sendqueue
, 0, e
);
887 ** Change functionality so a fatal error on an
888 ** address doesn't affect the entire envelope.
891 /* delete fatal errors generated by this address */
892 if (!bitset(EF_FATALERRS
, saveflags
))
893 e
->e_flags
&= ~EF_FATALERRS
;
897 /* save the message-id for logging */
898 p
= "resent-message-id";
899 if (!bitset(EF_RESENT
, e
->e_flags
))
901 if (sm_strcasecmp(h
->h_field
, p
) == 0)
903 e
->e_msgid
= h
->h_value
;
904 while (isascii(*e
->e_msgid
) && isspace(*e
->e_msgid
))
906 macdefine(&e
->e_macro
, A_PERM
, macid("{msg_id}"),
911 sm_dprintf("----------------------------\n");
913 /* if we are just verifying (that is, sendmail -t -bv), drop out now */
914 if (OpMode
== MD_VERIFY
)
917 /* store hop count */
918 if (hopcnt
> e
->e_hopcount
)
920 e
->e_hopcount
= hopcnt
;
921 (void) sm_snprintf(buf
, sizeof(buf
), "%d", e
->e_hopcount
);
922 macdefine(&e
->e_macro
, A_TEMP
, 'c', buf
);
925 /* message priority */
926 p
= hvalue("precedence", e
->e_header
);
928 e
->e_class
= priencode(p
);
930 e
->e_timeoutclass
= TOC_NONURGENT
;
931 else if (e
->e_class
> 0)
932 e
->e_timeoutclass
= TOC_URGENT
;
935 e
->e_msgpriority
= e
->e_msgsize
936 - e
->e_class
* WkClassFact
937 + e
->e_nrcpts
* WkRecipFact
;
940 /* check for DSN to properly set e_timeoutclass */
941 p
= hvalue("content-type", e
->e_header
);
946 char pvpbuf
[MAXLINE
];
947 extern unsigned char MimeTokenTab
[256];
949 /* tokenize header */
952 pvp
= prescan(p
, '\0', pvpbuf
, sizeof(pvpbuf
), NULL
,
953 MimeTokenTab
, false);
956 /* Check if multipart/report */
957 if (pvp
!= NULL
&& pvp
[0] != NULL
&&
958 pvp
[1] != NULL
&& pvp
[2] != NULL
&&
959 sm_strcasecmp(*pvp
++, "multipart") == 0 &&
960 strcmp(*pvp
++, "/") == 0 &&
961 sm_strcasecmp(*pvp
++, "report") == 0)
963 /* Look for report-type=delivery-status */
966 /* skip to semicolon separator */
967 while (*pvp
!= NULL
&& strcmp(*pvp
, ";") != 0)
971 if (*pvp
++ == NULL
|| *pvp
== NULL
)
974 /* look for report-type */
975 if (sm_strcasecmp(*pvp
++, "report-type") != 0)
979 if (*pvp
== NULL
|| strcmp(*pvp
, "=") != 0)
983 if (*++pvp
!= NULL
&&
985 "delivery-status") == 0)
986 e
->e_timeoutclass
= TOC_DSN
;
988 /* found report-type, no need to continue */
994 /* message timeout priority */
995 p
= hvalue("priority", e
->e_header
);
998 /* (this should be in the configuration file) */
999 if (sm_strcasecmp(p
, "urgent") == 0)
1000 e
->e_timeoutclass
= TOC_URGENT
;
1001 else if (sm_strcasecmp(p
, "normal") == 0)
1002 e
->e_timeoutclass
= TOC_NORMAL
;
1003 else if (sm_strcasecmp(p
, "non-urgent") == 0)
1004 e
->e_timeoutclass
= TOC_NONURGENT
;
1005 else if (bitset(EF_RESPONSE
, e
->e_flags
))
1006 e
->e_timeoutclass
= TOC_DSN
;
1008 else if (bitset(EF_RESPONSE
, e
->e_flags
))
1009 e
->e_timeoutclass
= TOC_DSN
;
1011 /* date message originated */
1012 p
= hvalue("posted-date", e
->e_header
);
1014 p
= hvalue("date", e
->e_header
);
1016 macdefine(&e
->e_macro
, A_PERM
, 'a', p
);
1018 /* check to see if this is a MIME message */
1019 if ((e
->e_bodytype
!= NULL
&&
1020 sm_strcasecmp(e
->e_bodytype
, "8BITMIME") == 0) ||
1021 hvalue("MIME-Version", e
->e_header
) != NULL
)
1023 e
->e_flags
|= EF_IS_MIME
;
1025 e
->e_bodytype
= "8BITMIME";
1027 else if ((p
= hvalue("Content-Type", e
->e_header
)) != NULL
)
1029 /* this may be an RFC 1049 message */
1030 p
= strpbrk(p
, ";/");
1031 if (p
== NULL
|| *p
== ';')
1034 e
->e_flags
|= EF_DONT_MIME
;
1039 ** From person in antiquated ARPANET mode
1040 ** required by UK Grey Book e-mail gateways (sigh)
1043 if (OpMode
== MD_ARPAFTP
)
1045 register struct hdrinfo
*hi
;
1047 for (hi
= HdrInfo
; hi
->hi_field
!= NULL
; hi
++)
1049 if (bitset(H_FROM
, hi
->hi_flags
) &&
1050 (!bitset(H_RESENT
, hi
->hi_flags
) ||
1051 bitset(EF_RESENT
, e
->e_flags
)) &&
1052 (p
= hvalue(hi
->hi_field
, e
->e_header
)) != NULL
)
1055 if (hi
->hi_field
!= NULL
)
1058 sm_dprintf("eatheader: setsender(*%s == %s)\n",
1060 setsender(p
, e
, NULL
, '\0', true);
1065 ** Log collection information.
1068 if (log
&& bitset(EF_LOGSENDER
, e
->e_flags
) && LogLevel
> 4)
1070 logsender(e
, e
->e_msgid
);
1071 e
->e_flags
&= ~EF_LOGSENDER
;
1076 ** LOGSENDER -- log sender information
1079 ** e -- the envelope to log
1080 ** msgid -- the message id
1088 register ENVELOPE
*e
;
1094 char hbuf
[MAXNAME
+ 1];
1095 char sbuf
[MAXLINE
+ 1];
1096 char mbuf
[MAXNAME
+ 1];
1098 /* don't allow newlines in the message-id */
1099 /* XXX do we still need this? sm_syslog() replaces control chars */
1105 if (l
> sizeof(mbuf
) - 1)
1106 l
= sizeof(mbuf
) - 1;
1107 memmove(mbuf
, msgid
, l
);
1110 while ((p
= strchr(p
, '\n')) != NULL
)
1114 if (bitset(EF_RESPONSE
, e
->e_flags
))
1115 name
= "[RESPONSE]";
1116 else if ((name
= macvalue('_', e
)) != NULL
)
1119 else if (RealHostName
== NULL
)
1121 else if (RealHostName
[0] == '[')
1122 name
= RealHostName
;
1126 (void) sm_snprintf(hbuf
, sizeof(hbuf
), "%.80s", RealHostName
);
1127 if (RealHostAddr
.sa
.sa_family
!= 0)
1129 p
= &hbuf
[strlen(hbuf
)];
1130 (void) sm_snprintf(p
, SPACELEFT(hbuf
, p
),
1132 anynet_ntoa(&RealHostAddr
));
1136 /* some versions of syslog only take 5 printf args */
1137 #if (SYSLOG_BUFSIZE) >= 256
1139 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1140 "from=%.200s, size=%ld, class=%d, nrcpts=%d",
1141 e
->e_from
.q_paddr
== NULL
? "<NONE>" : e
->e_from
.q_paddr
,
1142 e
->e_msgsize
, e
->e_class
, e
->e_nrcpts
);
1146 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1147 ", msgid=%.100s", mbuf
);
1150 if (e
->e_bodytype
!= NULL
)
1152 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1153 ", bodytype=%.20s", e
->e_bodytype
);
1156 p
= macvalue('r', e
);
1159 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1160 ", proto=%.20s", p
);
1163 p
= macvalue(macid("{daemon_name}"), e
);
1166 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1167 ", daemon=%.20s", p
);
1170 sm_syslog(LOG_INFO
, e
->e_id
, "%.850s, relay=%s", sbuf
, name
);
1172 #else /* (SYSLOG_BUFSIZE) >= 256 */
1174 sm_syslog(LOG_INFO
, e
->e_id
,
1176 e
->e_from
.q_paddr
== NULL
? "<NONE>"
1177 : shortenstring(e
->e_from
.q_paddr
,
1179 sm_syslog(LOG_INFO
, e
->e_id
,
1180 "size=%ld, class=%ld, nrcpts=%d",
1181 e
->e_msgsize
, e
->e_class
, e
->e_nrcpts
);
1183 sm_syslog(LOG_INFO
, e
->e_id
,
1185 shortenstring(mbuf
, 83));
1188 if (e
->e_bodytype
!= NULL
)
1190 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1191 "bodytype=%.20s, ", e
->e_bodytype
);
1194 p
= macvalue('r', e
);
1197 (void) sm_snprintf(sbp
, SPACELEFT(sbuf
, sbp
),
1198 "proto=%.20s, ", p
);
1201 sm_syslog(LOG_INFO
, e
->e_id
,
1202 "%.400srelay=%s", sbuf
, name
);
1203 #endif /* (SYSLOG_BUFSIZE) >= 256 */
1207 ** PRIENCODE -- encode external priority names into internal values.
1210 ** p -- priority in ascii.
1213 ** priority as a numeric level.
1225 for (i
= 0; i
< NumPriorities
; i
++)
1227 if (sm_strcasecmp(p
, Priorities
[i
].pri_name
) == 0)
1228 return Priorities
[i
].pri_val
;
1231 /* unknown priority */
1236 ** CRACKADDR -- parse an address and turn it into a macro
1238 ** This doesn't actually parse the address -- it just extracts
1239 ** it and replaces it with "$g". The parse is totally ad hoc
1240 ** and isn't even guaranteed to leave something syntactically
1241 ** identical to what it started with. However, it does leave
1242 ** something semantically identical if possible, else at least
1243 ** syntactically correct.
1245 ** For example, it changes "Real Name <real@example.com> (Comment)"
1246 ** to "Real Name <$g> (Comment)".
1248 ** This algorithm has been cleaned up to handle a wider range
1249 ** of cases -- notably quoted and backslash escaped strings.
1250 ** This modification makes it substantially better at preserving
1251 ** the original syntax.
1254 ** addr -- the address to be cracked.
1255 ** e -- the current envelope.
1258 ** a pointer to the new version.
1264 ** The return value is saved in local storage and should
1265 ** be copied if it is to be reused.
1268 #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend))
1271 ** Append a character to bp if we have room.
1272 ** If not, punt and return $g.
1275 #define SM_APPEND_CHAR(c) \
1285 ERROR MAXNAME must be at least
10
1286 #endif /* MAXNAME < 10 */
1290 register char *addr
;
1295 int cmtlev
; /* comment level in input string */
1296 int realcmtlev
; /* comment level in output string */
1297 int anglelev
; /* angle level in input string */
1298 int copylev
; /* 0 == in address, >0 copying */
1299 int bracklev
; /* bracket level for IPv6 addr check */
1300 bool addangle
; /* put closing angle in output */
1301 bool qmode
; /* quoting in original string? */
1302 bool realqmode
; /* quoting in output string? */
1303 bool putgmac
= false; /* already wrote $g */
1304 bool quoteit
= false; /* need to quote next character */
1305 bool gotangle
= false; /* found first '<' */
1306 bool gotcolon
= false; /* found a ':' */
1312 static char buf
[MAXNAME
+ 1];
1315 sm_dprintf("crackaddr(%s)\n", addr
);
1317 buflim
= bufend
= &buf
[sizeof(buf
) - 1];
1320 /* skip over leading spaces but preserve them */
1321 while (*addr
!= '\0' && isascii(*addr
) && isspace(*addr
))
1323 SM_APPEND_CHAR(*addr
);
1329 ** Start by assuming we have no angle brackets. This will be
1330 ** adjusted later if we find them.
1333 p
= addrhead
= addr
;
1334 copylev
= anglelev
= cmtlev
= realcmtlev
= 0;
1336 qmode
= realqmode
= addangle
= false;
1338 while ((c
= *p
++) != '\0')
1341 ** Try to keep legal syntax using spare buffer space
1342 ** (maintained by buflim).
1348 /* check for backslash escapes */
1351 /* arrange to quote the address */
1352 if (cmtlev
<= 0 && !qmode
)
1355 if ((c
= *p
++) == '\0')
1366 /* check for quoted strings */
1367 if (c
== '"' && cmtlev
<= 0)
1370 if (copylev
> 0 && SM_HAVE_ROOM
)
1376 realqmode
= !realqmode
;
1383 /* check for comments */
1388 /* allow space for closing paren */
1396 SM_APPEND_CHAR(' ');
1417 /* syntax error: unmatched ) */
1418 if (copylev
> 0 && SM_HAVE_ROOM
&& bp
> bufhead
)
1422 /* count nesting on [ ... ] (for IPv6 domain literals) */
1428 /* check for group: list; syntax */
1429 if (c
== ':' && anglelev
<= 0 && bracklev
<= 0 &&
1430 !gotcolon
&& !ColonOkInAddr
)
1435 ** Check for DECnet phase IV ``::'' (host::user)
1436 ** or DECnet phase V ``:.'' syntaxes. The latter
1437 ** covers ``user@DEC:.tay.myhost'' and
1438 ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
1441 if (*p
== ':' || *p
== '.')
1443 if (cmtlev
<= 0 && !qmode
)
1459 SM_APPEND_CHAR('"');
1461 /* back up over the ':' and any spaces */
1464 isascii(*--p
) && isspace(*p
))
1468 for (q
= addrhead
; q
< p
; )
1471 if (quoteit
&& c
== '"')
1472 SM_APPEND_CHAR('\\');
1477 if (bp
== &bufhead
[1])
1480 SM_APPEND_CHAR('"');
1481 while ((c
= *p
++) != ':')
1486 /* any trailing white space is part of group: */
1487 while (isascii(*p
) && isspace(*p
))
1493 putgmac
= quoteit
= false;
1499 if (c
== ';' && copylev
<= 0 && !ColonOkInAddr
)
1502 /* check for characters that may have to be quoted */
1503 if (strchr(MustQuoteChars
, c
) != NULL
)
1506 ** If these occur as the phrase part of a <>
1507 ** construct, but are not inside of () or already
1508 ** quoted, they will have to be quoted. Note that
1509 ** now (but don't actually do the quoting).
1512 if (cmtlev
<= 0 && !qmode
)
1516 /* check for angle brackets */
1521 /* assume first of two angles is bogus */
1526 /* oops -- have to change our mind */
1538 SM_APPEND_CHAR('"');
1540 /* back up over the '<' and any spaces */
1543 isascii(*--p
) && isspace(*p
))
1547 for (q
= addrhead
; q
< p
; )
1550 if (quoteit
&& c
== '"')
1552 SM_APPEND_CHAR('\\');
1563 SM_APPEND_CHAR('"');
1564 while ((c
= *p
++) != '<')
1569 putgmac
= quoteit
= false;
1585 else if (SM_HAVE_ROOM
)
1587 /* syntax error: unmatched > */
1588 if (copylev
> 0 && bp
> bufhead
)
1598 /* must be a real address character */
1600 if (copylev
<= 0 && !putgmac
)
1602 if (bp
> buf
&& bp
[-1] == ')')
1603 SM_APPEND_CHAR(' ');
1604 SM_APPEND_CHAR(MACROEXPAND
);
1605 SM_APPEND_CHAR('g');
1610 /* repair any syntactic damage */
1611 if (realqmode
&& bp
< bufend
)
1613 while (realcmtlev
-- > 0 && bp
< bufend
)
1615 if (addangle
&& bp
< bufend
)
1622 /* String too long, punt */
1624 buf
[1] = MACROEXPAND
;
1628 sm_syslog(LOG_ALERT
, e
->e_id
,
1629 "Dropped invalid comments from header address");
1634 sm_dprintf("crackaddr=>`");
1635 xputs(sm_debug_file(), buf
);
1642 ** PUTHEADER -- put the header part of a message from the in-core copy
1645 ** mci -- the connection information.
1646 ** hdr -- the header to put.
1647 ** e -- envelope to use.
1648 ** flags -- MIME conversion flags.
1651 ** true iff header part was written successfully
1658 putheader(mci
, hdr
, e
, flags
)
1661 register ENVELOPE
*e
;
1665 char buf
[SM_MAX(MAXLINE
,BUFSIZ
)];
1669 sm_dprintf("--- putheader, mailer = %s ---\n",
1670 mci
->mci_mailer
->m_name
);
1673 ** If we're in MIME mode, we're not really in the header of the
1674 ** message, just the header of one of the parts of the body of
1675 ** the message. Therefore MCIF_INHEADER should not be turned on.
1678 if (!bitset(MCIF_INMIME
, mci
->mci_flags
))
1679 mci
->mci_flags
|= MCIF_INHEADER
;
1681 for (h
= hdr
; h
!= NULL
; h
= h
->h_link
)
1683 register char *p
= h
->h_value
;
1688 sm_dprintf(" %s:", h
->h_field
);
1689 xputs(sm_debug_file(), p
);
1692 /* Skip empty headers */
1693 if (h
->h_value
== NULL
)
1696 /* heuristic shortening of MIME fields to avoid MUA overflows */
1697 if (MaxMimeFieldLength
> 0 &&
1698 wordinclass(h
->h_field
,
1699 macid("{checkMIMEFieldHeaders}")))
1703 len
= fix_mime_header(h
, e
);
1706 sm_syslog(LOG_ALERT
, e
->e_id
,
1707 "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1708 h
->h_field
, (unsigned long) len
);
1710 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
1712 (unsigned long) len
);
1716 if (MaxMimeHeaderLength
> 0 &&
1717 wordinclass(h
->h_field
,
1718 macid("{checkMIMETextHeaders}")))
1722 len
= strlen(h
->h_value
);
1723 if (len
> (size_t) MaxMimeHeaderLength
)
1725 h
->h_value
[MaxMimeHeaderLength
- 1] = '\0';
1726 sm_syslog(LOG_ALERT
, e
->e_id
,
1727 "Truncated long MIME %s header (length = %ld) (possible attack)",
1728 h
->h_field
, (unsigned long) len
);
1730 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1732 (unsigned long) len
);
1736 if (MaxMimeHeaderLength
> 0 &&
1737 wordinclass(h
->h_field
,
1738 macid("{checkMIMEHeaders}")))
1742 len
= strlen(h
->h_value
);
1743 if (shorten_rfc822_string(h
->h_value
,
1744 MaxMimeHeaderLength
))
1746 if (len
< MaxMimeHeaderLength
)
1748 /* we only rebalanced a bogus header */
1749 sm_syslog(LOG_ALERT
, e
->e_id
,
1750 "Fixed MIME %s header (possible attack)",
1753 sm_dprintf(" fixed MIME %s header (possible attack)\n",
1758 /* we actually shortened header */
1759 sm_syslog(LOG_ALERT
, e
->e_id
,
1760 "Truncated long MIME %s header (length = %ld) (possible attack)",
1762 (unsigned long) len
);
1764 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1766 (unsigned long) len
);
1772 ** Suppress Content-Transfer-Encoding: if we are MIMEing
1773 ** and we are potentially converting from 8 bit to 7 bit
1774 ** MIME. If converting, add a new CTE header in
1778 if (bitset(H_CTE
, h
->h_flags
) &&
1779 bitset(MCIF_CVT8TO7
|MCIF_CVT7TO8
|MCIF_INMIME
,
1781 !bitset(M87F_NO8TO7
, flags
))
1784 sm_dprintf(" (skipped (content-transfer-encoding))\n");
1788 if (bitset(MCIF_INMIME
, mci
->mci_flags
))
1792 if (!put_vanilla_header(h
, p
, mci
))
1797 if (bitset(H_CHECK
|H_ACHECK
, h
->h_flags
) &&
1798 !bitintersect(h
->h_mflags
, mci
->mci_mailer
->m_flags
) &&
1799 (h
->h_macro
== '\0' ||
1800 (q
= macvalue(bitidx(h
->h_macro
), e
)) == NULL
||
1804 sm_dprintf(" (skipped)\n");
1808 /* handle Resent-... headers specially */
1809 if (bitset(H_RESENT
, h
->h_flags
) && !bitset(EF_RESENT
, e
->e_flags
))
1812 sm_dprintf(" (skipped (resent))\n");
1816 /* suppress return receipts if requested */
1817 if (bitset(H_RECEIPTTO
, h
->h_flags
) &&
1818 (RrtImpliesDsn
|| bitset(EF_NORECEIPT
, e
->e_flags
)))
1821 sm_dprintf(" (skipped (receipt))\n");
1825 /* macro expand value if generated internally */
1826 if (bitset(H_DEFAULT
, h
->h_flags
) ||
1827 bitset(H_BINDLATE
, h
->h_flags
))
1829 expand(p
, buf
, sizeof(buf
), e
);
1834 sm_dprintf(" (skipped -- null value)\n");
1839 if (bitset(H_BCC
, h
->h_flags
))
1841 /* Bcc: field -- either truncate or delete */
1842 if (bitset(EF_DELETE_BCC
, e
->e_flags
))
1845 sm_dprintf(" (skipped -- bcc)\n");
1849 /* no other recipient headers: truncate value */
1850 (void) sm_strlcpyn(obuf
, sizeof(obuf
), 2,
1852 if (!putline(obuf
, mci
))
1861 if (bitset(H_FROM
|H_RCPT
, h
->h_flags
))
1864 bool oldstyle
= bitset(EF_OLDSTYLE
, e
->e_flags
);
1866 if (bitset(H_FROM
, h
->h_flags
))
1868 commaize(h
, p
, oldstyle
, mci
, e
,
1869 PXLF_HEADER
| PXLF_STRIPMQUOTE
);
1873 if (!put_vanilla_header(h
, p
, mci
))
1879 ** If we are converting this to a MIME message, add the
1880 ** MIME headers (but not in MIME mode!).
1884 if (bitset(MM_MIME8BIT
, MimeMode
) &&
1885 bitset(EF_HAS8BIT
, e
->e_flags
) &&
1886 !bitset(EF_DONT_MIME
, e
->e_flags
) &&
1887 !bitnset(M_8BITS
, mci
->mci_mailer
->m_flags
) &&
1888 !bitset(MCIF_CVT8TO7
|MCIF_CVT7TO8
|MCIF_INMIME
, mci
->mci_flags
) &&
1889 hvalue("MIME-Version", e
->e_header
) == NULL
)
1891 if (!putline("MIME-Version: 1.0", mci
))
1893 if (hvalue("Content-Type", e
->e_header
) == NULL
)
1895 (void) sm_snprintf(obuf
, sizeof(obuf
),
1896 "Content-Type: text/plain; charset=%s",
1898 if (!putline(obuf
, mci
))
1901 if (hvalue("Content-Transfer-Encoding", e
->e_header
) == NULL
1902 && !putline("Content-Transfer-Encoding: 8bit", mci
))
1905 #endif /* MIME8TO7 */
1913 ** PUT_VANILLA_HEADER -- output a fairly ordinary header
1916 ** h -- the structure describing this header
1917 ** v -- the value of this header
1918 ** mci -- the connection info for output
1921 ** true iff header was written successfully
1925 put_vanilla_header(h
, v
, mci
)
1933 char obuf
[MAXLINE
+ 256]; /* additional length for h_field */
1935 putflags
= PXLF_HEADER
| PXLF_STRIPMQUOTE
;
1936 if (bitnset(M_7BITHDRS
, mci
->mci_mailer
->m_flags
))
1937 putflags
|= PXLF_STRIP8BIT
;
1938 (void) sm_snprintf(obuf
, sizeof(obuf
), "%.200s:", h
->h_field
);
1939 obp
= obuf
+ strlen(obuf
);
1940 while ((nlp
= strchr(v
, '\n')) != NULL
)
1947 ** XXX This is broken for SPACELEFT()==0
1948 ** However, SPACELEFT() is always > 0 unless MAXLINE==1.
1951 if (SPACELEFT(obuf
, obp
) - 1 < (size_t) l
)
1952 l
= SPACELEFT(obuf
, obp
) - 1;
1954 (void) sm_snprintf(obp
, SPACELEFT(obuf
, obp
), "%.*s", l
, v
);
1955 if (!putxline(obuf
, strlen(obuf
), mci
, putflags
))
1959 if (*v
!= ' ' && *v
!= '\t')
1963 /* XXX This is broken for SPACELEFT()==0 */
1964 (void) sm_snprintf(obp
, SPACELEFT(obuf
, obp
), "%.*s",
1965 (int) (SPACELEFT(obuf
, obp
) - 1), v
);
1966 return putxline(obuf
, strlen(obuf
), mci
, putflags
);
1973 ** COMMAIZE -- output a header field, making a comma-translated list.
1976 ** h -- the header field to output.
1977 ** p -- the value to put in it.
1978 ** oldstyle -- true if this is an old style header.
1979 ** mci -- the connection information.
1980 ** e -- the envelope containing the message.
1981 ** putflags -- flags for putxline()
1984 ** true iff header field was written successfully
1987 ** outputs "p" to "mci".
1991 commaize(h
, p
, oldstyle
, mci
, e
, putflags
)
1996 register ENVELOPE
*e
;
2000 int opos
, omax
, spaces
;
2001 bool firstone
= true;
2003 char obuf
[MAXLINE
+ 3];
2006 ** Output the address list translated by the
2007 ** mailer and with commas.
2011 sm_dprintf("commaize(%s:%s)\n", h
->h_field
, p
);
2013 if (bitnset(M_7BITHDRS
, mci
->mci_mailer
->m_flags
))
2014 putflags
|= PXLF_STRIP8BIT
;
2017 (void) sm_snprintf(obp
, SPACELEFT(obuf
, obp
), "%.200s:", h
->h_field
);
2018 /* opos = strlen(obp); instead of the next 3 lines? */
2019 opos
= strlen(h
->h_field
) + 1;
2025 while (*p
!= '\0' && isascii(*p
) && isspace(*p
))
2032 SM_ASSERT(sizeof(obuf
) > opos
* 2);
2035 ** Restrict number of spaces to half the length of buffer
2036 ** so the header field body can be put in here too.
2037 ** Note: this is a hack...
2040 if (spaces
> sizeof(obuf
) / 2)
2041 spaces
= sizeof(obuf
) / 2;
2042 (void) sm_snprintf(obp
, SPACELEFT(obuf
, obp
), "%*s", spaces
,
2046 SM_ASSERT(obp
< &obuf
[MAXLINE
]);
2049 omax
= mci
->mci_mailer
->m_linelimit
- 2;
2050 if (omax
< 0 || omax
> 78)
2054 ** Run through the list of values.
2059 register char *name
;
2066 ** Find the end of the name. New style names
2067 ** end with a comma, old style names end with
2068 ** a space character. However, spaces do not
2069 ** necessarily delimit an old-style name -- at
2070 ** signs mean keep going.
2073 /* find end of name */
2074 while ((isascii(*p
) && isspace(*p
)) || *p
== ',')
2081 char pvpbuf
[PSBUFSIZE
];
2083 res
= prescan(p
, oldstyle
? ' ' : ',', pvpbuf
,
2084 sizeof(pvpbuf
), &oldp
, ExtTokenTab
, false);
2086 #if _FFR_IGNORE_BOGUS_ADDR
2087 /* ignore addresses that can't be parsed */
2093 #endif /* _FFR_IGNORE_BOGUS_ADDR */
2095 /* look to see if we have an at sign */
2096 while (*p
!= '\0' && isascii(*p
) && isspace(*p
))
2105 while (*p
!= '\0' && isascii(*p
) && isspace(*p
))
2108 /* at the end of one complete name */
2110 /* strip off trailing white space */
2112 ((isascii(*p
) && isspace(*p
)) || *p
== ',' || *p
== '\0'))
2118 ** if prescan() failed go a bit backwards; this is a hack,
2119 ** there should be some better error recovery.
2122 if (res
== NULL
&& p
> name
&&
2123 !((isascii(*p
) && isspace(*p
)) || *p
== ',' || *p
== '\0'))
2128 /* translate the name to be relative */
2129 flags
= RF_HEADERADDR
|RF_ADDDOMAIN
;
2130 if (bitset(H_FROM
, h
->h_flags
))
2131 flags
|= RF_SENDERADDR
;
2133 else if (e
->e_from
.q_mailer
!= NULL
&&
2134 bitnset(M_UDBRECIPIENT
, e
->e_from
.q_mailer
->m_flags
))
2138 q
= udbsender(name
, e
->e_rpool
);
2144 name
= remotename(name
, mci
->mci_mailer
, flags
, &status
, e
);
2150 name
= denlstring(name
, false, true);
2152 /* output the name with nice formatting */
2153 opos
+= strlen(name
);
2156 if (opos
> omax
&& !firstone
)
2158 (void) sm_strlcpy(obp
, ",\n", SPACELEFT(obuf
, obp
));
2159 if (!putxline(obuf
, strlen(obuf
), mci
, putflags
))
2162 (void) sm_strlcpy(obp
, " ", sizeof(obuf
));
2165 opos
+= strlen(name
);
2169 (void) sm_strlcpy(obp
, ", ", SPACELEFT(obuf
, obp
));
2173 while ((c
= *name
++) != '\0' && obp
< &obuf
[MAXLINE
])
2178 if (obp
< &obuf
[sizeof(obuf
)])
2181 obuf
[sizeof(obuf
) - 1] = '\0';
2182 return putxline(obuf
, strlen(obuf
), mci
, putflags
);
2189 ** COPYHEADER -- copy header list
2191 ** This routine is the equivalent of newstr for header lists
2194 ** header -- list of header structures to copy.
2195 ** rpool -- resource pool, or NULL
2198 ** a copy of 'header'.
2205 copyheader(header
, rpool
)
2206 register HDR
*header
;
2209 register HDR
*newhdr
;
2211 register HDR
**tail
= &ret
;
2213 while (header
!= NULL
)
2215 newhdr
= (HDR
*) sm_rpool_malloc_x(rpool
, sizeof(*newhdr
));
2216 STRUCTCOPY(*header
, *newhdr
);
2218 tail
= &newhdr
->h_link
;
2219 header
= header
->h_link
;
2227 ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
2229 ** Run through all of the parameters of a MIME header and
2230 ** possibly truncate and rebalance the parameter according
2231 ** to MaxMimeFieldLength.
2234 ** h -- the header to truncate/rebalance
2235 ** e -- the current envelope
2238 ** length of last offending field, 0 if all ok.
2241 ** string modified in place
2245 fix_mime_header(h
, e
)
2249 char *begin
= h
->h_value
;
2254 if (begin
== NULL
|| *begin
== '\0')
2257 /* Split on each ';' */
2258 /* find_character() never returns NULL */
2259 while ((end
= find_character(begin
, ';')) != NULL
)
2266 len
= strlen(begin
);
2268 /* Shorten individual parameter */
2269 if (shorten_rfc822_string(begin
, MaxMimeFieldLength
))
2271 if (len
< MaxMimeFieldLength
)
2273 /* we only rebalanced a bogus field */
2274 sm_syslog(LOG_ALERT
, e
->e_id
,
2275 "Fixed MIME %s header field (possible attack)",
2278 sm_dprintf(" fixed MIME %s header field (possible attack)\n",
2283 /* we actually shortened the header */
2288 /* Collapse the possibly shortened string with rest */
2289 bp
= begin
+ strlen(begin
);
2297 /* copy character by character due to overlap */