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