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