aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/auth/factotum/ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/auth/factotum/ctl.c')
-rw-r--r--src/cmd/auth/factotum/ctl.c158
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;
+ }
+}