URI: 
       trewrite.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       trewrite.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 }