summaryrefslogtreecommitdiff
path: root/src/headers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/headers.c')
-rw-r--r--src/headers.c231
1 files changed, 188 insertions, 43 deletions
diff --git a/src/headers.c b/src/headers.c
index 857e9c3..6c43dcb 100644
--- a/src/headers.c
+++ b/src/headers.c
@@ -1,39 +1,17 @@
/*
- * Copyright (c) 1983, 1995-1997 Eric P. Allman
+ * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
*/
#ifndef lint
-static char sccsid[] = "@(#)headers.c 8.115 (Berkeley) 10/22/97";
+static char sccsid[] = "@(#)headers.c 8.136 (Berkeley) 1/26/1999";
#endif /* not lint */
# include <errno.h>
@@ -99,6 +77,7 @@ chompheader(line, def, hdrp, e)
bool headeronly;
STAB *s;
struct hdrinfo *hi;
+ bool nullheader = FALSE;
BITMAP mopts;
if (tTd(31, 6))
@@ -145,17 +124,22 @@ chompheader(line, def, hdrp, e)
return 0;
}
*fvalue = '\0';
- fvalue = p;
/* strip field value on front */
- if (*fvalue == ' ')
- fvalue++;
+ if (*p == ' ')
+ p++;
+ fvalue = p;
+
+ /* if the field is null, go ahead and use the default */
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p == '\0')
+ nullheader = TRUE;
/* security scan: long field names are end-of-header */
if (strlen(fname) > 100)
return H_EOH;
-#if _FFR_HEADER_RSCHECK
/* check to see if it represents a ruleset call */
if (def)
{
@@ -177,7 +161,6 @@ chompheader(line, def, hdrp, e)
return 0;
}
}
-#endif
/* see if it is a known type */
s = stab(fname, ST_HEADER, ST_FIND);
@@ -206,7 +189,7 @@ chompheader(line, def, hdrp, e)
(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
/* if this means "end of header" quit now */
- if (bitset(H_EOH, hi->hi_flags))
+ if (!headeronly && bitset(H_EOH, hi->hi_flags))
return hi->hi_flags;
/*
@@ -260,6 +243,11 @@ chompheader(line, def, hdrp, e)
bitset(H_DEFAULT, h->h_flags) &&
!bitset(H_FORCE, h->h_flags))
{
+ if (nullheader)
+ {
+ /* user-supplied value was null */
+ return 0;
+ }
h->h_value = NULL;
if (!cond)
{
@@ -278,6 +266,10 @@ chompheader(line, def, hdrp, e)
bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
*hp = h;
h->h_flags = hi->hi_flags;
+
+ /* strip EOH flag if parsing MIME headers */
+ if (headeronly)
+ h->h_flags &= ~H_EOH;
if (def)
h->h_flags |= H_DEFAULT;
if (cond)
@@ -463,7 +455,22 @@ eatheader(e, full)
/* full name of from person */
p = hvalue("full-name", e->e_header);
if (p != NULL)
+ {
+ extern bool rfc822_string __P((char *));
+
+ if (!rfc822_string(p))
+ {
+ extern char *addquotes __P((char *));
+
+ /*
+ ** Quote a full name with special characters
+ ** as a comment so crackaddr() doesn't destroy
+ ** the name portion of the address.
+ */
+ p = addquotes(p);
+ }
define('x', p, e);
+ }
if (tTd(32, 1))
printf("----- collected header -----\n");
@@ -493,7 +500,7 @@ eatheader(e, full)
{
if (bitset(H_FROM, h->h_flags))
{
- extern char *crackaddr();
+ extern char *crackaddr __P((char *));
expand(crackaddr(buf), buf, sizeof buf, e);
}
@@ -517,15 +524,17 @@ eatheader(e, full)
!bitset(H_DEFAULT, h->h_flags) &&
(!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
{
+#if 0
int saveflags = e->e_flags;
+#endif
(void) sendtolist(h->h_value, NULLADDR,
&e->e_sendqueue, 0, e);
#if 0
/*
- ** Change functionality so a fatal error on an
- ** address doesn't affect the entire envelope.
+ ** Change functionality so a fatal error on an
+ ** address doesn't affect the entire envelope.
*/
/* delete fatal errors generated by this address */
@@ -1152,6 +1161,7 @@ crackaddr(addr)
** mci -- the connection information.
** h -- the header to put.
** e -- envelope to use.
+** flags -- MIME conversion flags.
**
** Returns:
** none.
@@ -1168,10 +1178,11 @@ crackaddr(addr)
#endif
void
-putheader(mci, hdr, e)
+putheader(mci, hdr, e, flags)
register MCI *mci;
HDR *hdr;
register ENVELOPE *e;
+ int flags;
{
register HDR *h;
char buf[MAX(MAXLINE,BUFSIZ)];
@@ -1181,11 +1192,19 @@ putheader(mci, hdr, e)
printf("--- putheader, mailer = %s ---\n",
mci->mci_mailer->m_name);
- mci->mci_flags |= MCIF_INHEADER;
+ /*
+ ** If we're in MIME mode, we're not really in the header of the
+ ** message, just the header of one of the parts of the body of
+ ** the message. Therefore MCIF_INHEADER should not be turned on.
+ */
+
+ if (!bitset(MCIF_INMIME, mci->mci_flags))
+ mci->mci_flags |= MCIF_INHEADER;
+
for (h = hdr; h != NULL; h = h->h_link)
{
register char *p = h->h_value;
- extern bool bitintersect();
+ extern bool bitintersect __P((BITMAP, BITMAP));
if (tTd(34, 11))
{
@@ -1193,9 +1212,69 @@ putheader(mci, hdr, e)
xputs(p);
}
- /* suppress Content-Transfer-Encoding: if we are MIMEing */
+#if _FFR_MAX_MIME_HEADER_LENGTH
+ /* heuristic shortening of MIME fields to avoid MUA overflows */
+ if (MaxMimeFieldLength > 0 &&
+ wordinclass(h->h_field,
+ macid("{checkMIMEFieldHeaders}", NULL)))
+ {
+ extern bool fix_mime_header __P((char *));
+
+ if (fix_mime_header(h->h_value))
+ {
+ sm_syslog(LOG_ALERT, e->e_id,
+ "Truncated MIME %s header due to field size (possible attack)",
+ h->h_field);
+ if (tTd(34, 11))
+ printf(" truncated MIME %s header due to field size (possible attack)\n",
+ h->h_field);
+ }
+ }
+
+ if (MaxMimeHeaderLength > 0 &&
+ wordinclass(h->h_field,
+ macid("{checkMIMETextHeaders}", NULL)))
+ {
+ if (strlen(h->h_value) > MaxMimeHeaderLength)
+ {
+ h->h_value[MaxMimeHeaderLength - 1] = '\0';
+ sm_syslog(LOG_ALERT, e->e_id,
+ "Truncated long MIME %s header (possible attack)",
+ h->h_field);
+ if (tTd(34, 11))
+ printf(" truncated long MIME %s header (possible attack)\n",
+ h->h_field);
+ }
+ }
+
+ if (MaxMimeHeaderLength > 0 &&
+ wordinclass(h->h_field,
+ macid("{checkMIMEHeaders}", NULL)))
+ {
+ extern bool shorten_rfc822_string __P((char *, int));
+
+ if (shorten_rfc822_string(h->h_value, MaxMimeHeaderLength))
+ {
+ sm_syslog(LOG_ALERT, e->e_id,
+ "Truncated long MIME %s header (possible attack)",
+ h->h_field);
+ if (tTd(34, 11))
+ printf(" truncated long MIME %s header (possible attack)\n",
+ h->h_field);
+ }
+ }
+#endif
+
+ /*
+ ** Suppress Content-Transfer-Encoding: if we are MIMEing
+ ** and we are potentially converting from 8 bit to 7 bit
+ ** MIME. If converting, add a new CTE header in
+ ** mime8to7().
+ */
if (bitset(H_CTE, h->h_flags) &&
- bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags))
+ bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
+ mci->mci_flags) &&
+ !bitset(M87F_NO8TO7, flags))
{
if (tTd(34, 11))
printf(" (skipped (content-transfer-encoding))\n");
@@ -1483,7 +1562,7 @@ commaize(h, p, oldstyle, mci, e)
else if (e->e_from.q_mailer != NULL &&
bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
{
- extern char *udbsender();
+ extern char *udbsender __P((char *));
char *q;
q = udbsender(name);
@@ -1563,3 +1642,69 @@ copyheader(header)
return ret;
}
+ /*
+** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
+**
+** Run through all of the parameters of a MIME header and
+** possibly truncate and rebalance the parameter according
+** to MaxMimeFieldLength.
+**
+** Parameters:
+** string -- the full header
+**
+** Returns:
+** TRUE if the header was modified, FALSE otherwise
+**
+** Side Effects:
+** string modified in place
+*/
+
+bool
+fix_mime_header(string)
+ char *string;
+{
+ bool modified = FALSE;
+ char *begin = string;
+ char *end;
+ extern char *find_character __P((char *, char));
+ extern bool shorten_rfc822_string __P((char *, int));
+
+ if (string == NULL || *string == '\0')
+ return FALSE;
+
+ /* Split on each ';' */
+ while ((end = find_character(begin, ';')) != NULL)
+ {
+ char save = *end;
+ char *bp;
+
+ *end = '\0';
+
+ /* Shorten individual parameter */
+ if (shorten_rfc822_string(begin, MaxMimeFieldLength))
+ modified = TRUE;
+
+ /* Collapse the possibly shortened string with rest */
+ bp = begin + strlen(begin);
+ if (bp != end)
+ {
+ char *ep = end;
+
+ *end = save;
+ end = bp;
+
+ /* copy character by character due to overlap */
+ while (*ep != '\0')
+ *bp++ = *ep++;
+ *bp = '\0';
+ }
+ else
+ *end = save;
+ if (*end == '\0')
+ break;
+
+ /* Move past ';' */
+ begin = end + 1;
+ }
+ return modified;
+}