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