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); 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, 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);} 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]);}
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);
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, 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);
}
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]);
}