xref: /plan9/sys/src/cmd/upas/send/rewrite.c (revision c6569576083e48cef148efbb162a33bacec4ce98)
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