summaryrefslogtreecommitdiff
path: root/appl/cmd/auth/secstore.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/auth/secstore.b')
-rw-r--r--appl/cmd/auth/secstore.b317
1 files changed, 317 insertions, 0 deletions
diff --git a/appl/cmd/auth/secstore.b b/appl/cmd/auth/secstore.b
new file mode 100644
index 00000000..5a63b78d
--- /dev/null
+++ b/appl/cmd/auth/secstore.b
@@ -0,0 +1,317 @@
+implement Secstorec;
+
+#
+# interact with the Plan 9 secstore
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "secstore.m";
+ secstore: Secstore;
+
+include "arg.m";
+
+Secstorec: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+Maxfilesize: con 128*1024;
+
+stderr: ref Sys->FD;
+conn: ref Sys->Connection;
+seckey: array of byte;
+filekey: array of byte;
+file: array of byte;
+verbose := 0;
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ secstore = load Secstore Secstore->PATH;
+
+ sys->pctl(Sys->FORKFD, nil);
+ stderr = sys->fildes(2);
+ secstore->init();
+ secstore->privacy();
+
+ addr := "net!$auth!secstore";
+ user := readfile("/dev/user");
+ arg := load Arg Arg->PATH;
+ arg->init(args);
+ arg->setusage("auth/secstore [-iv] [-k key] [-p pin] [-s net!server!secstore] [-u user] [{drptx} file ...]");
+ iflag := 0;
+ pass, pin: string;
+ while((o := arg->opt()) != 0)
+ case o {
+ 'i' => iflag = 1;
+ 'k' => pass = arg->earg();
+ 'v' => verbose = 1;
+ 's' => addr = arg->earg();
+ 'u' => user = arg->earg();
+ 'p' => pin = arg->earg();
+ * =>
+ arg->usage();
+ }
+ args = arg->argv();
+ op := -1;
+ if(args != nil){
+ if(len hd args != 1)
+ arg->usage();
+ op = (hd args)[0];
+ args = tl args;
+ case op {
+ 'd' or 'r' or 'p' or 'x' =>
+ if(args == nil)
+ arg->usage();
+ 't' =>
+ ;
+ * =>
+ arg->usage();
+ }
+ }
+ arg = nil;
+
+ if(iflag){
+ buf := array[Secstore->Maxmsg] of byte;
+ stdin := sys->fildes(0);
+ for(nr := 0; nr < len buf && (n := sys->read(stdin, buf, len buf-nr)) > 0;)
+ nr += n;
+ s := string buf[0:nr];
+ secstore->erasekey(buf[0:nr]);
+ (nf, flds) := sys->tokenize(s, "\n");
+ for(i := 0; i < len s; i++)
+ s[i] = 0;
+ if(nf < 1)
+ error("no password on standard input");
+ pass = hd flds;
+ if(nf > 1)
+ pin = hd tl flds;
+ }
+ conn: ref Sys->Connection;
+Auth:
+ for(;;){
+ if(!iflag)
+ pass = readpassword("secstore password");
+ if(pass == nil)
+ exit;
+ erase();
+ seckey = secstore->mkseckey(pass);
+ filekey = secstore->mkfilekey(pass);
+ for(i := 0; i < len pass; i++)
+ pass[i] = 0; # clear it
+ conn = secstore->dial(netmkaddr(addr, "net", "secstore"));
+ if(conn == nil)
+ error(sys->sprint("can't connect to secstore: %r"));
+ (srvname, diag) := secstore->auth(conn, user, seckey);
+ if(srvname == nil){
+ secstore->bye(conn);
+ sys->fprint(stderr, "secstore: authentication failed: %s\n", diag);
+ if(iflag)
+ raise "fail:auth";
+ continue;
+ }
+ case diag {
+ "" =>
+ if(verbose)
+ sys->fprint(stderr, "server: %s\n", srvname);
+ secstore->erasekey(seckey);
+ seckey = nil;
+ break Auth;
+ "need pin" =>
+ if(!iflag){
+ pin = readpassword("STA PIN+SecureID");
+ if(len pin == 0){
+ sys->fprint(stderr, "cancelled");
+ exit;
+ }
+ }else if(pin == nil)
+ raise "fail:no pin";
+ if(secstore->sendpin(conn, pin) < 0){
+ sys->fprint(stderr, "secstore: pin rejected: %r\n");
+ if(iflag)
+ raise "fail:bad pin";
+ continue;
+ }
+ }
+ }
+ if(op == 't'){
+ erase(); # no longer need the keys
+ entries := secstore->files(conn);
+ for(; entries != nil; entries = tl entries){
+ (name, size, date, hash, nil) := hd entries;
+ if(args != nil){
+ for(l := args; l != nil; l = tl l)
+ if((hd args) == name)
+ break;
+ if(args == nil)
+ continue;
+ }
+ if(verbose)
+ sys->print("%-14q %10d %s %s\n", name, size, date, hash);
+ else
+ sys->print("%q\n", name);
+ }
+ exit;
+ }
+ for(; args != nil; args = tl args){
+ fname := hd args;
+ case op {
+ 'd' =>
+ checkname(fname, 1);
+ if(secstore->remove(conn, fname) < 0)
+ error(sys->sprint("can't remove %q: %r", fname));
+ verb('d', fname);
+ 'p' =>
+ checkname(fname, 1);
+ file = getfile(conn, fname, filekey);
+ lines := secstore->lines(file);
+ lno := 1;
+ for(; lines != nil; lines = tl lines){
+ l := hd lines;
+ if(sys->write(sys->fildes(1), l, len l) != len l)
+ sys->fprint(sys->fildes(2), "secstore (%s:%d): %r\n", fname, lno);
+ lno++;
+ }
+ secstore->erasekey(file);
+ file = nil;
+ verb('p', fname);
+ 'x' =>
+ checkname(fname, 1);
+ file = getfile(conn, fname, filekey);
+ ofd := sys->create(fname, Sys->OWRITE, 8r600);
+ if(ofd == nil)
+ error(sys->sprint("can't create %q: %r", fname));
+ if(sys->write(ofd, file, len file) != len file)
+ error(sys->sprint("error writing to %q: %r", fname));
+ secstore->erasekey(file);
+ file = nil;
+ verb('x', fname);
+ 'r' or * =>
+ error(sys->sprint("op %c not implemented", op));
+ }
+ }
+ erase();
+}
+
+checkname(s: string, noslash: int): string
+{
+ tail := s;
+ for(i := 0; i < len s; i++){
+ if(s[i] == '/'){
+ if(noslash)
+ break;
+ tail = s[i+1:];
+ }
+ if(s[i] == '\n' || s[i] <= ' ')
+ break;
+ }
+ if(s == nil || tail == nil || i < len s || s == "..")
+ error(sys->sprint("can't use %q as a secstore file name", s)); # server checks as well, of course
+ return tail;
+}
+
+verb(op: int, n: string)
+{
+ if(verbose)
+ sys->fprint(stderr, "%c %q\n", op, n);
+}
+
+getfile(conn: ref Sys->Connection, fname: string, key: array of byte): array of byte
+{
+ f := secstore->getfile(conn, fname, 0);
+ if(f == nil)
+ error(sys->sprint("can't fetch %q: %r", fname));
+ if(fname != "."){
+ f = secstore->decrypt(f, key);
+ if(f == nil)
+ error(sys->sprint("can't decrypt %q: %r", fname));
+ }
+ return f;
+}
+
+erase()
+{
+ if(secstore != nil){
+ secstore->erasekey(seckey);
+ secstore->erasekey(filekey);
+ secstore->erasekey(file);
+ }
+}
+
+error(s: string)
+{
+ erase();
+ sys->fprint(stderr, "secstore: %s\n", s);
+ raise "fail:error";
+}
+
+readpassword(prompt: string): string
+{
+ cons := sys->open("/dev/cons", Sys->ORDWR);
+ if(cons == nil)
+ return nil;
+ stdin := bufio->fopen(cons, Sys->OREAD);
+ if(stdin == nil)
+ return nil;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if (cfd == nil || sys->fprint(cfd, "rawon") <= 0)
+ sys->fprint(stderr, "secstore: warning: cannot hide typed password\n");
+L:
+ for(;;){
+ sys->fprint(cons, "%s: ", prompt);
+ s := "";
+ while ((c := stdin.getc()) >= 0){
+ case c {
+ '\n' or ('d'&8r037) =>
+ sys->fprint(cons, "\n");
+ return s;
+ '\b' or 8r177 =>
+ if(len s > 0)
+ s = s[0:len s - 1];
+ 'u' & 8r037 =>
+ sys->fprint(cons, "\n");
+ continue L;
+ * =>
+ s[len s] = c;
+ }
+ }
+ break;
+ }
+ return nil;
+}
+
+readfile(f: string): string
+{
+ fd := sys->open(f, Sys->OREAD);
+ if(fd == nil)
+ return "";
+ buf := array[Sys->NAMEMAX] of byte;
+ n := sys->read(fd, buf, len buf);
+ if(n < 0)
+ return "";
+ return string buf[0:n];
+}
+
+netmkaddr(addr, net, svc: string): string
+{
+ if(net == nil)
+ net = "net";
+ (n, nil) := sys->tokenize(addr, "!");
+ if(n <= 1){
+ if(svc== nil)
+ return sys->sprint("%s!%s", net, addr);
+ return sys->sprint("%s!%s!%s", net, addr, svc);
+ }
+ if(svc == nil || n > 2)
+ return addr;
+ return sys->sprint("%s!%s", addr, svc);
+}