Apply patch from sendmail.org to handle a new header overflow bug.

This commit is contained in:
atatat 2003-03-03 21:20:50 +00:00
parent fedc587dac
commit 382b4984f3
4 changed files with 132 additions and 86 deletions

View File

@ -648,7 +648,8 @@ eatheader(e, full)
if (buf[0] != '\0')
{
if (bitset(H_FROM, h->h_flags))
expand(crackaddr(buf), buf, sizeof buf, e);
expand(crackaddr(buf, e),
buf, sizeof buf, e);
h->h_value = newstr(buf);
h->h_flags &= ~H_DEFAULT;
}
@ -971,7 +972,11 @@ priencode(p)
** it and replaces it with "$g". The parse is totally ad hoc
** and isn't even guaranteed to leave something syntactically
** identical to what it started with. However, it does leave
** something semantically identical.
** something semantically identical if possible, else at least
** syntactically correct.
**
** For example, it changes "Real Name <real@example.com> (Comment)"
** to "Real Name <$g> (Comment)".
**
** This algorithm has been cleaned up to handle a wider range
** of cases -- notably quoted and backslash escaped strings.
@ -980,6 +985,7 @@ priencode(p)
**
** Parameters:
** addr -- the address to be cracked.
** e -- the current envelope.
**
** Returns:
** a pointer to the new version.
@ -992,28 +998,50 @@ priencode(p)
** be copied if it is to be reused.
*/
#define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend))
/*
** Append a character to bp if we have room.
** If not, punt and return $g.
*/
#define SM_APPEND_CHAR(c) \
do \
{ \
if (SM_HAVE_ROOM) \
*bp++ = (c); \
else \
goto returng; \
} while (0)
#if MAXNAME < 10
ERROR MAXNAME must be at least 10
#endif /* MAXNAME < 10 */
char *
crackaddr(addr)
crackaddr(addr, e)
register char *addr;
ENVELOPE *e;
{
register char *p;
register char c;
int cmtlev;
int realcmtlev;
int anglelev, realanglelev;
int copylev;
int bracklev;
bool qmode;
bool realqmode;
bool skipping;
bool putgmac = FALSE;
bool quoteit = FALSE;
bool gotangle = FALSE;
bool gotcolon = FALSE;
int cmtlev; /* comment level in input string */
int realcmtlev; /* comment level in output string */
int anglelev; /* angle level in input string */
int copylev; /* 0 == in address, >0 copying */
int bracklev; /* bracket level for IPv6 addr check */
bool addangle; /* put closing angle in output */
bool qmode; /* quoting in original string? */
bool realqmode; /* quoting in output string? */
bool putgmac = FALSE; /* already wrote $g */
bool quoteit = FALSE; /* need to quote next character */
bool gotangle = FALSE; /* found first '<' */
bool gotcolon = FALSE; /* found a ':' */
register char *bp;
char *buflim;
char *bufhead;
char *addrhead;
char *bufend;
static char buf[MAXNAME + 1];
if (tTd(33, 1))
@ -1028,25 +1056,22 @@ crackaddr(addr)
** adjusted later if we find them.
*/
buflim = bufend = &buf[sizeof(buf) - 1];
bp = bufhead = buf;
buflim = &buf[sizeof buf - 7];
p = addrhead = addr;
copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
copylev = anglelev = cmtlev = realcmtlev = 0;
bracklev = 0;
qmode = realqmode = FALSE;
qmode = realqmode = addangle = FALSE;
while ((c = *p++) != '\0')
{
/*
** If the buffer is overful, go into a special "skipping"
** mode that tries to keep legal syntax but doesn't actually
** output things.
** Try to keep legal syntax using spare buffer space
** (maintained by buflim).
*/
skipping = bp >= buflim;
if (copylev > 0 && !skipping)
*bp++ = c;
if (copylev > 0)
SM_APPEND_CHAR(c);
/* check for backslash escapes */
if (c == '\\')
@ -1061,8 +1086,8 @@ crackaddr(addr)
p--;
goto putg;
}
if (copylev > 0 && !skipping)
*bp++ = c;
if (copylev > 0)
SM_APPEND_CHAR(c);
goto putg;
}
@ -1070,8 +1095,14 @@ crackaddr(addr)
if (c == '"' && cmtlev <= 0)
{
qmode = !qmode;
if (copylev > 0 && !skipping)
if (copylev > 0 && SM_HAVE_ROOM)
{
if (realqmode)
buflim--;
else
buflim++;
realqmode = !realqmode;
}
continue;
}
if (qmode)
@ -1083,15 +1114,15 @@ crackaddr(addr)
cmtlev++;
/* allow space for closing paren */
if (!skipping)
if (SM_HAVE_ROOM)
{
buflim--;
realcmtlev++;
if (copylev++ <= 0)
{
if (bp != bufhead)
*bp++ = ' ';
*bp++ = c;
SM_APPEND_CHAR(' ');
SM_APPEND_CHAR(c);
}
}
}
@ -1101,7 +1132,7 @@ crackaddr(addr)
{
cmtlev--;
copylev--;
if (!skipping)
if (SM_HAVE_ROOM)
{
realcmtlev--;
buflim++;
@ -1112,7 +1143,7 @@ crackaddr(addr)
else if (c == ')')
{
/* syntax error: unmatched ) */
if (copylev > 0 && !skipping)
if (copylev > 0 && SM_HAVE_ROOM)
bp--;
}
@ -1130,7 +1161,7 @@ crackaddr(addr)
/*
** Check for DECnet phase IV ``::'' (host::user)
** or ** DECnet phase V ``:.'' syntaxes. The latter
** or DECnet phase V ``:.'' syntaxes. The latter
** covers ``user@DEC:.tay.myhost'' and
** ``DEC:.tay.myhost::user'' syntaxes (bletch).
*/
@ -1139,10 +1170,10 @@ crackaddr(addr)
{
if (cmtlev <= 0 && !qmode)
quoteit = TRUE;
if (copylev > 0 && !skipping)
if (copylev > 0)
{
*bp++ = c;
*bp++ = *p;
SM_APPEND_CHAR(c);
SM_APPEND_CHAR(*p);
}
p++;
goto putg;
@ -1153,41 +1184,43 @@ crackaddr(addr)
bp = bufhead;
if (quoteit)
{
*bp++ = '"';
SM_APPEND_CHAR('"');
/* back up over the ':' and any spaces */
--p;
while (isascii(*--p) && isspace(*p))
while (p > addr &&
isascii(*--p) && isspace(*p))
continue;
p++;
}
for (q = addrhead; q < p; )
{
c = *q++;
if (bp < buflim)
{
if (quoteit && c == '"')
*bp++ = '\\';
*bp++ = c;
{
SM_APPEND_CHAR('\\');
SM_APPEND_CHAR(c);
}
else
SM_APPEND_CHAR(c);
}
if (quoteit)
{
if (bp == &bufhead[1])
bp--;
else
*bp++ = '"';
SM_APPEND_CHAR('"');
while ((c = *p++) != ':')
{
if (bp < buflim)
*bp++ = c;
}
*bp++ = c;
SM_APPEND_CHAR(c);
SM_APPEND_CHAR(c);
}
/* any trailing white space is part of group: */
while (isascii(*p) && isspace(*p) && bp < buflim)
*bp++ = *p++;
while (isascii(*p) && isspace(*p))
{
SM_APPEND_CHAR(*p);
p++;
}
copylev = 0;
putgmac = quoteit = FALSE;
bufhead = bp;
@ -1196,10 +1229,7 @@ crackaddr(addr)
}
if (c == ';' && copylev <= 0 && !ColonOkInAddr)
{
if (bp < buflim)
*bp++ = c;
}
SM_APPEND_CHAR(c);
/* check for characters that may have to be quoted */
if (strchr(MustQuoteChars, c) != NULL)
@ -1227,42 +1257,45 @@ crackaddr(addr)
/* oops -- have to change our mind */
anglelev = 1;
if (!skipping)
realanglelev = 1;
if (SM_HAVE_ROOM)
{
if (!addangle)
buflim--;
addangle = TRUE;
}
bp = bufhead;
if (quoteit)
{
*bp++ = '"';
SM_APPEND_CHAR('"');
/* back up over the '<' and any spaces */
--p;
while (isascii(*--p) && isspace(*p))
while (p > addr &&
isascii(*--p) && isspace(*p))
continue;
p++;
}
for (q = addrhead; q < p; )
{
c = *q++;
if (bp < buflim)
{
if (quoteit && c == '"')
*bp++ = '\\';
*bp++ = c;
{
SM_APPEND_CHAR('\\');
SM_APPEND_CHAR(c);
}
else
SM_APPEND_CHAR(c);
}
if (quoteit)
{
if (bp == &buf[1])
bp--;
else
*bp++ = '"';
SM_APPEND_CHAR('"');
while ((c = *p++) != '<')
{
if (bp < buflim)
*bp++ = c;
}
*bp++ = c;
SM_APPEND_CHAR(c);
SM_APPEND_CHAR(c);
}
copylev = 0;
putgmac = quoteit = FALSE;
@ -1274,13 +1307,14 @@ crackaddr(addr)
if (anglelev > 0)
{
anglelev--;
if (!skipping)
if (SM_HAVE_ROOM)
{
realanglelev--;
if (addangle)
buflim++;
addangle = FALSE;
}
}
else if (!skipping)
else if (SM_HAVE_ROOM)
{
/* syntax error: unmatched > */
if (copylev > 0)
@ -1289,7 +1323,7 @@ crackaddr(addr)
continue;
}
if (copylev++ <= 0)
*bp++ = c;
SM_APPEND_CHAR(c);
continue;
}
@ -1297,30 +1331,42 @@ crackaddr(addr)
putg:
if (copylev <= 0 && !putgmac)
{
if (bp > bufhead && bp[-1] == ')')
*bp++ = ' ';
*bp++ = MACROEXPAND;
*bp++ = 'g';
if (bp > buf && bp[-1] == ')')
SM_APPEND_CHAR(' ');
SM_APPEND_CHAR(MACROEXPAND);
SM_APPEND_CHAR('g');
putgmac = TRUE;
}
}
/* repair any syntactic damage */
if (realqmode)
if (realqmode && bp < bufend)
*bp++ = '"';
while (realcmtlev-- > 0)
while (realcmtlev-- > 0 && bp < bufend)
*bp++ = ')';
while (realanglelev-- > 0)
if (addangle && bp < bufend)
*bp++ = '>';
*bp++ = '\0';
*bp = '\0';
if (bp < bufend)
goto success;
returng:
/* String too long, punt */
buf[0] = '<';
buf[1] = MACROEXPAND;
buf[2]= 'g';
buf[3] = '>';
buf[4]= '\0';
sm_syslog(LOG_ALERT, e->e_id,
"Dropped invalid comments from header address");
success:
if (tTd(33, 1))
{
dprintf("crackaddr=>`");
xputs(buf);
dprintf("'\n");
}
return buf;
}
/*

View File

@ -3300,7 +3300,7 @@ testmodeline(line, e)
printf("Usage: /parse address\n");
return;
}
q = crackaddr(p);
q = crackaddr(p, e);
printf("Cracked address = ");
xputs(q);
printf("\nParsing %s %s address\n",

View File

@ -2286,7 +2286,7 @@ remotename(name, m, flags, pstat, e)
if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
fancy = "\201g";
else
fancy = crackaddr(name);
fancy = crackaddr(name, e);
/*
** Turn the name into canonical form.

View File

@ -270,7 +270,7 @@ extern ADDRESS NullAddress; /* a null (template) address [main.c] */
/* functions */
extern void cataddr __P((char **, char **, char *, int, int));
extern char *crackaddr __P((char *));
extern char *crackaddr __P((char *, ENVELOPE *));
extern bool emptyaddr __P((ADDRESS *));
extern ADDRESS *getctladdr __P((ADDRESS *));
extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *));