diff options
Diffstat (limited to 'src/cmd/auth/factotum/ctl.c')
-rw-r--r-- | src/cmd/auth/factotum/ctl.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/cmd/auth/factotum/ctl.c b/src/cmd/auth/factotum/ctl.c new file mode 100644 index 00000000..df44b97d --- /dev/null +++ b/src/cmd/auth/factotum/ctl.c @@ -0,0 +1,158 @@ +#include "std.h" +#include "dat.h" + +/* + * key attr=val... - add a key + * the attr=val pairs are protocol-specific. + * for example, both of these are valid: + * key p9sk1 gre cs.bell-labs.com mysecret + * key p9sk1 gre cs.bell-labs.com 11223344556677 fmt=des7hex + * delkey ... - delete a key + * if given, the attr=val pairs are used to narrow the search + * [maybe should require a password?] + * + * debug - toggle debugging + */ + +static char *msg[] = { + "key", + "delkey", + "debug", +}; + +static int +classify(char *s) +{ + int i; + + for(i=0; i<nelem(msg); i++) + if(strcmp(msg[i], s) == 0) + return i; + return -1; +} + +int +ctlwrite(char *a) +{ + char *p; + int i, nmatch, ret; + Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos; + Key *k; + Proto *proto; + + if(a[0] == '#' || a[0] == '\0') + return 0; + + /* + * it would be nice to emit a warning of some sort here. + * we ignore all but the first line of the write. this helps + * both with things like "echo delkey >/mnt/factotum/ctl" + * and writes that (incorrectly) contain multiple key lines. + */ + if(p = strchr(a, '\n')){ + if(p[1] != '\0'){ + werrstr("multiline write not allowed"); + return -1; + } + *p = '\0'; + } + + if((p = strchr(a, ' ')) == nil) + p = ""; + else + *p++ = '\0'; + switch(classify(a)){ + default: + werrstr("unknown verb"); + return -1; + case 0: /* key */ + attr = parseattr(p); + /* separate out proto= attributes */ + lprotos = &protos; + for(l=&attr; (*l); ){ + if(strcmp((*l)->name, "proto") == 0){ + *lprotos = *l; + lprotos = &(*l)->next; + *l = (*l)->next; + }else + l = &(*l)->next; + } + *lprotos = nil; + if(protos == nil){ + werrstr("key without protos"); + freeattr(attr); + return -1; + } + + /* separate out private attributes */ + lpriv = &priv; + for(l=&attr; (*l); ){ + if((*l)->name[0] == '!'){ + *lpriv = *l; + lpriv = &(*l)->next; + *l = (*l)->next; + }else + l = &(*l)->next; + } + *lpriv = nil; + + /* add keys */ + ret = 0; + for(pa=protos; pa; pa=pa->next){ + if((proto = protolookup(pa->val)) == nil){ + werrstr("unknown proto %s", pa->val); + ret = -1; + continue; + } + if(proto->checkkey == nil){ + werrstr("proto %s does not accept keys", proto->name); + ret = -1; + continue; + } + k = emalloc(sizeof(Key)); + k->attr = mkattr(AttrNameval, "proto", proto->name, copyattr(attr)); + k->privattr = copyattr(priv); + k->ref = 1; + k->proto = proto; + if((*proto->checkkey)(k) < 0){ + ret = -1; + keyclose(k); + continue; + } + keyadd(k); + keyclose(k); + } + freeattr(attr); + freeattr(priv); + freeattr(protos); + return ret; + case 1: /* delkey */ + nmatch = 0; + attr = parseattr(p); + for(pa=attr; pa; pa=pa->next){ + if(pa->type != AttrQuery && pa->name[0]=='!'){ + werrstr("only !private? patterns are allowed for private fields"); + freeattr(attr); + return -1; + } + } + for(i=0; i<ring.nkey; ){ + if(matchattr(attr, ring.key[i]->attr, ring.key[i]->privattr)){ + nmatch++; + keyclose(ring.key[i]); + ring.nkey--; + memmove(&ring.key[i], &ring.key[i+1], (ring.nkey-i)*sizeof(ring.key[0])); + }else + i++; + } + freeattr(attr); + if(nmatch == 0){ + werrstr("found no keys to delete"); + return -1; + } + return 0; + case 2: /* debug */ + debug ^= 1; + return 0; + } +} |