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