diff options
Diffstat (limited to 'appl/cmd/auth/keysrv.b')
| -rw-r--r-- | appl/cmd/auth/keysrv.b | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/appl/cmd/auth/keysrv.b b/appl/cmd/auth/keysrv.b new file mode 100644 index 00000000..c7144256 --- /dev/null +++ b/appl/cmd/auth/keysrv.b @@ -0,0 +1,199 @@ +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, nbytes, fid, rc) := <-file.read => + if(rc == nil) + break; + if(err != nil){ + rc <-= (nil, err); + break; + } + rc <-= (nil, nil); + (nil, data, fid, 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); +} |
