* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
- * %sccs.include.redist.c%
+ * 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.
+ *
+ * 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[] = "@(#)parseaddr.c 8.30 (Berkeley) %G%";
+static char sccsid[] = "@(#)parseaddr.c 8.31 (Berkeley) 4/15/94";
#endif /* not lint */
-#include "sendmail.h"
-
-#ifdef CC_WONT_PROMOTE
-static int toktype __P((char));
-#else /* !CC_WONT_PROMOTE */
-static int toktype __P((int)); /* char -> int */
-#endif /* CC_WONT_PROMOTE */
-static void _rewrite __P((char **, int));
-static void callsubr __P((char **));
-static ADDRESS * buildaddr __P((char **, ADDRESS *));
-static void uurelativize __P((const char *, const char *, char **));
-
-char *DelimChar; /* set to point to the delimiter */
+# include "sendmail.h"
/*
** PARSEADDR -- Parse an address
auto char *delimptrbuf;
bool queueup;
char pvpbuf[PSBUFSIZE];
+ extern ADDRESS *buildaddr();
+ extern bool invalidaddr();
/*
** Initialize and prescan address.
if (tTd(20, 1))
printf("\n--parseaddr(%s)\n", addr);
- {
- extern char *DelimChar; /* parseaddr.c */
- char savec;
- bool invalid;
- extern char *finddelim();
- extern bool invalidaddr();
-
- DelimChar = finddelim(addr, delim);
- savec = *DelimChar;
- *DelimChar = '\0';
- invalid = invalidaddr(addr);
- *DelimChar = savec;
- if (invalid)
- return (NULL);
- }
-
if (delimptr == NULL)
delimptr = &delimptrbuf;
if (savec != '\0')
**delimptr = '\0';
- addr = newstr(addr);
+ e->e_to = addr = newstr(addr);
if (savec != '\0')
**delimptr = savec;
}
a->q_paddr = a->q_user;
}
\f/*
-** INVALIDADDR -- check an address string for invalid control characters.
-**
-** Parameters:
-** addr -- address string to be checked.
-**
-** Returns:
-** TRUE if address string could cause problems, FALSE o/w.
-**
-** Side Effects:
-** ExitStat may be changed and an error message generated.
-*/
-
-bool
-invalidaddr(addr)
- const char *addr;
-{
- register const char *cp;
-
- /* make sure error messages don't have garbage on them */
- errno = 0;
-
- /*
- ** Sendmail reserves characters 020 - 036 for rewriting rules
- ** which can cause havoc (e.g. infinite rewriting loops) if
- ** one shows up at the wrong time. If any of these characters
- ** appear in an address, the address is deemed "invalid" and
- ** an error message is generated.
- */
-
- for (cp = addr; *cp; cp++)
- if ((*cp >= MATCHZANY && *cp <= HOSTEND) || *cp == '\001')
- {
- setstat(EX_USAGE);
- usrerr("address contained invalid control char(s)");
- return (TRUE);
- }
- return (FALSE);
-}
-\f/*
** PRESCAN -- Prescan name and make it canonical
**
** Scans a name and turns it into a set of tokens. This process
char *saveto = CurEnv->e_to;
static char *av[MAXATOM+1];
static char firsttime = TRUE;
+ extern int errno;
if (firsttime)
{
{
bslashmode = TRUE;
}
- if (state == QST)
+ else if (state == QST)
{
/* do nothing, just avoid next clauses */
}
}
else if (delim == ' ' && isascii(c) && isspace(c))
c = ' ';
- else if (c == ':' && !CurEnv->e_oldstyle)
- {
- /* consume characters until a semicolon */
- while (*p != '\0' && *p != ';')
- p++;
- if (*p == '\0')
- usrerr("Unbalanced ':...;' group spec");
- else
- p++;
- c = ' ';
- }
-
- else if (c == ';') /* semicolons are not tokens */
- c = NOCHAR;
if (c == NOCHAR)
continue;
** pvp is modified.
*/
-# define OP_NONZLEN 00001
-# define OP_VARLEN 00002
-# define OP_CLASS 00004
-# define OP_EXACT 00010
-
struct match
{
char **first; /* first token matched */
char **last; /* last token matched */
char **pattern; /* pointer to pattern */
- char **source; /* left hand source operand */
- char flags; /* attributes of this operator */
};
# define MAXMATCH 9 /* max params per rewrite */
-# define MAX_CONTROL ' '
# ifndef MAXRULERECURSION
# define MAXRULERECURSION 50 /* max recursion depth */
# endif
-static char control_opts[MAX_CONTROL];
int
-static char control_init_data[] = {
- MATCHZANY, OP_VARLEN,
- MATCHONE, OP_NONZLEN,
- MATCHANY, OP_VARLEN|OP_NONZLEN,
-#ifdef MACVALUE
- MACVALUE, OP_EXACT,
-#endif /* MACVALUE */
- MATCHNCLASS, OP_NONZLEN,
- MATCHCLASS, OP_NONZLEN|OP_VARLEN|OP_CLASS,
-};
-
-static int nrw;
-
-void
rewrite(pvp, ruleset, reclevel, e)
char **pvp;
int ruleset;
int reclevel;
register ENVELOPE *e;
-{
- nrw = 0;
- _rewrite(pvp, ruleset);
-}
-
-static void
-_rewrite(pvp, ruleset)
- char **pvp;
- int ruleset;
{
register char *ap; /* address pointer */
register char *rp; /* rewrite pointer */
int ruleno; /* current rule number */
int rstat = EX_OK; /* return status */
int loopcount;
- 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 */
- char tokbuf[MAXNAME+1]; /* for concatenated class tokens */
- int nloops, nmatches = 0; /* for looping rule checks */
- struct rewrite *prev_rwr; /* pointer to previous rewrite rule */
- struct match mlist[MAXMATCH+1]; /* stores match on LHS */
- struct match *old_mlp; /* to save our place */
- bool extend_match; /* extend existing match during backup */
if (OpMode == MD_TEST || tTd(21, 2))
{
printf("rewrite: ruleset %2d input:", ruleset);
- printcav(pvp);
+ printav(pvp);
}
if (ruleset < 0 || ruleset >= MAXRWSETS)
{
if (pvp == NULL)
return EX_USAGE;
- if (++nrw > 100)
- {
- char buf[MAXLINE];
-
- buf[0] = buf[MAXLINE-1] = 0;
- while (*pvp)
- (void) strncat(buf, *pvp++, sizeof buf);
- syserr("address causes rewrite loop: <%s>", buf);
- return;
- }
-
- /* Be sure to recognize first rule as new */
- prev_rwr = NULL;
-
/*
- ** Run through the list of rewrite rules, applying any that match.
+ ** Run through the list of rewrite rules, applying
+ ** any that match.
*/
ruleno = 1;
if (tTd(21, 12))
{
printf("-----trying rule:");
- printcav(rwr->r_lhs);
- }
-
- /*
- ** Set up the match list. This is done once for each
- ** rule. If a rule is used repeatedly, the list need not
- ** be set up the next time.
- */
-
- if (rwr != prev_rwr)
- {
- prev_rwr = rwr;
- for (rvp = rwr->r_lhs, mlp = mlist;
- *rvp && (mlp < &mlist[MAXMATCH]); rvp++)
- {
- mlp->flags = ((unsigned char) **rvp >= MAX_CONTROL) ?
- 0 : control_opts[**rvp] ;
- if (mlp->flags)
- {
- mlp->source = rvp;
- mlp++;
- }
- }
- if (*rvp)
- {
- syserr("Too many variables on LHS in ruleset %d", ruleset);
- return;
- }
- mlp->source = rvp;
-
- /* Make sure end marker is initialized */
- mlp->flags = 0;
+ printav(rwr->r_lhs);
}
/* try to match on this rule */
mlp = mlist;
-
rvp = rwr->r_lhs;
avp = pvp;
- nloops = 0;
- extend_match = FALSE;
-
if (++loopcount > 100)
{
- if (nloops++ > 400)
- {
- syserr("Looping on ruleset %d, rule %d",
- ruleset, rwr-RewriteRules[ruleset]);
- mlp = mlist - 1; /* force rule failure */
- break;
- }
syserr("554 Infinite loop in ruleset %d, rule %d",
ruleset, ruleno);
if (tTd(21, 1))
while ((ap = *avp) != NULL || *rvp != NULL)
{
rp = *rvp;
-
if (tTd(21, 35))
{
printf("ADVANCE rp=");
xputs(ap);
printf("\n");
}
-
- if (extend_match)
- extend_match = FALSE;
- else
- {
- mlp->first = avp;
- mlp->last = mlp->flags == 0 || (mlp->flags & OP_NONZLEN) ?
- avp + 1 : avp;
- }
-
if (rp == NULL)
+ {
/* end-of-pattern before end-of-address */
goto backup;
-
- /* Premature end of address */
- if (ap == NULL && avp != mlp->last)
- goto backup;
-
- /*
- ** Simplest case - exact token comparison between
- ** pattern and address. Such a match is not saved
- ** in mlp.
- */
-
- if (rvp < mlp->source)
+ }
+ if (ap == NULL && (*rp & 0377) != MATCHZANY &&
+ (*rp & 0377) != MATCHZERO)
{
- if (ap == NULL || strcasecmp(ap, rp))
- goto backup;
- rvp++;
- avp++;
- continue;
+ /* end-of-input with patterns left */
+ goto backup;
}
-#ifdef MACVALUE
- /*
- ** This is special case handled. The match is exact,
- ** but might span zero or more address tokens. The
- ** result is saved in mlp.
- */
-
- if (*rp == MACVALUE)
+ switch (*rp & 0377)
{
- int len;
- rp = macvalue(rp[1], CurEnv);
+ register STAB *s;
+ char buf[MAXLINE];
- if (rp)
- while (*rp)
+ case MATCHCLASS:
+ /* match any phrase in a class */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ extendclass:
+ ap = *avp;
+ if (ap == NULL)
+ goto backup;
+ mlp->last = avp++;
+ cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
+ s = stab(buf, ST_CLASS, ST_FIND);
+ if (s == NULL || !bitnset(rp[1], s->s_class))
+ {
+ if (tTd(21, 36))
{
- if (*avp == NULL || strncasecmp(rp,*avp,len = strlen(*avp)))
- goto backup;
- rp += len;
- avp++;
+ printf("EXTEND rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
}
- mlp->last = avp;
- rvp++;
+ goto extendclass;
+ }
+ if (tTd(21, 36))
+ printf("CLMATCH\n");
mlp++;
- continue;
- }
-#endif /* MACVALUE */
+ break;
- /*
- ** All other matches are saved in mlp. Initially
- ** assume they match at the shortest possible length
- ** for this pattern. Variable patterns will be
- ** extended later as needed.
- */
+ case MATCHNCLASS:
+ /* match any token not in a class */
+ s = stab(ap, ST_CLASS, ST_FIND);
+ if (s != NULL && bitnset(rp[1], s->s_class))
+ goto backup;
- /* Fixed length first */
- if (!(mlp->flags & OP_VARLEN))
- {
- switch (*rp)
- {
- break;
- }
+ /* fall through */
- avp = mlp->last;
- rvp++;
+ case MATCHONE:
+ case MATCHANY:
+ /* match exactly one token */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ mlp->last = avp++;
+ mlp++;
+ break;
+
+ case MATCHZANY:
+ /* match zero or more tokens */
+ mlp->pattern = rvp;
+ mlp->first = avp;
+ mlp->last = avp - 1;
mlp++;
break;
case MATCHZERO:
/* match zero tokens */
- continue;
- }
+ break;
case MACRODEXPAND:
/*
/* match */
break;
- /*
- ** We now have a variable length item. It could
- ** be $+ or $* in which case no special checking
- ** is needed. But a class match such as $=x must
- ** be verified.
- **
- ** As a speedup, if a variable length item is
- ** followed by a plain character token, we initially
- ** extend the match to the first such token we find.
- ** If the required character token cannot be found,
- ** we fail the match at this point.
- */
-
- avp = mlp->last;
-
- /* If next token is char token */
- if (&rvp[1] < mlp[1].source)
- {
- while (*avp && strcasecmp(*avp, rvp[1]))
- avp++;
-
- /*
- ** If we can't find the proper ending token,
- ** leave avp point to NULL. This indicates
- ** we have run out of address tokens. It is
- ** pointless to advance the beginning of this
- ** match and retry.
- */
-
- if (*avp == NULL)
+ default:
+ /* must have exact match */
+ if (strcasecmp(rp, ap))
goto backup;
- mlp->last = avp;
- }
- else if (rvp[1] == NULL)
- /* next token is end of address */
- {
- while (*avp)
- avp++;
- mlp->last = avp;
- }
-
- if (mlp->flags & OP_CLASS)
- {
- register char *cp = tokbuf;
-
- avp = mlp->first;
- strcpy(cp, *avp);
avp++;
- for (;;)
- {
- while (avp < mlp->last)
- {
- while (*cp)
- cp++;
- strcpy(cp, *avp);
- avp++;
- }
- switch (*rp)
- {
- register STAB *s;
-
- case MATCHCLASS:
- s = stab(tokbuf, ST_CLASS, ST_FIND);
- if (s != NULL && bitnset(rp[1], s->s_class))
- goto have_match;
- break;
- }
-
- /*
- ** Class match initially failed.
- ** Extend the tentative match.
- ** Again, if followed by a character
- ** token, extend all the way to that
- ** token before checking.
- */
-
- if (*avp)
- {
- (mlp->last)++;
- if (&rvp[1] < mlp[1].source)
- {
- while (*(mlp->last) && strcasecmp(*(mlp->last), rvp[1]))
- (mlp->last)++;
- if (*(mlp->last) == NULL)
- avp = mlp->last;
- }
- }
- if (*avp == NULL)
- {
- /*
- ** We could not find the
- ** ending token. But we had
- ** found ending tokens before.
- ** A match is still plausible
- ** if the start of the
- ** tentative match is advanced.
- ** Hence we must not leave avp
- ** pointing to NULL.
- */
- avp = mlp->first;
- goto backup;
- }
- }
+ break;
}
- have_match:
+ /* successful match on this token */
rvp++;
- mlp++;
continue;
-backup:
- /* We failed to match. mlp marks point of failure */
-
- /*
- ** There is a special case when we have exhausted
- ** the address, but have not exhausted the pattern.
- ** Under normal circumstances we could consider the
- ** failure permanent, since extending the number of
- ** address tokens matched by a '$+' or a '$*' will
- ** only worsen the situation.
- **
- ** There is an exception, however. It is possible
- ** that we have matched a class token, say '$=x',
- ** with three or more tokens. Extending a '$+' say,
- ** which precedes the '$=x' will move the beginning
- ** of the '$=x' match to the right, but it might match
- ** a smaller number of tokens then, possibly
- ** correcting the mismatch.
- **
- ** Thus in this case we initially back up to the
- ** $=x which matches three or more tokens.
- */
-
- if (*avp == NULL)
+ backup:
+ /* match failed -- back up */
+ while (--mlp >= mlist)
{
rvp = mlp->pattern;
- while (--mlp > mlist)
+ rp = *rvp;
+ avp = mlp->last + 1;
+ ap = *avp;
+
+ if (tTd(21, 36))
{
- if ((mlp->flags & OP_CLASS) &&
- mlp->last > 2 + mlp->first)
- break;
+ printf("BACKUP rp=");
+ xputs(rp);
+ printf(", ap=");
+ xputs(ap);
+ printf("\n");
}
- }
- /*
- ** Now backup till we find a match with a pattern
- ** whose length is extendable, and extend that.
- */
-
- mlp--;
- while (mlp >= mlist && !(mlp->flags & OP_VARLEN))
- mlp--;
+ if (ap == NULL)
+ {
+ /* run off the end -- back up again */
+ continue;
+ }
+ if ((*rp & 0377) == MATCHANY ||
+ (*rp & 0377) == MATCHZANY)
+ {
+ /* extend binding and continue */
+ mlp->last = avp++;
+ rvp++;
+ mlp++;
+ break;
+ }
+ if ((*rp & 0377) == MATCHCLASS)
+ {
+ /* extend binding and try again */
+ mlp->last = avp;
+ goto extendclass;
+ }
+ }
- /* Total failure to match */
if (mlp < mlist)
- break;
-
- avp = ++(mlp->last);
- rvp = mlp->source;
-
- /*
- ** We have found a backup point. Normally we would
- ** increase the matched amount by one token, and
- ** continue from the next item in the pattern. But
- ** there are two special cases. If this is a
- ** class-type match (OP_CLASS), we must test the
- ** validity of the extended match. If this pattern
- ** item is directly followed by a character token, it
- ** is worth going back and locating the next such
- ** character token before we continue on.
- */
- if ((mlp->flags & OP_CLASS) || (&rvp[1] < mlp[1].source))
{
- avp = mlp->first;
- extend_match = TRUE;
- }
- else
- {
- mlp++;
- rvp++;
+ /* total failure to match */
+ break;
}
}
/*
- ** See if we successfully matched.
+ ** See if we successfully matched
*/
- if (mlp < mlist)
+ if (mlp < mlist || *rvp != NULL)
{
if (tTd(21, 10))
printf("----- rule fails\n");
rwr = rwr->r_next;
ruleno++;
loopcount = 0;
- nmatches = 0;
- continue;
- }
-
- if (nmatches++ > 200)
- {
- syserr("Loop in ruleset %d, rule %d (too many matches)",
- ruleset, rwr - RewriteRules[ruleset]);
- rwr = rwr->r_next;
- nmatches = 0;
continue;
}
if (tTd(21, 12))
{
printf("-----rule matches:");
- printcav(rvp);
+ printav(rvp);
}
rp = *rvp;
rwr = rwr->r_next;
ruleno++;
loopcount = 0;
- nmatches = 0;
}
else if ((*rp & 0377) == CANONHOST)
{
rwr = NULL;
/* substitute */
- dolookup = FALSE;
for (avp = npvp; *rvp != NULL; rvp++)
{
register struct match *m;
register char **pp;
rp = *rvp;
-
- /* check to see if we should do a lookup */
- if (*rp == MATCHLOOKUP)
- dolookup = TRUE;
-
- /* see if there is substitution here */
- if (*rp == MATCHREPL && rp[1] >= '1' && rp[1] <= '9')
+ if ((*rp & 0377) == MATCHREPL)
{
/* substitute from LHS */
m = &mlist[rp[1] - '1'];
if (m < mlist || m >= mlp)
{
- toolong:
- syserr("rewrite: ruleset %d: replacement #%c out of bounds",
+ syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
ruleset, rp[1]);
return EX_CONFIG;
}
{
printf("$%c:", rp[1]);
pp = m->first;
- while (pp < m->last)
+ while (pp <= m->last)
{
printf(" %x=\"", *pp);
(void) fflush(stdout);
printf("\n");
}
pp = m->first;
- while (pp < m->last)
+ while (pp <= m->last)
{
if (avp >= &npvp[MAXATOM])
- goto toolong;
+ {
+ syserr("554 rewrite: expansion too long");
+ return EX_DATAERR;
+ }
*avp++ = *pp++;
}
}
{
/* vanilla replacement */
if (avp >= &npvp[MAXATOM])
- goto toolong;
-#ifdef MACVALUE
- if (*rp == MACVALUE)
{
- char *p = macvalue(rp[1], CurEnv);
-
- if (tTd(21, 2))
- printf("expanding runtime macro '%c' to \"%s\"\n",
- rp[1], p ? p : "(null)");
- if (p)
- *avp++ = p;
+ toolong:
+ syserr("554 rewrite: expansion too long");
+ return EX_DATAERR;
}
- else
-#endif /* MACVALUE */
+ if ((*rp & 0377) != MACRODEXPAND)
*avp++ = rp;
+ else
+ {
+ *avp = macvalue(rp[1], e);
+ if (tTd(21, 2))
+ printf("rewrite: RHS $&%c => \"%s\"\n",
+ rp[1],
+ *avp == NULL ? "(NULL)" : *avp);
+ if (*avp != NULL)
+ avp++;
+ }
}
}
*avp++ = NULL;
for (rvp = npvp; *rvp != NULL; rvp++)
{
- char **hbrvp, **ubrvp;
+ char **hbrvp;
char **xpvp;
int trsize;
char *replac;
char **key_rvp;
char **arg_rvp;
char **default_rvp;
- char hbuf[MAXNAME + 1], ubuf[MAXNAME + 1];
+ char buf[MAXNAME + 1];
char *pvpb1[MAXATOM + 1];
char *argvect[10];
char pvpbuf[PSBUFSIZE];
char *nullpvp[1];
- bool match, defaultpart;
- char begintype;
- char db = '\0';
if ((**rvp & 0377) != HOSTBEGIN &&
(**rvp & 0377) != LOOKUPBEGIN)
** This could be optimized fairly easily.
*/
- begintype = **rvp;
hbrvp = rvp;
- ubrvp = NULL;
if ((**rvp & 0377) == HOSTBEGIN)
{
endtoken = HOSTEND;
trsize = (int) (avp - rvp + 1) * sizeof *rvp;
bcopy((char *) rvp, (char *) pvpb1, trsize);
- /* append it to the token list */
- for (avp = hbrvp; *xpvp != NULL; xpvp++)
- {
- *avp++ = newstr(*xpvp);
- if (avp >= &npvp[MAXATOM])
- goto toolong;
- }
+ /* look it up */
+ cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
+ argvect[0] = buf;
+ if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
+ {
+ auto int stat = EX_OK;
+
+ /* XXX should try to auto-open the map here */
+
+ if (tTd(60, 1))
+ printf("map_lookup(%s, %s) => ",
+ mapname, buf);
+ replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
+ buf, argvect, &stat);
+ if (tTd(60, 1))
+ printf("%s (%d)\n",
+ replac ? replac : "NOT FOUND",
+ stat);
+
+ /* should recover if stat == EX_TEMPFAIL */
+ if (stat == EX_TEMPFAIL)
+ rstat = stat;
}
else
- avp = hbrvp;
+ replac = NULL;
- /* restore the old trailing information */
- rvp = avp - 1;
- for (xpvp = pvpb1; *xpvp != NULL; xpvp++)
+ /* if no replacement, use default */
+ if (replac == NULL && default_rvp != NULL)
+ {
+ /* create the default */
+ cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
+ replac = buf;
+ }
+
+ if (replac == NULL)
+ {
+ xpvp = key_rvp;
+ }
+ else if (*replac == '\0')
{
- if (defaultpart && **xpvp == HOSTEND)
+ /* null replacement */
+ nullpvp[0] = NULL;
+ xpvp = nullpvp;
+ }
+ else
+ {
+ /* scan the new replacement */
+ xpvp = prescan(replac, '\0', pvpbuf,
+ sizeof pvpbuf, NULL);
+ if (xpvp == NULL)
{
- defaultpart = FALSE;
- rvp = avp - 1;
+ /* prescan already printed error */
+ return EX_DATAERR;
}
- else if (!defaultpart || !match)
- *avp++ = *xpvp;
+ }
+
+ /* append it to the token list */
+ for (avp = hbrvp; *xpvp != NULL; xpvp++)
+ {
+ *avp++ = newstr(*xpvp);
if (avp >= &npvp[MAXATOM])
goto toolong;
}
- *avp++ = NULL;
- /*break;*/
+ /* restore the old trailing information */
+ for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
+ if (avp >= &npvp[MAXATOM])
+ goto toolong;
+
+ break;
}
/*
** Check for subroutine calls.
- ** Then copy vector back into original space.
*/
- callsubr(npvp);
-
- for (avp = npvp; *avp++ != NULL;);
- subr = atoi(*++rvp);
- rvp++;
+ if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
+ {
+ int stat;
+ if (npvp[1] == NULL)
+ {
+ syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
+ ruleset, ruleno);
+ *pvp = NULL;
+ }
+ else
+ {
+ bcopy((char *) &npvp[2], (char *) pvp,
+ (int) (avp - npvp - 2) * sizeof *avp);
+ if (tTd(21, 3))
+ printf("-----callsubr %s\n", npvp[1]);
+ stat = rewrite(pvp, atoi(npvp[1]), reclevel, e);
+ if (rstat == EX_OK || stat == EX_TEMPFAIL)
+ rstat = stat;
+ if (*pvp != NULL && (**pvp & 0377) == CANONNET)
+ rwr = NULL;
+ }
+ }
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);
+ bcopy((char *) npvp, (char *) pvp,
+ (int) (avp - npvp) * sizeof *avp);
}
-
- /*
- ** Done with rewriting this pass.
- */
-
if (tTd(21, 4))
{
printf("rewritten as:");
- printcav(pvp);
+ printav(pvp);
}
}
if (OpMode == MD_TEST || tTd(21, 2))
{
printf("rewrite: ruleset %2d returns:", ruleset);
- printcav(pvp);
+ printav(pvp);
}
return rstat;
}
\f/*
-** CALLSUBR -- call subroutines in rewrite vector
-**
-** Parameters:
-** pvp -- pointer to token vector.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** pvp is modified.
-*/
-
-static void
-callsubr(pvp)
- char **pvp;
-{
- char **rvp;
- int subr;
-
- for (; *pvp != NULL; pvp++)
- if (**pvp == CALLSUBR && pvp[1] != NULL && isdigit(pvp[1][0]))
- {
- subr = atoi(pvp[1]);
-
- if (tTd(21, 3))
- printf("-----callsubr %d\n", subr);
-
- /*
- ** Take care of possible inner calls.
- */
- callsubr(pvp+2);
-
- /*
- ** Move vector up over calling opcode.
- */
- for (rvp = pvp+2; *rvp != NULL; rvp++)
- rvp[-2] = rvp[0];
- rvp[-2] = NULL;
-
- /*
- ** Call inferior ruleset.
- */
- _rewrite(pvp, subr);
-
- break;
- }
-}
-\f/*
** BUILDADDR -- build address from token vector.
**
** Parameters:
NULL, EX_UNAVAILABLE,
};
-static ADDRESS *
+ADDRESS *
buildaddr(tv, a, flags, e)
register char **tv;
register ADDRESS *a;
if (a == NULL)
a = (ADDRESS *) xalloc(sizeof *a);
- clear((char *) a, sizeof *a);
+ bzero((char *) a, sizeof *a);
/* figure out what net/mailer to use */
- if (*tv == NULL || **tv != CANONNET)
+ if (*tv == NULL || (**tv & 0377) != CANONNET)
{
syserr("554 buildaddr: no net");
badaddr:
}
else
setstat(EX_UNAVAILABLE);
- buf[0] = '\0';
- for (; (*tv != NULL) && (**tv != CANONUSER); tv++)
- {
- if (buf[0] != '\0')
- (void) strcat(buf, " ");
- (void) strcat(buf, *tv);
- }
if ((**tv & 0377) != CANONUSER)
syserr("554 buildaddr: error: no user");
cataddr(++tv, NULL, buf, sizeof buf, ' ');
stripquotes(buf);
-#ifdef LOG
- if (LogLevel > 8)
- syslog (LOG_DEBUG, "%s: Trace: $#ERROR $: %s",
- CurEnv->e_id, buf);
-#endif /* LOG */
if (isascii(buf[0]) && isdigit(buf[0]) &&
isascii(buf[1]) && isdigit(buf[1]) &&
isascii(buf[2]) && isdigit(buf[2]) &&
a->q_mailer = m;
/* figure out what host (if any) */
- if (**++tv != CANONHOST)
- {
- a->q_host = NULL;
- }
- else
+ tv++;
+ if ((**tv & 0377) == CANONHOST)
{
- else
- a->q_host = NULL;
+ bp = buf;
+ spaceleft = sizeof buf - 1;
+ while (*++tv != NULL && (**tv & 0377) != CANONUSER)
+ {
+ int i = strlen(*tv);
+
+ if (i > spaceleft)
+ {
+ /* out of space for this address */
+ if (spaceleft >= 0)
+ syserr("554 buildaddr: host too long (%.40s...)",
+ buf);
+ i = spaceleft;
+ spaceleft = 0;
+ }
+ if (i <= 0)
+ continue;
+ bcopy(*tv, bp, i);
+ bp += i;
+ spaceleft -= i;
+ }
+ *bp = '\0';
+ a->q_host = newstr(buf);
}
else
{
- while (*++tv != NULL && **tv != CANONUSER)
- (void) strcat(buf, *tv);
- a->q_host = newstr(buf);
+ if (!bitnset(M_LOCALMAILER, m->m_flags))
+ {
+ syserr("554 buildaddr: no host");
+ goto badaddr;
+ }
+ a->q_host = NULL;
}
/* figure out the user */
a->q_flags |= QNOTREMOTE;
}
- if (m->m_r_rwset > 0)
- rewrite(tv, m->m_r_rwset);
+ /* rewrite according recipient mailer rewriting rules */
+ define('h', a->q_host, e);
+ if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
+ {
+ /* sender addresses done later */
+ (void) rewrite(tv, 2, 0, e);
+ if (m->m_re_rwset > 0)
+ (void) rewrite(tv, m->m_re_rwset, 0, e);
+ }
(void) rewrite(tv, 4, 0, e);
/* save the result for the command line/RCPT argument */
** Destroys buf.
*/
-void
cataddr(pvp, evp, buf, sz, spacesub)
char **pvp;
char **evp;
char spacesub;
{
bool oatomtok = FALSE;
- bool natomtok;
+ bool natomtok = FALSE;
register int i;
register char *p;
return (FALSE);
/* if the user isn't the same, we can drop out */
- if (strcasecmp(a->q_user, b->q_user))
+ if (strcmp(a->q_user, b->q_user) != 0)
return (FALSE);
/* if we have good uids for both but they differ, these are different */
/* only one is a null pointer */
return (FALSE);
}
- if (strcasecmp(a->q_host, b->q_host))
+ if (strcmp(a->q_host, b->q_host) != 0)
return (FALSE);
return (TRUE);
** none.
*/
-void
printaddr(a, follow)
register ADDRESS *a;
bool follow;
register MAILER *m;
MAILER pseudomailer;
- static int indent;
- register int i;
-
while (a != NULL)
{
first = FALSE;
- for (i = indent; i > 0; i--)
- printf("\t");
printf("%x=", a);
(void) fflush(stdout);
m->m_name = "NULL";
}
- for (i = indent; i > 0; i--)
- printf("\t");
- printf("\tnext=%x, flags=%o, rmailer %d, alias=%x, sibling=%x, child=%x\n",
- a->q_next, a->q_flags, a->q_rmailer, a->q_alias,
- a->q_sibling, a->q_child);
-
- /* follow the chain if appropriate */
+ printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n",
+ a->q_paddr, m->m_mno, m->m_name,
+ a->q_host, a->q_user,
+ a->q_ruser ? a->q_ruser : "<null>");
+ printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n",
+ a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid);
+ printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
+ a->q_owner == NULL ? "(none)" : a->q_owner,
+ a->q_home == NULL ? "(none)" : a->q_home,
+ a->q_fullname == NULL ? "(none)" : a->q_fullname);
+
if (!follow)
return;
-
- indent++;
- printaddr(a->q_child, TRUE);
- indent--;
- a = a->q_sibling;
+ a = a->q_next;
}
if (first)
printf("[NULL]\n");
char *
remotename(name, m, flags, pstat, e)
char *name;
- MAILER *m;
+ struct mailer *m;
int flags;
int *pstat;
register ENVELOPE *e;
static char buf[MAXNAME];
char lbuf[MAXNAME];
char pvpbuf[PSBUFSIZE];
+ extern char *crackaddr();
if (tTd(12, 1))
printf("remotename(%s)\n", name);
/* don't do anything if we are tagging it as special */
- if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0)
+ if (bitset(RF_SENDERADDR, flags))
+ rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
+ : m->m_se_rwset;
+ else
+ rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
+ : m->m_re_rwset;
+ if (rwset < 0)
return (name);
/*
/*
** Do more specific rewriting.
- ** Rewrite using ruleset 1 or 2 for envelope addresses and
- ** 5 or 6 for header addresses depending on whether this
- ** is a sender address or not.
+ ** Rewrite using ruleset 1 or 2 depending on whether this is
+ ** a sender address or not.
** Then run it through any receiving-mailer-specific rulesets.
*/
+ if (bitset(RF_SENDERADDR, flags))
+ {
+ if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ }
else
{
+ if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
+ *pstat = EX_TEMPFAIL;
+ }
if (rwset > 0)
{
if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
return (buf);
}
\f/*
-** UURELATIVIZE -- Make an address !-relative to recipient/sender nodes
-**
-** Parameters:
-** from -- the sending node (usually "$k" or "$w")
-** to -- the receiving node (usually "$h")
-** pvp -- address vector
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** The pvp is rewritten to be relative the "to" node
-** wrt the "from" node. In other words, if the pvp
-** is headed by "to!" that part is stripped; otherwise
-** "from!" is prepended. Exception: "to!user" addresses
-** with no '!'s in the user part are sent as is.
-**
-** Bugs:
-** The pvp may overflow, but we don't catch it.
-*/
-
-static void
-uurelativize(from, to, pvp)
- const char *from, *to;
- char **pvp;
-{
- register char **pxp = pvp;
- char expfrom[MAXNAME], expto[MAXNAME];
-
- expand(from, expfrom, &expfrom[sizeof expfrom - 1], CurEnv);
- expand(to, expto, &expto[sizeof expto - 1], CurEnv);
-
- /*
- * supposing that we've got something, should
- * we add "from!" or remove "to!"?
- */
- if (pvp[0] != NULL)
- if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 ||
- /*strcasecmp?*/ strcmp(pvp[0], expto) != 0)
- {
- /* either local name, no UUCP address, */
- /* or not to "to!" ==> prepend address with "from!" */
-
- /* already there? */
- if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 ||
- /*strcasecmp?*/ strcmp(pvp[0], expfrom) != 0)
- {
-
- /* no, put it there */
- while (*pxp != NULL)
- pxp++;
- do
- pxp[2] = *pxp;
- while (pxp-- != pvp);
- pvp[0] = newstr(expfrom);
- pvp[1] = "!";
- }
- }
- else
- {
- /* address is to "to!" -- remove if not "to!user" */
- for (pxp = &pvp[2];
- *pxp != NULL && strcmp(*pxp, "!") != 0; pxp++)
- ;
- if (*pxp != NULL)
- for (pxp = pvp; *pxp != NULL; pxp++)
- *pxp = pxp[2];
- }
-}
-\f/*
** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
**
** Parameters: