1 #include "common.h" 2 #include "send.h" 3 4 extern int debug; 5 6 /* configuration */ 7 #define RULEBiobuf "lib/rewrite" 8 9 /* 10 * Routines for dealing with the rewrite rules. 11 */ 12 13 /* globals */ 14 typedef struct rule rule; 15 16 #define NSUBEXP 10 17 struct rule { 18 String *matchre; /* address match */ 19 String *repl1; /* first replacement String */ 20 String *repl2; /* second replacement String */ 21 d_status type; /* type of rule */ 22 Reprog *program; 23 Resub subexp[NSUBEXP]; 24 rule *next; 25 }; 26 static rule *rulep; 27 static rule *rlastp; 28 29 /* predeclared */ 30 static String *substitute(String *, Resub *, char *); 31 static rule *findrule(String *, int); 32 33 34 /* 35 * Get the next token from `line'. The symbol `\l' is replaced by 36 * the name of the local system. 37 */ 38 extern String * 39 rule_parse(String *line, char *system, int *backl) 40 { 41 String *token; 42 String *expanded; 43 char *cp; 44 45 token = s_parse(line, 0); 46 if(token == 0) 47 return(token); 48 if (strchr(s_to_c(token), '\\')==0) 49 return(token); 50 expanded = s_new(); 51 for(cp = s_to_c(token); *cp; cp++) { 52 if(*cp == '\\') switch(*++cp) { 53 case 'l': 54 s_append(expanded, system); 55 *backl = 1; 56 break; 57 case '\\': 58 s_putc(expanded, '\\'); 59 break; 60 default: 61 s_putc(expanded, '\\'); 62 s_putc(expanded, *cp); 63 break; 64 } else 65 s_putc(expanded, *cp); 66 } 67 s_free(token); 68 s_terminate(expanded); 69 return(expanded); 70 } 71 72 static int 73 getrule(String *line, String *type, char *system) 74 { 75 rule *rp; 76 String *re; 77 int backl; 78 79 backl = 0; 80 81 /* get a rule */ 82 re = rule_parse(s_restart(line), system, &backl); 83 if(re == 0) 84 return 0; 85 rp = (rule *)malloc(sizeof(rule)); 86 if (rp == 0) { 87 perror("getrules:"); 88 exit(1); 89 } 90 rp->next = 0; 91 s_tolower(re); 92 rp->matchre = s_new(); 93 if(*s_to_c(re)!='^') 94 s_append(rp->matchre, "^"); 95 s_append(rp->matchre, s_to_c(re)); 96 s_append(rp->matchre, "$"); 97 USE(s_restart(rp->matchre)); 98 s_free(re); 99 s_parse(line, s_restart(type)); 100 rp->repl1 = rule_parse(line, system, &backl); 101 rp->repl2 = rule_parse(line, system, &backl); 102 rp->program = 0; 103 if (strcmp(s_to_c(type), "|") == 0) 104 rp->type = d_pipe; 105 else if (strcmp(s_to_c(type), ">>") == 0) 106 rp->type = d_cat; 107 else if (strcmp(s_to_c(type), "alias") == 0) 108 rp->type = d_alias; 109 else if (strcmp(s_to_c(type), "translate") == 0) 110 rp->type = d_translate; 111 else if (strcmp(s_to_c(type), "auth") == 0) 112 rp->type = d_auth; 113 else { 114 s_free(rp->matchre); 115 s_free(rp->repl1); 116 s_free(rp->repl2); 117 free((char *)rp); 118 fprint(2,"illegal rewrite rule: %s\n", s_to_c(line)); 119 return 0; 120 } 121 if (rulep == 0) 122 rulep = rlastp = rp; 123 else 124 rlastp = rlastp->next = rp; 125 return backl; 126 } 127 128 /* 129 * rules are of the form: 130 * <reg exp> <String> <repl exp> [<repl exp>] 131 */ 132 extern int 133 getrules(void) 134 { 135 Biobuf *rfp; 136 String *line; 137 String *type; 138 String *file; 139 140 file = abspath(RULEBiobuf, MAILROOT, (String *)0); 141 rfp = sysopen(s_to_c(file), "r", 0); 142 if (rfp == 0) { 143 rulep = 0; 144 return -1; 145 } 146 rlastp = 0; 147 line = s_new(); 148 type = s_new(); 149 while(s_getline(rfp, s_restart(line))) 150 if(getrule(line, type, thissys) && altthissys) 151 getrule(s_restart(line), type, altthissys); 152 s_free(type); 153 s_free(line); 154 s_free(file); 155 sysclose(rfp); 156 return 0; 157 } 158 159 /* look up a matching rule */ 160 static rule * 161 findrule(String *addrp, int authorized) 162 { 163 rule *rp; 164 static rule defaultrule; 165 166 if (rulep == 0) 167 return &defaultrule; 168 for (rp = rulep; rp != 0; rp = rp->next) { 169 if (rp->type==d_auth && authorized) 170 continue; 171 if (rp->program == 0) 172 rp->program = regcomp(rp->matchre->base); 173 if (rp->program == 0) 174 continue; 175 memset(rp->subexp, 0, sizeof(rp->subexp)); 176 if(debug) 177 print("trying %s\n", rp->matchre->base); 178 if (regexec(rp->program, s_to_c(addrp), rp->subexp, NSUBEXP)) 179 return rp; 180 } 181 return 0; 182 } 183 184 /* Transforms the address into a command. 185 * Returns: -1 if address not matched by reules 186 * 0 if address matched and ok to forward 187 * 1 if address matched and not ok to forward 188 */ 189 extern int 190 rewrite(dest *dp, char *s) 191 { 192 rule *rp; /* rewriting rule */ 193 String *lower; /* lower case version of destination */ 194 195 /* 196 * Rewrite the address. Matching is case insensitive. 197 */ 198 lower = s_clone(s_restart(dp->addr)); 199 s_tolower(s_restart(lower)); 200 rp = findrule(lower, dp->authorized); 201 if (rp == 0) 202 return -1; 203 strcpy(s_to_c(lower), s_to_c(dp->addr)); 204 dp->repl1 = substitute(rp->repl1, rp->subexp, s); 205 dp->repl2 = substitute(rp->repl2, rp->subexp, s); 206 dp->status = rp->type; 207 if(debug){ 208 print("\t->"); 209 if(dp->repl1) 210 print("%s", s_to_c(dp->repl1)); 211 if(dp->repl2) 212 print("%s", s_to_c(dp->repl2)); 213 print("\n"); 214 } 215 return 0; 216 } 217 218 static String * 219 substitute(String *source, Resub *subexp, char *s) 220 { 221 register char *sp; 222 register char *ssp; 223 register String *stp; 224 register int i; 225 226 if (source == 0) 227 return 0; 228 sp = s_to_c(source); 229 230 /* someplace to put it */ 231 stp = s_new(); 232 233 /* do the substitution */ 234 while (*sp != '\0') { 235 if (*sp == '\\') { 236 switch (*++sp) { 237 case '0': case '1': case '2': case '3': case '4': 238 case '5': case '6': case '7': case '8': case '9': 239 i = *sp-'0'; 240 if (subexp[i].sp != 0) 241 for (ssp = subexp[i].sp; 242 ssp < subexp[i].ep; 243 ssp++) 244 s_putc(stp, *ssp); 245 break; 246 case '\\': 247 s_putc(stp, '\\'); 248 break; 249 case '\0': 250 sp--; 251 break; 252 case 's': 253 for(ssp = s; *ssp; ssp++) 254 s_putc(stp, *ssp); 255 break; 256 default: 257 s_putc(stp, *sp); 258 break; 259 } 260 } else if (*sp == '&') { 261 if (subexp[0].sp != 0) 262 for (ssp = subexp[0].sp; 263 ssp < subexp[0].ep; ssp++) 264 s_putc(stp, *ssp); 265 } else 266 s_putc(stp, *sp); 267 sp++; 268 } 269 s_terminate(stp); 270 271 return s_restart(stp); 272 } 273 274 extern void 275 regerror(char* s) 276 { 277 fprint(2, "rewrite: %s\n", s); 278 } 279 280 extern void 281 dumprules(void) 282 { 283 rule *rp; 284 285 for (rp = rulep; rp != 0; rp = rp->next) { 286 fprint(2, "'%s'", rp->matchre->base); 287 switch (rp->type) { 288 case d_pipe: 289 fprint(2, " |"); 290 break; 291 case d_cat: 292 fprint(2, " >>"); 293 break; 294 case d_alias: 295 fprint(2, " alias"); 296 break; 297 case d_translate: 298 fprint(2, " translate"); 299 break; 300 default: 301 fprint(2, " UNKNOWN"); 302 break; 303 } 304 fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"..."); 305 fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"..."); 306 } 307 } 308 309