diff options
Diffstat (limited to 'appl/cmd/auth/passwd.b')
| -rw-r--r-- | appl/cmd/auth/passwd.b | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/appl/cmd/auth/passwd.b b/appl/cmd/auth/passwd.b new file mode 100644 index 00000000..d10b5c95 --- /dev/null +++ b/appl/cmd/auth/passwd.b @@ -0,0 +1,290 @@ +implement Passwd; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "keyring.m"; + kr: Keyring; + +include "security.m"; + auth: Auth; + +include "arg.m"; + +Passwd: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +stderr, stdin, stdout: ref Sys->FD; +keysrv := "/mnt/keysrv"; +signer := "$SIGNER"; + +usage() +{ + sys->fprint(sys->fildes(2), "usage: passwd [-u user] [-s signer] [keyfile]\n"); + raise "fail:usage"; +} + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + + stdin = sys->fildes(0); + stdout = sys->fildes(1); + stderr = sys->fildes(2); + + kr = load Keyring Keyring->PATH; + if(kr == nil) + noload(Keyring->PATH); + auth = load Auth Auth->PATH; + if(auth == nil) + noload(Auth->PATH); + auth->init(); + + keyfile, id: string; + arg := load Arg Arg->PATH; + if(arg == nil) + noload(Arg->PATH); + arg->init(args); + while((o := arg->opt()) != 0) + case o { + 's' => + signer = arg->arg(); + 'u' => + id = arg->arg(); + * => + usage(); + } + args = arg->argv(); + arg = nil; + + if(args == nil) + args = "default" :: nil; + + if(id == nil) + id= user(); + + if(args != nil) + keyfile = hd args; + else + keyfile = "default"; + if(len keyfile > 0 && keyfile[0] != '/') + keyfile = "/usr/" + id + "/keyring/" + keyfile; + + ai := kr->readauthinfo(keyfile); + if(ai == nil) + err(sys->sprint("can't read certificate from %s: %r", keyfile)); +sys->print("key owner: %s\n", ai.mypk.owner); + + sys->pctl(Sys->FORKNS|Sys->FORKFD, nil); + remid := mountsrv(ai); + + # get password + ok: int; + secret: array of byte; + oldhash: array of byte; + word: string; + for(;;){ + sys->print("Inferno secret: "); + (ok, word) = readline(stdin, "rawon"); + if(!ok || word == nil) + exit; + secret = array of byte word; + (nil, s) := hashkey(secret); + for(i := 0; i < len word; i++) + word[i] = ' '; + oldhash = array of byte s; + e := putsecret(oldhash, nil); + if(e != "wrong secret"){ + if(e == nil) + break; + err(e); + } + sys->fprint(stderr, "!wrong secret\n"); + } + newsecret: array of byte; + for(;;){ + for(;;){ + sys->print("new secret [default = don't change]: "); + (ok, word) = readline(stdin, "rawon"); + if(!ok) + exit; + if(word == "" && secret != nil) + break; + if(len word >= 8) + break; + sys->print("!secret must be at least 8 characters\n"); + } + if(word != ""){ + # confirm password change + word1 := word; + sys->print("confirm: "); + (ok, word) = readline(stdin, "rawon"); + if(!ok || word != word1){ + sys->fprint(stderr, "!entries didn't match\n"); + continue; + } + # TO DO... + #pwbuf := array of byte word; + #newsecret = array[Keyring->SHA1dlen] of byte; + #kr->sha1(pwbuf, len pwbuf, newsecret, nil); + newsecret = array of byte word; + } + if(!eq(newsecret, secret)){ + if((e := putsecret(oldhash, newsecret)) != nil){ + sys->fprint(stderr, "passwd: can't update secret for %s: %s\n", id, e); + continue; + } + } + break; + } +} + +noload(s: string) +{ + err(sys->sprint("can't load %s: %r", s)); +} + +err(s: string) +{ + sys->fprint(sys->fildes(2), "passwd: %s\n", s); + raise "fail:error"; +} + +mountsrv(ai: ref Keyring->Authinfo): string +{ + (rc, c) := sys->dial(netmkaddr(signer, "net", "infkey"), nil); + if(rc < 0) + err(sys->sprint("can't dial %s: %r", signer)); + (fd, id_or_err) := auth->client("sha1/rc4_256", ai, c.dfd); + if(fd == nil) + err(sys->sprint("can't authenticate with %s: %r", signer)); + if(sys->mount(fd, nil, keysrv, Sys->MREPL, nil) < 0) + err(sys->sprint("can't mount %s on %s: %r", signer, keysrv)); + return id_or_err; +} + +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]; +} + +eq(a, b: array of byte): int +{ + if(len a != len b) + return 0; + for(i := 0; i < len a; i++) + if(a[i] != b[i]) + return 0; + return 1; +} + +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); +} + +putsecret(oldhash: array of byte, secret: array of byte): string +{ + fd := sys->create(keysrv+"/secret", Sys->OWRITE, 8r600); + if(fd == nil) + return sys->sprint("%r"); + n := len oldhash; + if(secret != nil) + n += 1 + len secret; + buf := array[n] of byte; + buf[0:] = oldhash; + if(secret != nil){ + buf[len oldhash] = byte ' '; + buf[len oldhash+1:] = secret; + } + if(sys->write(fd, buf, len buf) < 0) + return sys->sprint("%r"); + return nil; +} + +netmkaddr(addr, net, svc: string): string +{ + if(net == nil) + net = "net"; + (n, l) := 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); +} + +readline(io: ref Sys->FD, mode: string): (int, string) +{ + r : int; + line : string; + buf := array[8192] of byte; + fdctl : ref Sys->FD; + rawoff := array of byte "rawoff"; + + if(mode == "rawon"){ + fdctl = sys->open("/dev/consctl", sys->OWRITE); + if(fdctl == nil || sys->write(fdctl,array of byte mode,len mode) != len mode){ + sys->fprint(stderr, "unable to change console mode"); + return (0,nil); + } + } + + line = ""; + for(;;) { + r = sys->read(io, buf, len buf); + if(r <= 0){ + sys->fprint(stderr, "error read from console mode"); + if(mode == "rawon") + sys->write(fdctl,rawoff,6); + return (0, nil); + } + + line += string buf[0:r]; + if ((len line >= 1) && (line[(len line)-1] == '\n')){ + if(mode == "rawon"){ + r = sys->write(stdout,array of byte "\n",1); + if(r <= 0) { + sys->write(fdctl,rawoff,6); + return (0, nil); + } + } + break; + } + else { + if(mode == "rawon"){ + #r = sys->write(stdout, array of byte "*",1); + if(r <= 0) { + sys->write(fdctl,rawoff,6); + return (0, nil); + } + } + } + } + + if(mode == "rawon") + sys->write(fdctl,rawoff,6); + + return (1, line[0:len line - 1]); +} |
