blob: 3f30d4f3aa0d0e0eee788df78e07854e961905aa [file] [log] [blame]
#include "common.h"
#include "send.h"
extern int debug;
/*
* Routines for dealing with the rewrite rules.
*/
/* globals */
typedef struct rule rule;
#define NSUBEXP 10
struct rule {
String *matchre; /* address match */
String *repl1; /* first replacement String */
String *repl2; /* second replacement String */
d_status type; /* type of rule */
Reprog *program;
Resub subexp[NSUBEXP];
rule *next;
};
static rule *rulep;
static rule *rlastp;
/* predeclared */
static String *substitute(String *, Resub *, message *);
static rule *findrule(String *, int);
/*
* Get the next token from `line'. The symbol `\l' is replaced by
* the name of the local system.
*/
extern String *
rule_parse(String *line, char *system, int *backl)
{
String *token;
String *expanded;
char *cp;
token = s_parse(line, 0);
if(token == 0)
return(token);
if(strchr(s_to_c(token), '\\')==0)
return(token);
expanded = s_new();
for(cp = s_to_c(token); *cp; cp++) {
if(*cp == '\\') switch(*++cp) {
case 'l':
s_append(expanded, system);
*backl = 1;
break;
case '\\':
s_putc(expanded, '\\');
break;
default:
s_putc(expanded, '\\');
s_putc(expanded, *cp);
break;
} else
s_putc(expanded, *cp);
}
s_free(token);
s_terminate(expanded);
return(expanded);
}
static int
getrule(String *line, String *type, char *system)
{
rule *rp;
String *re;
int backl;
backl = 0;
/* get a rule */
re = rule_parse(s_restart(line), system, &backl);
if(re == 0)
return 0;
rp = (rule *)malloc(sizeof(rule));
if(rp == 0) {
perror("getrules:");
exit(1);
}
rp->next = 0;
s_tolower(re);
rp->matchre = s_new();
s_append(rp->matchre, s_to_c(re));
s_restart(rp->matchre);
s_free(re);
s_parse(line, s_restart(type));
rp->repl1 = rule_parse(line, system, &backl);
rp->repl2 = rule_parse(line, system, &backl);
rp->program = 0;
if(strcmp(s_to_c(type), "|") == 0)
rp->type = d_pipe;
else if(strcmp(s_to_c(type), ">>") == 0)
rp->type = d_cat;
else if(strcmp(s_to_c(type), "alias") == 0)
rp->type = d_alias;
else if(strcmp(s_to_c(type), "translate") == 0)
rp->type = d_translate;
else if(strcmp(s_to_c(type), "auth") == 0)
rp->type = d_auth;
else {
s_free(rp->matchre);
s_free(rp->repl1);
s_free(rp->repl2);
free((char *)rp);
fprint(2,"illegal rewrite rule: %s\n", s_to_c(line));
return 0;
}
if(rulep == 0)
rulep = rlastp = rp;
else
rlastp = rlastp->next = rp;
return backl;
}
/*
* rules are of the form:
* <reg exp> <String> <repl exp> [<repl exp>]
*/
extern int
getrules(void)
{
Biobuf *rfp;
String *line;
String *type;
String *file;
file = abspath("rewrite", UPASLIB, (String *)0);
rfp = sysopen(s_to_c(file), "r", 0);
if(rfp == 0) {
rulep = 0;
return -1;
}
rlastp = 0;
line = s_new();
type = s_new();
while(s_getline(rfp, s_restart(line)))
if(getrule(line, type, thissys) && altthissys)
getrule(s_restart(line), type, altthissys);
s_free(type);
s_free(line);
s_free(file);
sysclose(rfp);
return 0;
}
/* look up a matching rule */
static rule *
findrule(String *addrp, int authorized)
{
rule *rp;
static rule defaultrule;
if(rulep == 0)
return &defaultrule;
for (rp = rulep; rp != 0; rp = rp->next) {
if(rp->type==d_auth && authorized)
continue;
if(rp->program == 0)
rp->program = regcomp(rp->matchre->base);
if(rp->program == 0)
continue;
memset(rp->subexp, 0, sizeof(rp->subexp));
if(debug)
fprint(2, "matching %s aginst %s\n", s_to_c(addrp), rp->matchre->base);
if(regexec(rp->program, s_to_c(addrp), rp->subexp, NSUBEXP))
if(s_to_c(addrp) == rp->subexp[0].s.sp)
if((s_to_c(addrp) + strlen(s_to_c(addrp))) == rp->subexp[0].e.ep)
return rp;
}
return 0;
}
/* Transforms the address into a command.
* Returns: -1 ifaddress not matched by reules
* 0 ifaddress matched and ok to forward
* 1 ifaddress matched and not ok to forward
*/
extern int
rewrite(dest *dp, message *mp)
{
rule *rp; /* rewriting rule */
String *lower; /* lower case version of destination */
/*
* Rewrite the address. Matching is case insensitive.
*/
lower = s_clone(dp->addr);
s_tolower(s_restart(lower));
rp = findrule(lower, dp->authorized);
if(rp == 0){
s_free(lower);
return -1;
}
strcpy(s_to_c(lower), s_to_c(dp->addr));
dp->repl1 = substitute(rp->repl1, rp->subexp, mp);
dp->repl2 = substitute(rp->repl2, rp->subexp, mp);
dp->status = rp->type;
if(debug){
fprint(2, "\t->");
if(dp->repl1)
fprint(2, "%s", s_to_c(dp->repl1));
if(dp->repl2)
fprint(2, "%s", s_to_c(dp->repl2));
fprint(2, "\n");
}
s_free(lower);
return 0;
}
/* stolen from rc/lex.c */
static int
idchr(int c)
{
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
}
static char*
getrcvar(char* p, char** rv)
{
char* p0;
char buf[128];
char* bufe;
*rv = 0;
p0=p;
bufe=buf+sizeof buf-1;
while(p<bufe && idchr(*p))
p++;
memcpy(buf, p0, p-p0);
buf[p-p0]=0;
*rv = getenv(buf);
if (debug)
fprint(2, "varsubst: %s → %s\n", buf, *rv);
return p;
}
static String *
substitute(String *source, Resub *subexp, message *mp)
{
int i;
char *s;
char *sp;
String *stp;
if(source == 0)
return 0;
sp = s_to_c(source);
/* someplace to put it */
stp = s_new();
/* do the substitution */
while (*sp != '\0') {
if(*sp == '\\') {
switch (*++sp) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i = *sp-'0';
if(subexp[i].s.sp != 0)
for (s = subexp[i].s.sp;
s < subexp[i].e.ep;
s++)
s_putc(stp, *s);
break;
case '\\':
s_putc(stp, '\\');
break;
case '\0':
sp--;
break;
case 's':
for(s = s_to_c(mp->replyaddr); *s; s++)
s_putc(stp, *s);
break;
case 'p':
if(mp->bulk)
s = "bulk";
else
s = "normal";
for(;*s; s++)
s_putc(stp, *s);
break;
default:
s_putc(stp, *sp);
break;
}
} else if(*sp == '&') {
if(subexp[0].s.sp != 0)
for (s = subexp[0].s.sp;
s < subexp[0].e.ep; s++)
s_putc(stp, *s);
} else if(*sp == '$') {
sp = getrcvar(sp+1, &s);
s_append(stp, s);
free(s);
sp--; /* counter sp++ below */
} else
s_putc(stp, *sp);
sp++;
}
s_terminate(stp);
return s_restart(stp);
}
extern void
regerror(char* s)
{
fprint(2, "rewrite: %s\n", s);
}
extern void
dumprules(void)
{
rule *rp;
for (rp = rulep; rp != 0; rp = rp->next) {
fprint(2, "'%s'", rp->matchre->base);
switch (rp->type) {
case d_pipe:
fprint(2, " |");
break;
case d_cat:
fprint(2, " >>");
break;
case d_alias:
fprint(2, " alias");
break;
case d_translate:
fprint(2, " translate");
break;
default:
fprint(2, " UNKNOWN");
break;
}
fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"...");
fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"...");
}
}