implement Getauthinfo; # # get and save a certificate from a signer in exchange for a valid secret # include "sys.m"; sys: Sys; stderr: ref Sys->FD; include "draw.m"; include "keyring.m"; keyring: Keyring; IPint: import keyring; include "security.m"; login: Login; include "sexprs.m"; sexprs: Sexprs; Sexp: import sexprs; include "string.m"; str: String; include "arg.m"; include "bufio.m"; Getauthinfo: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; stderr = sys->fildes(2); arg := load Arg Arg->PATH; if (arg == nil) nomod(Arg->PATH); keyring = load Keyring Keyring->PATH; if(keyring == nil) nomod(Keyring->PATH); str = load String String->PATH; if(str == nil) nomod(String->PATH); login = load Login Login->PATH; if(login == nil) nomod(Login->PATH); sexprs = load Sexprs Sexprs->PATH; if(sexprs == nil) nomod(Sexprs->PATH); sexprs->init(); signer := "$SIGNER"; authname := user(); password := ""; havepw := 0; factotum := 0; showkey := 0; attrs: string; keyfile: string; arg->init(argv); arg->setusage("getauthinfo [-fF] [-s signer] [-u user] [-p password] [-k attrs] [keyfile]"); while ((opt := arg->opt()) != 0){ case opt { 's' => signer = arg->earg(); 'u' => authname = arg->earg(); 'p' => password = arg->earg(); havepw = 1; 'f' => factotum = 1; 'F' => factotum = 1; showkey = 1; 'k' => attrs = arg->earg(); * => arg->usage(); } } facfd: ref Sys->FD; argv = arg->argv(); if (argv != nil && factotum || len argv != 1 && !factotum) arg->usage(); if (factotum){ if(showkey) facfd = sys->fildes(1); else if((facfd = sys->open("/mnt/factotum/ctl", Sys->OWRITE)) == nil) sys->fprint(stderr, "getauthinfo: cannot open factotum: %r\n"); }else keyfile = hd argv; if(!havepw) password = readpassword(); (err, info) := login->login(authname, password, netmkaddr(signer, "net", "inflogin")); if(err != nil){ sys->fprint(stderr, "getauthinfo: failed to authenticate: %s\n", err); raise "fail:login failed"; } if(factotum){ if(sys->fprint(facfd, "key proto=infauth role=client !authinfo=%s user=%s signer=%s %s\n", authinfotostr(info), authname, signer, attrs) == -1){ sys->fprint(stderr, "getauthinfo: cannot write key to factotum: %r\n"); raise "fail:cannot write key"; } if(sys->fprint(facfd, "key proto=infauth role=server !authinfo=%s user=%s signer=%s %s\n", authinfotostr(info), authname, signer, attrs) == -1){ sys->fprint(stderr, "getauthinfo: cannot write key to factotum: %r\n"); raise "fail:cannot write key"; } }else{ if (! (keyfile[0] == '/' || (len keyfile > 2 && keyfile[0:2] == "./"))) keyfile = "/usr/" + user() + "/keyring/" + keyfile; # write to /keyring if user directory doesn't exist. if(keyring->writeauthinfo(keyfile, info) < 0){ sys->fprint(stderr, "getauthinfo: can't write certificate to %s: %r\n", keyfile); raise "fail:bad file"; } } } user(): string { if ((fd := sys->open("/dev/user", sys->OREAD)) == nil) return nil; buf := array[128] of byte; if ((n := sys->read(fd, buf, len buf)) <= 0) return nil; return string buf[0:n]; } nomod(s: string) { sys->fprint(stderr, "getauthinfo: can't load %s: %r\n", s); raise "fail:load"; } readpassword(): string { bufio := load Bufio Bufio->PATH; Iobuf: import bufio; stdin := bufio->fopen(sys->fildes(0), Sys->OREAD); cfd := sys->open("/dev/consctl", Sys->OWRITE); if (cfd == nil || sys->fprint(cfd, "rawon") <= 0) sys->fprint(stderr, "getauthinfo: warning: cannot hide typed password\n"); sys->fprint(stderr, "password: "); s := ""; while ((c := stdin.getc()) >= 0 && c != '\n'){ case c { '\b' => if (len s > 0) s = s[0:len s - 1]; 8r25 => # ^U s = nil; * => s[len s] = c; } } sys->fprint(stderr, "\n"); return s; } 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); } authinfotostr(ai: ref Keyring->Authinfo): string { return (ref Sexp.List( ss(keyring->pktostr(ai.spk)) :: ss(keyring->certtostr(ai.cert)) :: ss(keyring->sktostr(ai.mysk)) :: sb(ai.alpha.iptobytes()) :: sb(ai.p.iptobytes()) :: nil )).b64text(); } ss(s: string): ref Sexp.String { return ref Sexp.String(s, nil); } sb(d: array of byte): ref Sexp.Binary { return ref Sexp.Binary(d, nil); }