summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ratfs/ctlfiles.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/ratfs/ctlfiles.c397
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;
+ }
+ }
+}