📄 parseaddr.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* 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.
*
* 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.
*
*/
#ifndef lint
static char id[] = "@(#)$Id: parseaddr.c,v 8.234.4.5 2000/09/25 07:53:29 gshapiro Exp $";
#endif /* ! lint */
#include <sendmail.h>
static void allocaddr __P((ADDRESS *, int, char *));
static int callsubr __P((char**, int, ENVELOPE *));
static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
/*
** PARSEADDR -- Parse an address
**
** Parses an address and breaks it up into three parts: a
** net to transmit the message on, the host to transmit it
** to, and a user on that host. These are loaded into an
** ADDRESS header with the values squirreled away if necessary.
** The "user" part may not be a real user; the process may
** just reoccur on that machine. For example, on a machine
** with an arpanet connection, the address
** csvax.bill@berkeley
** will break up to a "user" of 'csvax.bill' and a host
** of 'berkeley' -- to be transmitted over the arpanet.
**
** Parameters:
** addr -- the address to parse.
** a -- a pointer to the address descriptor buffer.
** If NULL, a header will be created.
** flags -- describe detail for parsing. See RF_ definitions
** in sendmail.h.
** delim -- the character to terminate the address, passed
** to prescan.
** delimptr -- if non-NULL, set to the location of the
** delim character that was found.
** e -- the envelope that will contain this address.
**
** Returns:
** A pointer to the address descriptor header (`a' if
** `a' is non-NULL).
** NULL on error.
**
** Side Effects:
** none
*/
/* following delimiters are inherent to the internal algorithms */
#define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
ADDRESS *
parseaddr(addr, a, flags, delim, delimptr, e)
char *addr;
register ADDRESS *a;
int flags;
int delim;
char **delimptr;
register ENVELOPE *e;
{
register char **pvp;
auto char *delimptrbuf;
bool qup;
char pvpbuf[PSBUFSIZE];
/*
** Initialize and prescan address.
*/
e->e_to = addr;
if (tTd(20, 1))
dprintf("\n--parseaddr(%s)\n", addr);
if (delimptr == NULL)
delimptr = &delimptrbuf;
pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
if (pvp == NULL)
{
if (tTd(20, 1))
dprintf("parseaddr-->NULL\n");
return NULL;
}
if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
{
if (tTd(20, 1))
dprintf("parseaddr-->bad address\n");
return NULL;
}
/*
** Save addr if we are going to have to.
**
** We have to do this early because there is a chance that
** the map lookups in the rewriting rules could clobber
** static memory somewhere.
*/
if (bitset(RF_COPYPADDR, flags) && addr != NULL)
{
char savec = **delimptr;
if (savec != '\0')
**delimptr = '\0';
e->e_to = addr = newstr(addr);
if (savec != '\0')
**delimptr = savec;
}
/*
** Apply rewriting rules.
** Ruleset 0 does basic parsing. It must resolve.
*/
qup = FALSE;
if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
qup = TRUE;
if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
qup = TRUE;
/*
** Build canonical address from pvp.
*/
a = buildaddr(pvp, a, flags, e);
/*
** Make local copies of the host & user and then
** transport them out.
*/
allocaddr(a, flags, addr);
if (QS_IS_BADADDR(a->q_state))
return a;
/*
** If there was a parsing failure, mark it for queueing.
*/
if (qup && OpMode != MD_INITALIAS)
{
char *msg = "Transient parse error -- message queued for future delivery";
if (e->e_sendmode == SM_DEFER)
msg = "Deferring message until queue run";
if (tTd(20, 1))
dprintf("parseaddr: queuing message\n");
message(msg);
if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
e->e_message = newstr(msg);
a->q_state = QS_QUEUEUP;
a->q_status = "4.4.3";
}
/*
** Compute return value.
*/
if (tTd(20, 1))
{
dprintf("parseaddr-->");
printaddr(a, FALSE);
}
return a;
}
/*
** INVALIDADDR -- check for address containing meta-characters
**
** Parameters:
** addr -- the address to check.
**
** Returns:
** TRUE -- if the address has any "wierd" characters
** FALSE -- otherwise.
*/
bool
invalidaddr(addr, delimptr)
register char *addr;
char *delimptr;
{
char savedelim = '\0';
if (delimptr != NULL)
{
savedelim = *delimptr;
if (savedelim != '\0')
*delimptr = '\0';
}
if (strlen(addr) > MAXNAME - 1)
{
usrerr("553 5.1.1 Address too long (%d bytes max)",
MAXNAME - 1);
goto failure;
}
for (; *addr != '\0'; addr++)
{
if ((*addr & 0340) == 0200)
break;
}
if (*addr == '\0')
{
if (delimptr != NULL && savedelim != '\0')
*delimptr = savedelim;
return FALSE;
}
setstat(EX_USAGE);
usrerr("553 5.1.1 Address contained invalid control characters");
failure:
if (delimptr != NULL && savedelim != '\0')
*delimptr = savedelim;
return TRUE;
}
/*
** ALLOCADDR -- do local allocations of address on demand.
**
** Also lowercases the host name if requested.
**
** Parameters:
** a -- the address to reallocate.
** flags -- the copy flag (see RF_ definitions in sendmail.h
** for a description).
** paddr -- the printname of the address.
**
** Returns:
** none.
**
** Side Effects:
** Copies portions of a into local buffers as requested.
*/
static void
allocaddr(a, flags, paddr)
register ADDRESS *a;
int flags;
char *paddr;
{
if (tTd(24, 4))
dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
a->q_paddr = paddr;
if (a->q_user == NULL)
a->q_user = newstr("");
if (a->q_host == NULL)
a->q_host = newstr("");
if (bitset(RF_COPYPARSE, flags))
{
a->q_host = newstr(a->q_host);
if (a->q_user != a->q_paddr)
a->q_user = newstr(a->q_user);
}
if (a->q_paddr == NULL)
a->q_paddr = newstr(a->q_user);
}
/*
** PRESCAN -- Prescan name and make it canonical
**
** Scans a name and turns it into a set of tokens. This process
** deletes blanks and comments (in parentheses) (if the token type
** for left paren is SPC).
**
** This routine knows about quoted strings and angle brackets.
**
** There are certain subtleties to this routine. The one that
** comes to mind now is that backslashes on the ends of names
** are silently stripped off; this is intentional. The problem
** is that some versions of sndmsg (like at LBL) set the kill
** character to something other than @ when reading addresses;
** so people type "csvax.eric\@berkeley" -- which screws up the
** berknet mailer.
**
** Parameters:
** addr -- the name to chomp.
** delim -- the delimiter for the address, normally
** '\0' or ','; \0 is accepted in any case.
** If '\t' then we are reading the .cf file.
** pvpbuf -- place to put the saved text -- note that
** the pointers are static.
** pvpbsize -- size of pvpbuf.
** delimptr -- if non-NULL, set to the location of the
** terminating delimiter.
** toktab -- if set, a token table to use for parsing.
** If NULL, use the default table.
**
** Returns:
** A pointer to a vector of tokens.
** NULL on error.
*/
/* states and character types */
#define OPR 0 /* operator */
#define ATM 1 /* atom */
#define QST 2 /* in quoted string */
#define SPC 3 /* chewing up spaces */
#define ONE 4 /* pick up one character */
#define ILL 5 /* illegal character */
#define NSTATES 6 /* number of states */
#define TYPE 017 /* mask to select state type */
/* meta bits for table */
#define M 020 /* meta character; don't pass through */
#define B 040 /* cause a break */
#define MB M|B /* meta-break */
static short StateTab[NSTATES][NSTATES] =
{
/* oldst chtype> OPR ATM QST SPC ONE ILL */
/*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB },
/*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB },
/*QST*/ { QST, QST, OPR, QST, QST, QST },
/*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB },
/*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB },
/*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M },
};
/* token type table -- it gets modified with $o characters */
static u_char TokTypeTab[256] =
{
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* sp ! " # $ % & ' ( ) * + , - . / */
SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* @ A B C D E F G H I J K L M N O */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* ` a b c d e f g h i j k l m n o */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* p q r s t u v w x y z { | } ~ del */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
/* sp ! " # $ % & ' ( ) * + , - . / */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* @ A B C D E F G H I J K L M N O */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* ` a b c d e f g h i j k l m n o */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* p q r s t u v w x y z { | } ~ del */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
};
/* token type table for MIME parsing */
u_char MimeTokenTab[256] =
{
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* sp ! " # $ % & ' ( ) * + , - . / */
SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
/* @ A B C D E F G H I J K L M N O */
OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
/* ` a b c d e f g h i j k l m n o */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* p q r s t u v w x y z { | } ~ del */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* sp ! " # $ % & ' ( ) * + , - . / */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* @ A B C D E F G H I J K L M N O */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* ` a b c d e f g h i j k l m n o */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
/* p q r s t u v w x y z { | } ~ del */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
};
/* token type table: don't strip comments */
u_char TokTypeNoC[256] =
{
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* sp ! " # $ % & ' ( ) * + , - . / */
SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* @ A B C D E F G H I J K L M N O */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* ` a b c d e f g h i j k l m n o */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* p q r s t u v w x y z { | } ~ del */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
/* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
/* sp ! " # $ % & ' ( ) * + , - . / */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* @ A B C D E F G H I J K L M N O */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* ` a b c d e f g h i j k l m n o */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
/* p q r s t u v w x y z { | } ~ del */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
};
#define NOCHAR -1 /* signal nothing in lookahead token */
char **
prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
char *addr;
int delim;
char pvpbuf[];
int pvpbsize;
char **delimptr;
u_char *toktab;
{
register char *p;
register char *q;
register int c;
char **avp;
bool bslashmode;
bool route_syntax;
int cmntcnt;
int anglecnt;
char *tok;
int state;
int newstate;
char *saveto = CurEnv->e_to;
static char *av[MAXATOM + 1];
static char firsttime = TRUE;
extern int errno;
if (firsttime)
{
/* initialize the token type table */
char obuf[50];
firsttime = FALSE;
if (OperatorChars == NULL)
{
if (ConfigLevel < 7)
OperatorChars = macvalue('o', CurEnv);
if (OperatorChars == NULL)
OperatorChars = ".:@[]";
}
expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS,
CurEnv);
(void) strlcat(obuf, DELIMCHARS, sizeof obuf);
for (p = obuf; *p != '\0'; p++)
{
if (TokTypeTab[*p & 0xff] == ATM)
TokTypeTab[*p & 0xff] = OPR;
if (TokTypeNoC[*p & 0xff] == ATM)
TokTypeNoC[*p & 0xff] = OPR;
}
}
if (toktab == NULL)
toktab = TokTypeTab;
/* make sure error messages don't have garbage on them */
errno = 0;
q = pvpbuf;
bslashmode = FALSE;
route_syntax = FALSE;
cmntcnt = 0;
anglecnt = 0;
avp = av;
state = ATM;
c = NOCHAR;
p = addr;
CurEnv->e_to = p;
if (tTd(22, 11))
{
dprintf("prescan: ");
xputs(p);
dprintf("\n");
}
do
{
/* read a token */
tok = q;
for (;;)
{
/* store away any old lookahead character */
if (c != NOCHAR && !bslashmode)
{
/* see if there is room */
if (q >= &pvpbuf[pvpbsize - 5])
{
usrerr("553 5.1.1 Address too long");
if (strlen(addr) > (SIZE_T) MAXNAME)
addr[MAXNAME] = '\0';
returnnull:
if (delimptr != NULL)
*delimptr = p;
CurEnv->e_to = saveto;
return NULL;
}
/* squirrel it away */
*q++ = c;
}
/* read a new input character */
c = *p++;
if (c == '\0')
{
/* diagnose and patch up bad syntax */
if (state == QST)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -