Blob


1 #include "common.h"
2 #include "send.h"
4 extern int debug;
6 /*
7 * Routines for dealing with the rewrite rules.
8 */
10 /* globals */
11 typedef struct rule rule;
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;
26 /* predeclared */
27 static String *substitute(String *, Resub *, message *);
28 static rule *findrule(String *, int);
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;
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 }
69 static int
70 getrule(String *line, String *type, char *system)
71 {
72 rule *rp;
73 String *re;
74 int backl;
76 backl = 0;
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;
115 if(rulep == 0)
116 rulep = rlastp = rp;
117 else
118 rlastp = rlastp->next = rp;
119 return backl;
122 /*
123 * rules are of the form:
124 * <reg exp> <String> <repl exp> [<repl exp>]
125 */
126 extern int
127 getrules(void)
129 Biobuf *rfp;
130 String *line;
131 String *type;
132 String *file;
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;
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;
153 /* look up a matching rule */
154 static rule *
155 findrule(String *addrp, int authorized)
157 rule *rp;
158 static rule defaultrule;
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;
177 return 0;
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)
188 rule *rp; /* rewriting rule */
189 String *lower; /* lower case version of destination */
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;
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");
213 s_free(lower);
214 return 0;
217 /* stolen from rc/lex.c */
218 static int
219 idchr(int c)
221 return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
224 static char*
225 getrcvar(char* p, char** rv)
227 char* p0;
228 char buf[128];
229 char* bufe;
231 *rv = 0;
232 p0=p;
233 bufe=buf+sizeof buf-1;
234 while(p<bufe && idchr(*p))
235 p++;
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;
245 static String *
246 substitute(String *source, Resub *subexp, message *mp)
248 int i;
249 char *s;
250 char *sp;
251 String *stp;
253 if(source == 0)
254 return 0;
255 sp = s_to_c(source);
257 /* someplace to put it */
258 stp = s_new();
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;
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++;
309 s_terminate(stp);
311 return s_restart(stp);
314 extern void
315 regerror(char* s)
317 fprint(2, "rewrite: %s\n", s);
320 extern void
321 dumprules(void)
323 rule *rp;
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;
344 fprint(2, " '%s'", rp->repl1 ? rp->repl1->base:"...");
345 fprint(2, " '%s'\n", rp->repl2 ? rp->repl2->base:"...");