implement Convpasswd; include "sys.m"; sys: Sys; include "draw.m"; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "keyring.m"; keyring: Keyring; IPint: import keyring; include "security.m"; include "arg.m"; Convpasswd: module { init: fn(nil: ref Draw->Context, nil: list of string); }; PW: adt { id: string; # user id pw: array of byte; # password hashed by SHA expire: int; # expiration time (epoch seconds) other: string; # about the account }; mntpt := "/mnt/keys"; init(nil: ref Draw->Context, args: list of string) { sys = load Sys Sys->PATH; keyring = load Keyring Keyring->PATH; bufio = load Bufio Bufio->PATH; if(bufio == nil) noload(Arg->PATH); arg := load Arg Arg->PATH; if(arg == nil) noload(Arg->PATH); force := 0; verbose := 0; arg->init(args); arg->setusage("convpasswd [-f] [-v] [-m /mnt/keys] [passwordfile]"); while((o := arg->opt()) != 0) case o { 'f' => force = 1; 'm' => mntpt = arg->earg(); 'v' => verbose = 1; * => arg->usage(); } args = arg->argv(); arg = nil; f := "/keydb/password"; if(args != nil) f = hd args; iob := bufio->open(f, Bufio->OREAD); if(iob == nil) error(sys->sprint("%s: %r", f)); for(line := 1; (s := iob.gets('\n')) != nil; line++) { (n, tokl) := sys->tokenize(s, ":\n"); if (n < 3){ sys->fprint(sys->fildes(2), "convpasswd: %s:%d: invalid format\n", f, line); continue; } pw := ref PW; pw.id = hd tokl; pw.pw = IPint.b64toip(hd tl tokl).iptobytes(); pw.expire = int hd tl tl tokl; if (n==3) pw.other = nil; else pw.other = hd tl tl tl tokl; err := writekey(pw, force); if(err != nil) error(sys->sprint("error writing /mnt/keys entry for %s: %s", pw.id, err)); if(verbose) sys->print("%s\n", pw.id); } } noload(p: string) { error(sys->sprint("can't load %s: %r", p)); } error(s: string) { sys->fprint(sys->fildes(2), "convpasswd: %s\n", s); raise "fail:error"; } writekey(pw: ref PW, force: int): string { dir := mntpt+"/"+pw.id; if(sys->open(dir, Sys->OREAD) == nil){ # make it d := sys->create(dir, Sys->OREAD, Sys->DMDIR|8r600); if(d == nil) return sys->sprint("can't create %s: %r", dir); }else if(!force) return nil; # leave existing entry alone secret := dir+"/secret"; fd := sys->open(secret, Sys->OWRITE); if(fd == nil) return sys->sprint("can't open %s: %r", secret); if(sys->write(fd, pw.pw, len pw.pw) != len pw.pw) return sys->sprint("error writing %s: %r", secret); expire := dir+"/expire"; fd = sys->open(expire, Sys->OWRITE); if(fd == nil) return sys->sprint("can't open %s: %r", expire); if(sys->fprint(fd, "%d", pw.expire) < 0) return sys->sprint("error writing %s: %r", expire); # no equivalent of `other' return nil; }