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 *
rule_parse(String * line,char * system,int * backl)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
getrule(String * line,String * type,char * system)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
getrules(void)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 *
findrule(String * addrp,int authorized)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
rewrite(dest * dp,message * mp)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 *
substitute(String * source,Resub * subexp,message * mp)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
regerror(char * s)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
dumprules(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