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 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
rewrite(dest * dp,message * mp)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
idchr(int c)219 idchr(int c)
220 {
221 	return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
222 }
223 
224 static char*
getrcvar(char * p,char ** rv)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 *
substitute(String * source,Resub * subexp,message * mp)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
regerror(char * s)315 regerror(char* s)
316 {
317 	fprint(2, "rewrite: %s\n", s);
318 }
319 
320 extern void
dumprules(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 }
348