#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: * [] */ 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:"..."); } }