blob: d12fbca7caa59c16d6ff9a9fbc2d7f3a3dd0ba93 [file] [log] [blame]
#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, *kpa, **l, **lpriv, **lprotos, *pa, *priv, *protos;
Key *k;
Proto *proto;
while(*a == ' ' || *a == '\t' || *a == '\n')
a++;
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 %s", a);
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;
flog("addkey %A %A %N", protos, attr, priv);
/* add keys */
ret = 0;
for(pa=protos; pa; pa=pa->next){
if((proto = protolookup(pa->val)) == nil){
werrstr("unknown proto %s", pa->val);
flog("addkey: %r");
ret = -1;
continue;
}
if(proto->keyprompt){
kpa = parseattr(proto->keyprompt);
if(!matchattr(kpa, attr, priv)){
freeattr(kpa);
werrstr("missing attributes -- want %s", proto->keyprompt);
flog("addkey %s: %r", proto->name);
ret = -1;
continue;
}
freeattr(kpa);
}
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 && (*proto->checkkey)(k) < 0){
flog("addkey %s: %r", proto->name);
ret = -1;
keyclose(k);
continue;
}
flog("adding key: %A %N", k->attr, k->privattr);
keyadd(k);
keyclose(k);
}
freeattr(attr);
freeattr(priv);
freeattr(protos);
return ret;
case 1: /* delkey */
nmatch = 0;
attr = parseattr(p);
flog("delkey %A", attr);
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++;
flog("deleting %A %N", ring.key[i]->attr, ring.key[i]->privattr);
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;
flog("debug = %d", debug);
return 0;
}
}