plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

rewrite.c (6859B)


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