From d7ac03c10c41129058bfcad4473d778394642703 Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 24 Jan 1999 07:40:56 +0000 Subject: Check the patch obtained from sendmail.org for the header denial-of-service attack into the vendor branch. It is a little unusual doing it this way but it will eliminate (or minimize anyway) conflicts when 8.9.3 comes out. Obtained from: sendmail.org (as posted on bugtraq, but without broken tabs) --- contrib/sendmail/cf/m4/proto.m4 | 4 ++++ contrib/sendmail/src/collect.c | 44 ++++++++++++++++++++++++++++++++++++++++- contrib/sendmail/src/conf.c | 2 ++ contrib/sendmail/src/conf.h | 6 ++++++ contrib/sendmail/src/readcf.c | 23 +++++++++++++++++++++ contrib/sendmail/src/sendmail.h | 2 ++ 6 files changed, 80 insertions(+), 1 deletion(-) (limited to 'contrib/sendmail') diff --git a/contrib/sendmail/cf/m4/proto.m4 b/contrib/sendmail/cf/m4/proto.m4 index 8e79454..cce5e32 100644 --- a/contrib/sendmail/cf/m4/proto.m4 +++ b/contrib/sendmail/cf/m4/proto.m4 @@ -478,6 +478,10 @@ ifdef(`confMAX_MIME_HEADER_LENGTH', `# Maximum MIME header length to protect MUAs O MaxMimeHeaderLength=confMAX_MIME_HEADER_LENGTH ') +ifdef(`confMAX_HEADER_LINES', +`# Maximum number of header lines and header line length limit +O MaxHeaderLines=confMAX_HEADER_LINES +') ########################### # Message precedences # diff --git a/contrib/sendmail/src/collect.c b/contrib/sendmail/src/collect.c index e334e96..7e68f40 100644 --- a/contrib/sendmail/src/collect.c +++ b/contrib/sendmail/src/collect.c @@ -57,6 +57,7 @@ static EVENT *CollectTimeout; #define MS_UFROM 0 /* reading Unix from line */ #define MS_HEADER 1 /* reading message header */ #define MS_BODY 2 /* reading message body */ +#define MS_DISCARD 3 /* discarding rest of message */ void collect(fp, smtpmode, hdrp, e) @@ -77,6 +78,8 @@ collect(fp, smtpmode, hdrp, e) volatile int istate; volatile int mstate; u_char *volatile pbp; + int nhdrlines = 0; + int hdrlinelen = 0; u_char peekbuf[8]; char dfname[MAXQFNAME]; char bufbuf[MAXLINE]; @@ -198,6 +201,7 @@ collect(fp, smtpmode, hdrp, e) switch (istate) { case IS_BOL: + hdrlinelen = 0; if (c == '.') { istate = IS_DOT; @@ -262,12 +266,17 @@ collect(fp, smtpmode, hdrp, e) bufferchar: if (!headeronly) e->e_msgsize++; - if (mstate == MS_BODY) + switch (mstate) { + case MS_BODY: /* just put the character out */ if (MaxMessageSize <= 0 || e->e_msgsize <= MaxMessageSize) putc(c, tf); + + /* fall through */ + + case MS_DISCARD: continue; } @@ -298,7 +307,23 @@ bufferchar: #endif } else if (c != '\0') + { *bp++ = c; + if (MaxHeaderLineLength > 0 && + ++hdrlinelen > MaxHeaderLineLength) + { + sm_syslog(LOG_NOTICE, e->e_id, + "header line too long (%d max) from %s during message collect", + MaxHeaderLineLength, + CurHostName != NULL ? CurHostName : "localhost"); + errno = 0; + e->e_flags |= EF_CLRQUEUE; + e->e_status = "5.6.0"; + usrerr("552 Header line too long (%d max)", + MaxHeaderLineLength); + mstate = MS_DISCARD; + } + } if (istate == IS_BOL) break; } @@ -331,6 +356,22 @@ nextstate: goto nextstate; } + if (MaxHeaderLines > 0 && + ++nhdrlines > MaxHeaderLines) + { + sm_syslog(LOG_NOTICE, e->e_id, + "too many header lines (%d max) from %s during message collect", + MaxHeaderLines, + CurHostName != NULL ? CurHostName : "localhost"); + errno = 0; + e->e_flags |= EF_CLRQUEUE; + e->e_status = "5.6.0"; + usrerr("552 Too many header lines (%d max)", + MaxHeaderLines); + mstate = MS_DISCARD; + break; + } + /* check for possible continuation line */ do { @@ -350,6 +391,7 @@ nextstate: if (*--bp != '\n' || *--bp != '\r') bp++; *bp = '\0'; + if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e))) { mstate = MS_BODY; diff --git a/contrib/sendmail/src/conf.c b/contrib/sendmail/src/conf.c index 2668f9f..2544de6 100644 --- a/contrib/sendmail/src/conf.c +++ b/contrib/sendmail/src/conf.c @@ -284,6 +284,8 @@ setdefaults(e) ColonOkInAddr = TRUE; DontLockReadFiles = TRUE; DoubleBounceAddr = "postmaster"; + MaxHeaderLines = MAXHDRLINES; + MaxHeaderLineLength = MAXHDRLINELEN; snprintf(buf, sizeof buf, "%s%sdead.letter", _PATH_VARTMP, _PATH_VARTMP[sizeof _PATH_VARTMP - 2] == '/' ? "" : "/"); diff --git a/contrib/sendmail/src/conf.h b/contrib/sendmail/src/conf.h index b9cdc68..8e5a637 100644 --- a/contrib/sendmail/src/conf.h +++ b/contrib/sendmail/src/conf.h @@ -69,6 +69,12 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # else # define MAXMACNAMELEN 20 /* max macro name length */ # endif +# ifndef MAXHDRLINES +# define MAXHDRLINES 1000 /* max lines in a message header */ +# endif +# ifndef MAXHDRLINELEN +# define MAXHDRLINELEN SMTPLINELIM /* max length of a header line */ +# endif /********************************************************************** ** Compilation options. diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c index 56aa825..ab81027 100644 --- a/contrib/sendmail/src/readcf.c +++ b/contrib/sendmail/src/readcf.c @@ -1527,6 +1527,10 @@ struct optioninfo #define O_CONTROLSOCKET 0xa9 { "ControlSocketName", O_CONTROLSOCKET, FALSE }, #endif +#if _FFR_MAX_HEADER_LINES +#define O_MAXHDRLINES 0xaa + { "MaxHeaderLines", O_MAXHDRLINES, FALSE }, +#endif { NULL, '\0', FALSE } }; @@ -2466,6 +2470,25 @@ setoption(opt, val, safe, sticky, e) break; #endif +#if _FFR_MAX_HEADER_LINES + case O_MAXHDRLINES: + p = strchr(val, '/'); + if (p != NULL) + *p++ = '\0'; + MaxHeaderLines = atoi(val); + if (p != NULL && *p != '\0') + MaxHeaderLineLength = atoi(p); + + if (MaxHeaderLines > 0 && + MaxHeaderLines < 50) + printf("Warning: MaxHeaderLines: header line limit set lower than 50\n"); + + if (MaxHeaderLineLength > 0 && + MaxHeaderLineLength < MAXHDRLINELEN) + printf("Warning: MaxHeaderLines: header line length limit set lower than %d\n", MAXHDRLINELEN); + break; +#endif + default: if (tTd(37, 1)) { diff --git a/contrib/sendmail/src/sendmail.h b/contrib/sendmail/src/sendmail.h index 023799d..3c73699 100644 --- a/contrib/sendmail/src/sendmail.h +++ b/contrib/sendmail/src/sendmail.h @@ -1258,6 +1258,8 @@ EXTERN gid_t RunAsGid; /* GID to become for bulk of run */ EXTERN int MaxRcptPerMsg; /* max recipients per SMTP message */ EXTERN bool DoQueueRun; /* non-interrupt time queue run needed */ EXTERN u_long ConnectOnlyTo; /* override connection address (for testing) */ +EXTERN int MaxHeaderLines; /* max lines of headers per message */ +EXTERN int MaxHeaderLineLength; /* max length of a header line */ #if _FFR_DSN_RRT_OPTION EXTERN bool RrtImpliesDsn; /* turn Return-Receipt-To: into DSN */ #endif -- cgit v1.1