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 against %s\n", s_to_c(addrp), 172 rp->matchre->base); 173 if(regexec(rp->program, s_to_c(addrp), rp->subexp, NSUBEXP)) 174 if(s_to_c(addrp) == rp->subexp[0].sp) 175 if((s_to_c(addrp) + strlen(s_to_c(addrp))) == rp->subexp[0].ep) 176 return rp; 177 } 178 return 0; 179 } 180 181 /* Transforms the address into a command. 182 * Returns: -1 ifaddress not matched by reules 183 * 0 ifaddress matched and ok to forward 184 * 1 ifaddress matched and not ok to forward 185 */ 186 extern int 187 rewrite(dest *dp, message *mp) 188 { 189 rule *rp; /* rewriting rule */ 190 String *lower; /* lower case version of destination */ 191 192 /* 193 * Rewrite the address. Matching is case insensitive. 194 */ 195 lower = s_clone(dp->addr); 196 s_tolower(s_restart(lower)); 197 rp = findrule(lower, dp->authorized); 198 if(rp == 0){ 199 s_free(lower); 200 return -1; 201 } 202 strcpy(s_to_c(lower), s_to_c(dp->addr)); 203 dp->repl1 = substitute(rp->repl1, rp->subexp, mp); 204 dp->repl2 = substitute(rp->repl2, rp->subexp, mp); 205 dp->status = rp->type; 206 if(debug){ 207 fprint(2, "\t->"); 208 if(dp->repl1) 209 fprint(2, "%s", s_to_c(dp->repl1)); 210 if(dp->repl2) 211 fprint(2, "%s", s_to_c(dp->repl2)); 212 fprint(2, "\n"); 213 } 214 s_free(lower); 215 return 0; 216 } 217 218 static String * 219 substitute(String *source, Resub *subexp, message *mp) 220 { 221 int i; 222 char *s; 223 char *sp; 224 String *stp; 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 (s = subexp[i].sp; 242 s < subexp[i].ep; 243 s++) 244 s_putc(stp, *s); 245 break; 246 case '\\': 247 s_putc(stp, '\\'); 248 break; 249 case '\0': 250 sp--; 251 break; 252 case 's': 253 for(s = s_to_c(mp->replyaddr); *s; s++) 254 s_putc(stp, *s); 255 break; 256 case 'p': 257 if(mp->bulk) 258 s = "bulk"; 259 else 260 s = "normal"; 261 for(;*s; s++) 262 s_putc(stp, *s); 263 break; 264 default: 265 s_putc(stp, *sp); 266 break; 267 } 268 } else if(*sp == '&') { 269 if(subexp[0].sp != 0) 270 for (s = subexp[0].sp; 271 s < subexp[0].ep; s++) 272 s_putc(stp, *s); 273 } else 274 s_putc(stp, *sp); 275 sp++; 276 } 277 s_terminate(stp); 278 279 return s_restart(stp); 280 } 281 282 extern void 283 regerror(char* s) 284 { 285 fprint(2, "rewrite: %s\n", s); 286 /* make sure the message is seen locally */ 287 syslog(0, "mail", "regexp error in rewrite: %s", s); 288 } 289 290 extern void 291 dumprules(void) 292 { 293 rule *rp; 294 295 for (rp = rulep; rp != 0; rp = rp->next) { 296 fprint(2, "'%s'", rp->matchre->base); 297 switch (rp->type) { 298 case d_pipe: 299 fprint(2, " |"); 300 break; 301 case d_cat: 302 fprint(2, " >>"); 303 break; 304 case d_alias: 305 fprint(2, " alias"); 306 break; 307 case d_translate: 308 fprint(2, " translate"); 309 break; 310 default: 311 fprint(2, " UNKNOWN"); 312 break; 313 } 314 fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"..."); 315 fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"..."); 316 } 317 } 318 319