summaryrefslogtreecommitdiff
path: root/appl/cmd/auth/keysrv.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/auth/keysrv.b')
-rw-r--r--appl/cmd/auth/keysrv.b199
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);
+}