ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/auth/keysrv.b/
implement Keysrv;
#
# remote access to keys (currently only to change secret)
#
# Copyright © 2003 Vita Nuova Holdings Limited. All rights reserved.
#
include "sys.m";
sys: Sys;
include "draw.m";
include "keyring.m";
kr: Keyring;
include "security.m";
auth: Auth;
include "arg.m";
keydb := "/mnt/keys";
Keysrv: module
{
init: fn(nil: ref Draw->Context, nil: list of string);
};
usage()
{
sys->fprint(sys->fildes(2), "usage: keysrv\n");
raise "fail:usage";
}
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
if(sys->pctl(Sys->FORKNS|Sys->NEWPGRP, nil) < 0)
err(sys->sprint("can't fork name space: %r"));
keyfile := "/usr/"+user()+"/keyring/default";
arg := load Arg Arg->PATH;
if(arg == nil)
err("can't load Arg");
arg->init(args);
while((o := arg->opt()) != 0)
case o {
'k' =>
keyfile = arg->arg();
* =>
usage();
}
args = arg->argv();
arg = nil;
kr = load Keyring Keyring->PATH;
if(kr == nil)
err("can't load Keyring");
auth = load Auth Auth->PATH;
if(auth == nil)
err("can't load Auth");
auth->init();
ai := kr->readauthinfo(keyfile);
if(ai == nil)
err(sys->sprint("can't read server key file %s: %r", keyfile));
(fd, id_or_err) := auth->server("sha1" :: "rc4_256" :: nil, ai, sys->fildes(0), 0);
if(fd == nil)
err(sys->sprint("can't authenticate: %s", id_or_err));
if(sys->bind("#s", "/mnt/keysrv", Sys->MREPL) < 0)
err(sys->sprint("can't bind #s on /mnt/keysrv: %r"));
srv := sys->file2chan("/mnt/keysrv", "secret");
if(srv == nil)
err(sys->sprint("can't create file2chan on /mnt/keysrv: %r"));
exitc := chan of int;
spawn worker(srv, id_or_err, exitc);
if(sys->export(fd, "/mnt/keysrv", Sys->EXPWAIT) < 0){
exitc <-= 1;
err(sys->sprint("can't export %s: %r", "/mnt/keysrv"));
}
exitc <-= 1;
}
err(s: string)
{
sys->fprint(sys->fildes(2), "keysrv: %s\n", s);
raise "fail:error";
}
user(): string
{
fd := sys->open("/dev/user", Sys->OREAD);
if(fd == nil)
err(sys->sprint("can't open /dev/user: %r"));
buf := array[Sys->NAMEMAX] of byte;
n := sys->read(fd, buf, len buf);
if(n < 0)
err(sys->sprint("error reading /dev/user: %r"));
return string buf[0:n];
}
worker(file: ref Sys->FileIO, user: string, exitc: chan of int)
{
(keydir, secret, err) := getuser(user);
if(keydir == nil || secret == nil){
if(err == nil)
err = "no existing secret"; # can't change it remotely until set
}
(nil, hash) := hashkey(secret);
for(;;)alt{
<-exitc =>
exit;
(nil, nil, nil, rc) := <-file.read =>
if(rc == nil)
break;
if(err != nil){
rc <-= (nil, err);
break;
}
rc <-= (nil, nil);
(nil, data, nil, wc) := <-file.write =>
if(wc == nil)
break;
if(err != nil){
wc <-= (0, err);
break;
}
for(i := 0; i < len data; i++)
if(data[i] == byte ' ')
break;
if(string data[0:i] != hash){
wc <-= (0, "wrong secret");
break;
}
if(++i >= len data){
wc <-= (0, nil);
break;
}
if(len data - i < 8){
wc <-= (0, "unacceptable secret");
break;
}
if(putsecret(keydir, data[i:]) < 0){
wc <-= (0, sys->sprint("can't update secret: %r"));
break;
}
wc <-= (len data, nil);
}
}
hashkey(a: array of byte): (array of byte, string)
{
hash := array[Keyring->SHA1dlen] of byte;
kr->sha1(a, len a, hash, nil);
s := "";
for(i := 0; i < len hash; i++)
s += sys->sprint("%2.2ux", int hash[i]);
return (hash, s);
}
getuser(id: string): (string, array of byte, string)
{
(ok, nil) := sys->stat(keydb);
if(ok < 0)
return (nil, nil, sys->sprint("can't stat %s: %r", id));
dbdir := keydb+"/"+id;
(ok, nil) = sys->stat(dbdir);
if(ok < 0)
return (nil, nil, sys->sprint("user not registered: %s", id));
fd := sys->open(dbdir+"/secret", Sys->OREAD);
if(fd == nil)
return (nil, nil, sys->sprint("can't open %s/secret: %r", id));
d: Sys->Dir;
(ok, d) = sys->fstat(fd);
if(ok < 0)
return (nil, nil, sys->sprint("can't stat %s/secret: %r", id));
l := int d.length;
secret: array of byte;
if(l > 0){
secret = array[l] of byte;
if(sys->read(fd, secret, len secret) != len secret)
return (nil, nil, sys->sprint("error reading %s/secret: %r", id));
}
return (dbdir, secret, nil);
}
putsecret(dir: string, secret: array of byte): int
{
fd := sys->create(dir+"/secret", Sys->OWRITE, 8r600);
if(fd == nil)
return -1;
return sys->write(fd, secret, len secret);
}