Add $[ and $] as RHS operators to look up the contents and pass them
[unix-history] / usr / src / usr.sbin / sendmail / src / parseaddr.c
index bcf8697..74f1ba6 100644 (file)
@@ -1,6 +1,6 @@
 # include "sendmail.h"
 
 # include "sendmail.h"
 
-SCCSID(@(#)parseaddr.c 3.76            %G%);
+SCCSID(@(#)parseaddr.c 4.9             %G%);
 
 /*
 **  PARSEADDR -- Parse an address
 
 /*
 **  PARSEADDR -- Parse an address
@@ -28,6 +28,8 @@ SCCSID(@(#)parseaddr.c        3.76            %G%);
 **                     0 -- copy out the parsed user & host, but
 **                             don't copy the printname.
 **                     +1 -- copy everything.
 **                     0 -- copy out the parsed user & host, but
 **                             don't copy the printname.
 **                     +1 -- copy everything.
+**             delim -- the character to terminate the address, passed
+**                     to prescan.
 **
 **     Returns:
 **             A pointer to the address descriptor header (`a' if
 **
 **     Returns:
 **             A pointer to the address descriptor header (`a' if
@@ -39,16 +41,18 @@ SCCSID(@(#)parseaddr.c      3.76            %G%);
 */
 
 /* following delimiters are inherent to the internal algorithms */
 */
 
 /* following delimiters are inherent to the internal algorithms */
-# define DELIMCHARS    "$()<>,;\\\"\r\n"       /* word delimiters */
+# define DELIMCHARS    "\001()<>,;\\\"\r\n"    /* word delimiters */
 
 ADDRESS *
 
 ADDRESS *
-parseaddr(addr, a, copyf)
+parseaddr(addr, a, copyf, delim)
        char *addr;
        register ADDRESS *a;
        int copyf;
        char *addr;
        register ADDRESS *a;
        int copyf;
+       char delim;
 {
        register char **pvp;
        register struct mailer *m;
 {
        register char **pvp;
        register struct mailer *m;
+       char pvpbuf[PSBUFSIZE];
        extern char **prescan();
        extern ADDRESS *buildaddr();
 
        extern char **prescan();
        extern ADDRESS *buildaddr();
 
@@ -62,7 +66,7 @@ parseaddr(addr, a, copyf)
                printf("\n--parseaddr(%s)\n", addr);
 # endif DEBUG
 
                printf("\n--parseaddr(%s)\n", addr);
 # endif DEBUG
 
-       pvp = prescan(addr, ',');
+       pvp = prescan(addr, delim, pvpbuf);
        if (pvp == NULL)
                return (NULL);
 
        if (pvp == NULL)
                return (NULL);
 
@@ -121,13 +125,12 @@ parseaddr(addr, a, copyf)
        }
 
        /*
        }
 
        /*
-       **  Do UPPER->lower case mapping unless inhibited.
+       **  Convert host name to lower case if requested.
+       **      User name will be done later.
        */
 
        if (!bitnset(M_HST_UPPER, m->m_flags))
                makelower(a->q_host);
        */
 
        if (!bitnset(M_HST_UPPER, m->m_flags))
                makelower(a->q_host);
-       if (!bitnset(M_USR_UPPER, m->m_flags))
-               makelower(a->q_user);
 
        /*
        **  Compute return value.
 
        /*
        **  Compute return value.
@@ -144,6 +147,27 @@ parseaddr(addr, a, copyf)
        return (a);
 }
 \f/*
        return (a);
 }
 \f/*
+**  LOWERADDR -- map UPPER->lower case on addresses as requested.
+**
+**     Parameters:
+**             a -- address to be mapped.
+**
+**     Returns:
+**             none.
+**
+**     Side Effects:
+**             none.
+*/
+
+loweraddr(a)
+       register ADDRESS *a;
+{
+       register MAILER *m = a->q_mailer;
+
+       if (!bitnset(M_USR_UPPER, m->m_flags))
+               makelower(a->q_user);
+}
+\f/*
 **  PRESCAN -- Prescan name and make it canonical
 **
 **     Scans a name and turns it into a set of tokens.  This process
 **  PRESCAN -- Prescan name and make it canonical
 **
 **     Scans a name and turns it into a set of tokens.  This process
@@ -163,6 +187,9 @@ parseaddr(addr, a, copyf)
 **             addr -- the name to chomp.
 **             delim -- the delimiter for the address, normally
 **                     '\0' or ','; \0 is accepted in any case.
 **             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.
 **
 **     Returns:
 **             A pointer to a vector of tokens.
 **
 **     Returns:
 **             A pointer to a vector of tokens.
@@ -202,9 +229,10 @@ static short StateTab[NSTATES][NSTATES] =
 char   *DelimChar;             /* set to point to the delimiter */
 
 char **
 char   *DelimChar;             /* set to point to the delimiter */
 
 char **
-prescan(addr, delim)
+prescan(addr, delim, pvpbuf)
        char *addr;
        char delim;
        char *addr;
        char delim;
+       char pvpbuf[];
 {
        register char *p;
        register char *q;
 {
        register char *p;
        register char *q;
@@ -216,10 +244,13 @@ prescan(addr, delim)
        char *tok;
        int state;
        int newstate;
        char *tok;
        int state;
        int newstate;
-       static char buf[MAXNAME+MAXATOM];
        static char *av[MAXATOM+1];
        static char *av[MAXATOM+1];
+       extern int errno;
+
+       /* make sure error messages don't have garbage on them */
+       errno = 0;
 
 
-       q = buf;
+       q = pvpbuf;
        bslashmode = FALSE;
        cmntcnt = 0;
        anglecnt = 0;
        bslashmode = FALSE;
        cmntcnt = 0;
        anglecnt = 0;
@@ -245,13 +276,15 @@ prescan(addr, delim)
                        /* store away any old lookahead character */
                        if (c != NOCHAR)
                        {
                        /* store away any old lookahead character */
                        if (c != NOCHAR)
                        {
-                               /* squirrel it away */
-                               if (q >= &buf[sizeof buf - 5])
+                               /* see if there is room */
+                               if (q >= &pvpbuf[PSBUFSIZE - 5])
                                {
                                        usrerr("Address too long");
                                        DelimChar = p;
                                        return (NULL);
                                }
                                {
                                        usrerr("Address too long");
                                        DelimChar = p;
                                        return (NULL);
                                }
+
+                               /* squirrel it away */
                                *q++ = c;
                        }
 
                                *q++ = c;
                        }
 
@@ -259,13 +292,14 @@ prescan(addr, delim)
                        c = *p++;
                        if (c == '\0')
                                break;
                        c = *p++;
                        if (c == '\0')
                                break;
+                       c &= ~0200;
+
 # ifdef DEBUG
                        if (tTd(22, 101))
                                printf("c=%c, s=%d; ", c, state);
 # endif DEBUG
 
                        /* chew up special characters */
 # ifdef DEBUG
                        if (tTd(22, 101))
                                printf("c=%c, s=%d; ", c, state);
 # endif DEBUG
 
                        /* chew up special characters */
-                       c &= ~0200;
                        *q = '\0';
                        if (bslashmode)
                        {
                        *q = '\0';
                        if (bslashmode)
                        {
@@ -311,6 +345,8 @@ prescan(addr, delim)
                                }
                                anglecnt--;
                        }
                                }
                                anglecnt--;
                        }
+                       else if (delim == ' ' && isspace(c))
+                               c = ' ';
                        else if (c == ':' && !CurEnv->e_oldstyle)
                        {
                                /* consume characters until a semicolon */
                        else if (c == ':' && !CurEnv->e_oldstyle)
                        {
                                /* consume characters until a semicolon */
@@ -327,7 +363,7 @@ prescan(addr, delim)
                                continue;
 
                        /* see if this is end of input */
                                continue;
 
                        /* see if this is end of input */
-                       if (c == delim && anglecnt <= 0)
+                       if (c == delim && anglecnt <= 0 && state != QST)
                                break;
 
                        newstate = StateTab[state][toktype(c)];
                                break;
 
                        newstate = StateTab[state][toktype(c)];
@@ -397,7 +433,7 @@ toktype(c)
        if (firstime)
        {
                firstime = FALSE;
        if (firstime)
        {
                firstime = FALSE;
-               expand("$o", buf, &buf[sizeof buf - 1], CurEnv);
+               expand("\001o", buf, &buf[sizeof buf - 1], CurEnv);
                (void) strcat(buf, DELIMCHARS);
        }
        if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
                (void) strcat(buf, DELIMCHARS);
        }
        if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
@@ -463,6 +499,8 @@ rewrite(pvp, ruleset)
        register char **rvp;            /* rewrite vector pointer */
        register struct match *mlp;     /* cur ptr into mlist */
        register struct rewrite *rwr;   /* pointer to current rewrite rule */
        register char **rvp;            /* rewrite vector pointer */
        register struct match *mlp;     /* cur ptr into mlist */
        register struct rewrite *rwr;   /* pointer to current rewrite rule */
+       int subr;                       /* subroutine number if >= 0 */
+       bool dolookup;                  /* do host aliasing */
        struct match mlist[MAXMATCH];   /* stores match on LHS */
        char *npvp[MAXATOM+1];          /* temporary space for rebuild */
        extern bool sameword();
        struct match mlist[MAXMATCH];   /* stores match on LHS */
        char *npvp[MAXATOM+1];          /* temporary space for rebuild */
        extern bool sameword();
@@ -630,66 +668,178 @@ rewrite(pvp, ruleset)
                        rwr = NULL;
 
                /* substitute */
                        rwr = NULL;
 
                /* substitute */
+               dolookup = FALSE;
                for (avp = npvp; *rvp != NULL; rvp++)
                {
                        register struct match *m;
                        register char **pp;
 
                        rp = *rvp;
                for (avp = npvp; *rvp != NULL; rvp++)
                {
                        register struct match *m;
                        register char **pp;
 
                        rp = *rvp;
-                       if (*rp != MATCHREPL)
+
+                       /* check to see if we should do a lookup */
+                       if (*rp == MATCHLOOKUP)
+                               dolookup = TRUE;
+
+                       /* see if there is substitution here */
+                       if (*rp == MATCHREPL)
                        {
                        {
-                               if (avp >= &npvp[MAXATOM])
+                               /* substitute from LHS */
+                               m = &mlist[rp[1] - '1'];
+                               if (m >= mlp)
                                {
                                {
-                                       syserr("rewrite: expansion too long");
+                                 toolong:
+                                       syserr("rewrite: ruleset %d: replacement out of bounds", ruleset);
                                        return;
                                }
                                        return;
                                }
-                               *avp++ = rp;
-                               continue;
-                       }
-
-                       /* substitute from LHS */
-                       m = &mlist[rp[1] - '1'];
 # ifdef DEBUG
 # ifdef DEBUG
-                       if (tTd(21, 15))
-                       {
-                               printf("$%c:", rp[1]);
+                               if (tTd(21, 15))
+                               {
+                                       printf("$%c:", rp[1]);
+                                       pp = m->first;
+                                       while (pp <= m->last)
+                                       {
+                                               printf(" %x=\"", *pp);
+                                               (void) fflush(stdout);
+                                               printf("%s\"", *pp++);
+                                       }
+                                       printf("\n");
+                               }
+# endif DEBUG
                                pp = m->first;
                                while (pp <= m->last)
                                {
                                pp = m->first;
                                while (pp <= m->last)
                                {
-                                       printf(" %x=\"", *pp);
-                                       (void) fflush(stdout);
-                                       printf("%s\"", *pp++);
+                                       if (avp >= &npvp[MAXATOM])
+                                       {
+                                               syserr("rewrite: expansion too long");
+                                               return;
+                                       }
+                                       *avp++ = *pp++;
                                }
                                }
-                               printf("\n");
                        }
                        }
-# endif DEBUG
-                       pp = m->first;
-                       while (pp <= m->last)
+                       else
                        {
                        {
+                               /* vanilla replacement */
                                if (avp >= &npvp[MAXATOM])
                                if (avp >= &npvp[MAXATOM])
-                               {
-                                       syserr("rewrite: expansion too long");
-                                       return;
-                               }
-                               *avp++ = *pp++;
+                                       goto toolong;
+                               *avp++ = rp;
                        }
                }
                *avp++ = NULL;
                        }
                }
                *avp++ = NULL;
-               if (**npvp == CALLSUBR)
+
+               /*
+               **  Check for any hostname lookups.
+               */
+
+               for (rvp = npvp; *rvp != NULL; rvp++)
                {
                {
-                       bmove((char *) &npvp[2], (char *) pvp,
-                               (avp - npvp - 2) * sizeof *avp);
-# ifdef DEBUG
-                       if (tTd(21, 3))
-                               printf("-----callsubr %s\n", npvp[1]);
-# endif DEBUG
-                       rewrite(pvp, atoi(npvp[1]));
+                       char **hbrvp;
+                       char **xpvp;
+                       int trsize;
+                       int i;
+                       char buf[MAXATOM + 1];
+                       char *pvpb1[MAXATOM + 1];
+                       static char pvpbuf[PSBUFSIZE];
+
+                       if (**rvp != HOSTBEGIN)
+                               continue;
+
+                       /*
+                       **  Got a hostname lookup.
+                       **
+                       **      This could be optimized fairly easily.
+                       */
+
+                       hbrvp = rvp;
+
+                       /* extract the match part */
+                       while (*++rvp != NULL && **rvp != HOSTEND)
+                               continue;
+                       if (*rvp != NULL)
+                               *rvp++ = NULL;
+
+                       /* save the remainder of the input string */
+                       trsize = (int) (avp - rvp + 1) * sizeof *rvp;
+                       bcopy((char *) rvp, (char *) pvpb1, trsize);
+
+                       /* look it up */
+                       cataddr(++hbrvp, buf, sizeof buf);
+                       maphostname(buf, sizeof buf);
+
+                       /* scan the new host name */
+                       xpvp = prescan(buf, '\0', pvpbuf);
+                       if (xpvp == NULL)
+                       {
+                               syserr("rewrite: cannot prescan canonical hostname: %s", buf);
+                               return (NULL);
+                       }
+
+                       /* append it to the token list */
+                       rvp = --hbrvp;
+                       while ((*rvp++ = *xpvp++) != NULL)
+                               if (rvp >= &npvp[MAXATOM])
+                                       goto toolong;
+
+                       /* restore the old trailing information */
+                       for (xpvp = pvpb1, rvp--; (*rvp++ = *xpvp++) != NULL; )
+                               if (rvp >= &npvp[MAXATOM])
+                                       goto toolong;
+               }
+
+               /*
+               **  Check for subroutine calls.
+               */
+
+
+               /*
+               **  Do hostname lookup if requested.
+               */
+
+               if (dolookup)
+               {
+                       extern char **maphost();
+
+                       rvp = maphost(npvp);
                }
                else
                }
                else
+                       rvp = npvp;
+
+               /*
+               **  See if this is a subroutine call.
+               */
+
+               if (**rvp == CALLSUBR)
                {
                {
-                       bmove((char *) npvp, (char *) pvp,
-                               (avp - npvp) * sizeof *avp);
+                       subr = atoi(*++rvp);
+                       rvp++;
                }
                }
+               else
+                       subr = -1;
+
+               /*
+               **  Copy result back to original string.
+               */
+
+               for (avp = pvp; *rvp != NULL; rvp++)
+                       *avp++ = *rvp;
+               *avp = NULL;
+
+               /*
+               **  If this specified a subroutine, call it.
+               */
+
+               if (subr >= 0)
+               {
+# ifdef DEBUG
+                       if (tTd(21, 3))
+                               printf("-----callsubr %s\n", subr);
+# endif DEBUG
+                       rewrite(pvp, subr);
+               }
+
+               /*
+               **  Done with rewriting this pass.
+               */
+
 # ifdef DEBUG
                if (tTd(21, 4))
                {
 # ifdef DEBUG
                if (tTd(21, 4))
                {
@@ -796,7 +946,8 @@ buildaddr(tv, a)
                syserr("buildaddr: no user");
                return (NULL);
        }
                syserr("buildaddr: no user");
                return (NULL);
        }
-       cataddr(++tv, buf, sizeof buf);
+       rewrite(++tv, 4);
+       cataddr(tv, buf, sizeof buf);
        a->q_user = buf;
 
        return (a);
        a->q_user = buf;
 
        return (a);
@@ -974,10 +1125,12 @@ remotename(name, m, senderaddress, canonical)
 {
        register char **pvp;
        char *fancy;
 {
        register char **pvp;
        char *fancy;
+       register char *p;
        extern char *macvalue();
        char *oldg = macvalue('g', CurEnv);
        static char buf[MAXNAME];
        char lbuf[MAXNAME];
        extern char *macvalue();
        char *oldg = macvalue('g', CurEnv);
        static char buf[MAXNAME];
        char lbuf[MAXNAME];
+       char pvpbuf[PSBUFSIZE];
        extern char **prescan();
        extern char *crackaddr();
 
        extern char **prescan();
        extern char *crackaddr();
 
@@ -996,7 +1149,7 @@ remotename(name, m, senderaddress, canonical)
        */
 
        if (canonical)
        */
 
        if (canonical)
-               fancy = "$g";
+               fancy = "\001g";
        else
                fancy = crackaddr(name);
 
        else
                fancy = crackaddr(name);
 
@@ -1008,7 +1161,7 @@ remotename(name, m, senderaddress, canonical)
        **      domain will be appended.
        */
 
        **      domain will be appended.
        */
 
-       pvp = prescan(name, '\0');
+       pvp = prescan(name, '\0', pvpbuf);
        if (pvp == NULL)
                return (name);
        rewrite(pvp, 3);
        if (pvp == NULL)
                return (name);
        rewrite(pvp, 3);
@@ -1027,6 +1180,7 @@ remotename(name, m, senderaddress, canonical)
 
                        while ((*pxp++ = *qxq++) != NULL)
                                continue;
 
                        while ((*pxp++ = *qxq++) != NULL)
                                continue;
+                       rewrite(pvp, 3);
                }
        }
 
                }
        }