/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "common.h"#include "send.h" extern int debug; /* * Routines for dealing with the rewrite rules. */ /* globals */typedef struct rule rule; #define NSUBEXP 10struct 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 intgetrule(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 intgetrules(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 against %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].sp) if((s_to_c(addrp) + strlen(s_to_c(addrp))) == rp->subexp[0].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 intrewrite(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;} 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].sp != 0) for (s = subexp[i].sp; s < subexp[i].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].sp != 0) for (s = subexp[0].sp; s < subexp[0].ep; s++) s_putc(stp, *s); } else s_putc(stp, *sp); sp++; } s_terminate(stp); return s_restart(stp);} extern voidregerror(char* s){ fprint(2, "rewrite: %s\n", s); /* make sure the message is seen locally */ syslog(0, "mail", "regexp error in rewrite: %s", s);} extern voiddumprules(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:"..."); }}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#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 against %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].sp)
if((s_to_c(addrp) + strlen(s_to_c(addrp))) == rp->subexp[0].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;
}
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].sp != 0)
for (s = subexp[i].sp;
s < subexp[i].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].sp != 0)
for (s = subexp[0].sp;
s < subexp[0].ep; s++)
s_putc(stp, *s);
} else
s_putc(stp, *sp);
sp++;
}
s_terminate(stp);
return s_restart(stp);
}
extern void
regerror(char* s)
{
fprint(2, "rewrite: %s\n", s);
/* make sure the message is seen locally */
syslog(0, "mail", "regexp error in rewrite: %s", 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:"...");
}
}