| #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:"..."); |
| } |
| } |
| |