]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ratfs/ctlfiles.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / ratfs / ctlfiles.c
1 #include "ratfs.h"
2 #include <ip.h>
3
4 enum {
5         ACCEPT = 0,             /* verbs in control file */
6         REFUSED,
7         DENIED,
8         DIALUP,
9         BLOCKED,
10         DELAY,
11         NONE,
12
13         Subchar =       '#',    /* character substituted for '/' in file names */
14 };
15
16 static  Keyword actions[] = {
17         "allow",                ACCEPT,
18         "accept",               ACCEPT,
19         "block",                BLOCKED,
20         "deny",                 DENIED,
21         "dial",                 DIALUP,
22         "relay",                DELAY,
23         "delay",                DELAY,
24         0,                      NONE,
25 };
26
27 static void     acctinsert(Node*, char*);
28 static char*    getline(Biobuf*);
29 static void     ipinsert(Node*, char*);
30 static void     ipsort(void);
31
32 /*
33  *      Input the configuration file
34  *      Currently we only process the "ournets"
35  *      specification.
36  */
37 void
38 getconf(void)
39 {
40         Biobuf *bp;
41         char *cp;
42         Node *np, *dir, **l;
43
44         if(debugfd >= 0)
45                 fprint(debugfd, "loading %s\n", conffile);
46
47         bp = Bopen(conffile, OREAD);
48         if(bp == 0)
49                 return;
50
51         dir = finddir(Trusted);
52         if(dir == 0)
53                 return;
54
55         /*
56          * if this isn't the first time, purge permanent entries
57          */
58         trustedqid = Qtrustedfile;
59         if(lastconftime){
60                 l = &dir->children;
61                 for(np = dir->children; np; np = *l){
62                         if(np->d.type == Trustedperm){
63                                 *l = np->sibs;
64                                 free(np);
65                         } else {
66                                 np->d.qid.path = trustedqid++;
67                                 l = &np->sibs;
68                         }
69                 }
70                 dir->count = 0;
71         }
72
73         for(;;){
74                 cp = getline(bp);
75                 if(cp == 0)
76                         break;
77                 if (strcmp(cp, "ournets") == 0){
78                         for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){
79                                 np = newnode(dir, cp, Trustedperm, 0111, trustedqid++);
80                                 cidrparse(&np->ip, cp);
81                                 subslash(cp);
82                                 np->d.name = atom(cp);
83                         }
84                 }
85         }
86         Bterm(bp);
87         lastconftime = time(0);
88 }
89
90 /*
91  *      Reload the control file, if necessary
92  */
93 void
94 reload(void)
95 {
96         int type, action;
97         Biobuf *bp;
98         char *cp;
99         Node *np, *dir;
100
101         if(debugfd >= 0)
102                 fprint(debugfd,"loading %s\n", ctlfile);
103
104         bp = Bopen(ctlfile, OREAD);
105         if(bp == 0)
106                 return;
107         
108         if(lastctltime){
109                 for(dir = root->children; dir; dir = dir->sibs){
110                         if (dir->d.type != Addrdir)
111                                 continue;
112                         for(np = dir->children; np; np = np->sibs)
113                                 np->count = 0;
114                 }
115         }
116
117         for(;;){
118                 cp = getline(bp);
119                 if(cp == 0)
120                         break;
121                 type = *cp;
122                 if(type == '*'){
123                         cp++;
124                         if(*cp == 0)            /* space before keyword */
125                                 cp++;
126                 }
127                 action = findkey(cp, actions);
128                 if (action == NONE)
129                         continue;
130                 if (action == ACCEPT)
131                         dir = dirwalk("allow", root);
132                 else
133                 if (action == DELAY)
134                         dir = dirwalk("delay", root);
135                 else
136                         dir = dirwalk(cp, root);
137                 if(dir == 0)
138                         continue;
139                 
140                 for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){
141                         if(type == '*')
142                                 acctinsert(dir, cp);
143                         else
144                                 ipinsert(dir, cp);
145                 }
146         }
147         Bterm(bp);
148         ipsort();
149         dummy.d.mtime = dummy.d.atime = lastctltime = time(0);
150 }
151
152 /*
153  * get a canonicalized line: a string of null-terminated lower-case
154  * tokens with a two null bytes at the end.
155  */
156 static char*
157 getline(Biobuf *bp)
158 {
159         char c, *cp, *p, *q;
160         int n;
161
162         static char *buf;
163         static int bufsize;
164
165         for(;;){
166                 cp = Brdline(bp, '\n');
167                 if(cp == 0)
168                         return 0;
169                 n = Blinelen(bp);
170                 cp[n-1] = 0;
171                 if(buf == 0 || bufsize < n+1){
172                         bufsize += 512;
173                         if(bufsize < n+1)
174                                 bufsize = n+1;
175                         buf = realloc(buf, bufsize);
176                         if(buf == 0)
177                                 break;
178                 }
179                 q = buf;
180                 for (p = cp; *p; p++){
181                         c = *p;
182                         if(c == '\\' && p[1])   /* we don't allow \<newline> */
183                                 c = *++p;
184                         else
185                         if(c == '#')
186                                 break;
187                         else
188                         if(c == ' ' || c == '\t' || c == ',')
189                                 if(q == buf || q[-1] == 0)
190                                         continue;
191                                 else
192                                         c = 0;
193                         *q++ = tolower(c);
194                 }
195                 if(q != buf){
196                         if(q[-1])
197                                 *q++ = 0;
198                         *q = 0;
199                         break;
200                 }
201         }
202         return buf;
203 }
204
205 /*
206  *      Match a keyword
207  */
208 int
209 findkey(char *val, Keyword *p)
210 {
211
212         for(; p->name; p++)
213                 if(strcmp(val, p->name) == 0)
214                                 break;
215         return p->code;
216 }
217
218 /*
219  *      parse a cidr specification in either IP/mask or IP#mask format
220  */
221 void
222 cidrparse(Cidraddr *cidr, char *cp)
223 {
224
225         char *p, *slash;
226         int c;
227         ulong a, m;
228         uchar addr[IPv4addrlen];
229         uchar mask[IPv4addrlen];
230         char buf[64];
231
232         /*
233          * find '/' or '#' character in the cidr specification
234          */
235         slash = 0;
236         for(p = buf; p < buf+sizeof(buf)-1 && *cp; p++) {
237                 c = *cp++;
238                 switch(c) {
239                 case Subchar:
240                         c = '/';
241                         slash = p;
242                         break;
243                 case '/':
244                         slash = p;
245                         break;
246                 default:
247                         break;
248                 }
249                 *p = c;
250         }
251         *p = 0;
252
253         v4parsecidr(addr, mask, buf);
254         a = nhgetl(addr);
255         m = nhgetl(mask);
256         /*
257          * if a mask isn't specified, we build a minimal mask
258          * instead of using the default mask for that net.  in this
259          * case we never allow a class A mask (0xff000000).
260          */
261         if(slash == 0){
262                 m = 0xff000000;
263                 p = buf;
264                 for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.'))
265                                 m = (m>>8)|0xff000000;
266
267                 /* force at least a class B */
268                 m |= 0xffff0000;
269         }
270         cidr->ipaddr = a;
271         cidr->mask = m;
272 }
273
274 /*
275  *      Substitute Subchar ('#') for '/'
276  */
277 char*
278 subslash(char *os)
279 {
280         char *s;
281
282         for(s=os; *s; s++)
283                 if(*s == '/')
284                         *s = Subchar;
285         return os;
286 }
287
288 /*
289  *      Insert an account pseudo-file in a directory
290  */
291 static void
292 acctinsert(Node *np, char *cp)
293 {
294         int i;
295         char *tmp;
296         Address *ap;
297
298         static char *dangerous[] = { "*", "!", "*!", "!*", "*!*", 0 };
299
300         if(cp == 0 || *cp == 0)
301                 return;
302
303         /* rule out dangerous patterns */
304         for (i = 0; dangerous[i]; i++)
305                 if(strcmp(cp, dangerous[i])== 0)
306                         return;
307
308         np = dirwalk("account", np);
309         if(np == 0)
310                 return;
311
312         i = np->count++;
313         if(i >= np->allocated){
314                 np->allocated = np->count;
315                 np->addrs = realloc(np->addrs, np->allocated*sizeof(Address));
316                 if(np->addrs == 0)
317                         fatal("out of memory");
318         }
319
320         ap = &np->addrs[i];                     /* new entry on end */
321         tmp = strdup(cp);
322         if(tmp == nil)
323                 fatal("out of memory");
324         subslash(tmp);
325         ap->name = atom(tmp);
326         free(tmp);
327 }
328
329 /*
330  *      Insert an IP address pseudo-file in a directory
331  */
332 static void
333 ipinsert(Node *np, char *cp)
334 {
335         char *tmp;
336         int i;
337         Address *ap;
338         if(cp == 0 || *cp == 0)
339                 return;
340
341         np = dirwalk("ip", np);
342         if(np == 0)
343                 return;
344
345         i = np->count++;
346         if(i >= np->allocated){
347                 np->allocated = np->count;
348                 np->addrs = realloc(np->addrs, np->allocated*sizeof(Address));
349                 if(np->addrs == 0)
350                         fatal("out of memory");
351         }
352
353         ap = &np->addrs[i];                             /* new entry on end */
354         tmp = strdup(cp);
355         if(tmp == nil)
356                 fatal("out of memory");
357         subslash(tmp);
358         ap->name = atom(tmp);
359         free(tmp);
360         cidrparse(&ap->ip, cp);
361 }
362
363 int
364 ipcomp(void *a, void *b)
365 {
366         ulong aip, bip;
367
368         aip = ((Address*)a)->ip.ipaddr;
369         bip = ((Address*)b)->ip.ipaddr;
370         if(aip > bip)
371                 return 1;
372         if(aip < bip)
373                 return -1;
374         return 0;
375 }
376
377 /*
378  *      Sort a directory of IP addresses
379  */
380 static void
381 ipsort(void)
382 {
383         int base;
384         Node *dir, *np;
385
386         base = Qaddrfile;
387         for(dir = root->children; dir; dir = dir->sibs){
388                 if (dir->d.type != Addrdir)
389                         continue;
390                 for(np = dir->children; np; np = np->sibs){
391                         if(np->d.type == IPaddr && np->count && np->addrs)
392                                 qsort(np->addrs, np->count, sizeof(Address), ipcomp);
393                         np->baseqid = base;
394                         base += np->count;
395                 }
396         }
397 }