diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ratfs/ctlfiles.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ratfs/ctlfiles.c')
-rwxr-xr-x | sys/src/cmd/ratfs/ctlfiles.c | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/sys/src/cmd/ratfs/ctlfiles.c b/sys/src/cmd/ratfs/ctlfiles.c new file mode 100755 index 000000000..a9f863029 --- /dev/null +++ b/sys/src/cmd/ratfs/ctlfiles.c @@ -0,0 +1,397 @@ +#include "ratfs.h" +#include <ip.h> + +enum { + ACCEPT = 0, /* verbs in control file */ + REFUSED, + DENIED, + DIALUP, + BLOCKED, + DELAY, + NONE, + + Subchar = '#', /* character substituted for '/' in file names */ +}; + +static Keyword actions[] = { + "allow", ACCEPT, + "accept", ACCEPT, + "block", BLOCKED, + "deny", DENIED, + "dial", DIALUP, + "relay", DELAY, + "delay", DELAY, + 0, NONE, +}; + +static void acctinsert(Node*, char*); +static char* getline(Biobuf*); +static void ipinsert(Node*, char*); +static void ipsort(void); + +/* + * Input the configuration file + * Currently we only process the "ournets" + * specification. + */ +void +getconf(void) +{ + Biobuf *bp; + char *cp; + Node *np, *dir, **l; + + if(debugfd >= 0) + fprint(debugfd, "loading %s\n", conffile); + + bp = Bopen(conffile, OREAD); + if(bp == 0) + return; + + dir = finddir(Trusted); + if(dir == 0) + return; + + /* + * if this isn't the first time, purge permanent entries + */ + trustedqid = Qtrustedfile; + if(lastconftime){ + l = &dir->children; + for(np = dir->children; np; np = *l){ + if(np->d.type == Trustedperm){ + *l = np->sibs; + free(np); + } else { + np->d.qid.path = trustedqid++; + l = &np->sibs; + } + } + dir->count = 0; + } + + for(;;){ + cp = getline(bp); + if(cp == 0) + break; + if (strcmp(cp, "ournets") == 0){ + for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){ + np = newnode(dir, cp, Trustedperm, 0111, trustedqid++); + cidrparse(&np->ip, cp); + subslash(cp); + np->d.name = atom(cp); + } + } + } + Bterm(bp); + lastconftime = time(0); +} + +/* + * Reload the control file, if necessary + */ +void +reload(void) +{ + int type, action; + Biobuf *bp; + char *cp; + Node *np, *dir; + + if(debugfd >= 0) + fprint(debugfd,"loading %s\n", ctlfile); + + bp = Bopen(ctlfile, OREAD); + if(bp == 0) + return; + + if(lastctltime){ + for(dir = root->children; dir; dir = dir->sibs){ + if (dir->d.type != Addrdir) + continue; + for(np = dir->children; np; np = np->sibs) + np->count = 0; + } + } + + for(;;){ + cp = getline(bp); + if(cp == 0) + break; + type = *cp; + if(type == '*'){ + cp++; + if(*cp == 0) /* space before keyword */ + cp++; + } + action = findkey(cp, actions); + if (action == NONE) + continue; + if (action == ACCEPT) + dir = dirwalk("allow", root); + else + if (action == DELAY) + dir = dirwalk("delay", root); + else + dir = dirwalk(cp, root); + if(dir == 0) + continue; + + for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){ + if(type == '*') + acctinsert(dir, cp); + else + ipinsert(dir, cp); + } + } + Bterm(bp); + ipsort(); + dummy.d.mtime = dummy.d.atime = lastctltime = time(0); +} + +/* + * get a canonicalized line: a string of null-terminated lower-case + * tokens with a two null bytes at the end. + */ +static char* +getline(Biobuf *bp) +{ + char c, *cp, *p, *q; + int n; + + static char *buf; + static int bufsize; + + for(;;){ + cp = Brdline(bp, '\n'); + if(cp == 0) + return 0; + n = Blinelen(bp); + cp[n-1] = 0; + if(buf == 0 || bufsize < n+1){ + bufsize += 512; + if(bufsize < n+1) + bufsize = n+1; + buf = realloc(buf, bufsize); + if(buf == 0) + break; + } + q = buf; + for (p = cp; *p; p++){ + c = *p; + if(c == '\\' && p[1]) /* we don't allow \<newline> */ + c = *++p; + else + if(c == '#') + break; + else + if(c == ' ' || c == '\t' || c == ',') + if(q == buf || q[-1] == 0) + continue; + else + c = 0; + *q++ = tolower(c); + } + if(q != buf){ + if(q[-1]) + *q++ = 0; + *q = 0; + break; + } + } + return buf; +} + +/* + * Match a keyword + */ +int +findkey(char *val, Keyword *p) +{ + + for(; p->name; p++) + if(strcmp(val, p->name) == 0) + break; + return p->code; +} + +/* + * parse a cidr specification in either IP/mask or IP#mask format + */ +void +cidrparse(Cidraddr *cidr, char *cp) +{ + + char *p, *slash; + int c; + ulong a, m; + uchar addr[IPv4addrlen]; + uchar mask[IPv4addrlen]; + char buf[64]; + + /* + * find '/' or '#' character in the cidr specification + */ + slash = 0; + for(p = buf; p < buf+sizeof(buf)-1 && *cp; p++) { + c = *cp++; + switch(c) { + case Subchar: + c = '/'; + slash = p; + break; + case '/': + slash = p; + break; + default: + break; + } + *p = c; + } + *p = 0; + + v4parsecidr(addr, mask, buf); + a = nhgetl(addr); + m = nhgetl(mask); + /* + * if a mask isn't specified, we build a minimal mask + * instead of using the default mask for that net. in this + * case we never allow a class A mask (0xff000000). + */ + if(slash == 0){ + m = 0xff000000; + p = buf; + for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.')) + m = (m>>8)|0xff000000; + + /* force at least a class B */ + m |= 0xffff0000; + } + cidr->ipaddr = a; + cidr->mask = m; +} + +/* + * Substitute Subchar ('#') for '/' + */ +char* +subslash(char *os) +{ + char *s; + + for(s=os; *s; s++) + if(*s == '/') + *s = Subchar; + return os; +} + +/* + * Insert an account pseudo-file in a directory + */ +static void +acctinsert(Node *np, char *cp) +{ + int i; + char *tmp; + Address *ap; + + static char *dangerous[] = { "*", "!", "*!", "!*", "*!*", 0 }; + + if(cp == 0 || *cp == 0) + return; + + /* rule out dangerous patterns */ + for (i = 0; dangerous[i]; i++) + if(strcmp(cp, dangerous[i])== 0) + return; + + np = dirwalk("account", np); + if(np == 0) + return; + + i = np->count++; + if(i >= np->allocated){ + np->allocated = np->count; + np->addrs = realloc(np->addrs, np->allocated*sizeof(Address)); + if(np->addrs == 0) + fatal("out of memory"); + } + + ap = &np->addrs[i]; /* new entry on end */ + tmp = strdup(cp); + if(tmp == nil) + fatal("out of memory"); + subslash(tmp); + ap->name = atom(tmp); + free(tmp); +} + +/* + * Insert an IP address pseudo-file in a directory + */ +static void +ipinsert(Node *np, char *cp) +{ + char *tmp; + int i; + Address *ap; + if(cp == 0 || *cp == 0) + return; + + np = dirwalk("ip", np); + if(np == 0) + return; + + i = np->count++; + if(i >= np->allocated){ + np->allocated = np->count; + np->addrs = realloc(np->addrs, np->allocated*sizeof(Address)); + if(np->addrs == 0) + fatal("out of memory"); + } + + ap = &np->addrs[i]; /* new entry on end */ + tmp = strdup(cp); + if(tmp == nil) + fatal("out of memory"); + subslash(tmp); + ap->name = atom(tmp); + free(tmp); + cidrparse(&ap->ip, cp); +} + +int +ipcomp(void *a, void *b) +{ + ulong aip, bip; + + aip = ((Address*)a)->ip.ipaddr; + bip = ((Address*)b)->ip.ipaddr; + if(aip > bip) + return 1; + if(aip < bip) + return -1; + return 0; +} + +/* + * Sort a directory of IP addresses + */ +static void +ipsort(void) +{ + int base; + Node *dir, *np; + + base = Qaddrfile; + for(dir = root->children; dir; dir = dir->sibs){ + if (dir->d.type != Addrdir) + continue; + for(np = dir->children; np; np = np->sibs){ + if(np->d.type == IPaddr && np->count && np->addrs) + qsort(np->addrs, np->count, sizeof(Address), ipcomp); + np->baseqid = base; + base += np->count; + } + } +} |