1implement Getauthinfo; 2 3# 4# get and save a certificate from a signer in exchange for a valid secret 5# 6 7include "sys.m"; 8 sys: Sys; 9 stdin, stdout, stderr: ref Sys->FD; 10 11include "draw.m"; 12 13include "keyring.m"; 14 kr: Keyring; 15 16include "security.m"; 17 login: Login; 18 19include "string.m"; 20 str: String; 21 22include "promptstring.b"; 23 24Getauthinfo: module 25{ 26 init: fn(ctxt: ref Draw->Context, argv: list of string); 27}; 28 29usage() 30{ 31 sys->fprint(stderr, "usage: getauthinfo {net!hostname | default | /file}\n"); 32 raise "fail:usage"; 33} 34 35init(nil: ref Draw->Context, argv: list of string) 36{ 37 sys = load Sys Sys->PATH; 38 stdin = sys->fildes(0); 39 stdout = sys->fildes(1); 40 stderr = sys->fildes(2); 41 42 # Disable echoing in RAWON mode 43 RAWON_STR = nil; 44 45 argv = tl argv; 46 if(argv == nil) 47 usage(); 48 keyname := hd argv; 49 if(keyname == nil) 50 usage(); 51 52 kr = load Keyring Keyring->PATH; 53 if(kr == nil) 54 nomod(Keyring->PATH); 55 56 str = load String String->PATH; 57 if(str == nil) 58 nomod(String->PATH); 59 60 login = load Login Login->PATH; 61 if(login == nil) 62 nomod(Login->PATH); 63 64 user := user(); 65 path := keyname; 66 if(path[0] != '/' && (len path < 2 || path[0:2] != "./")) 67 path = "/usr/" + user + "/keyring/" + keyname; 68 69 signer := defaultsigner(); 70 if(signer == nil){ 71 sys->fprint(stderr, "getauthinfo: warning: can't get default signer server name\n"); 72 signer = "$SIGNER"; 73 } 74 75 passwd := ""; 76 save := "yes"; 77 for(;;) { 78 signer = promptstring("use signer", signer, RAWOFF); 79 user = promptstring("remote user name", user, RAWOFF); 80 passwd = promptstring("password", passwd, RAWON); 81 82 info := logon(user, passwd, signer, path, save); 83 if(info != nil) 84 break; 85 } 86} 87 88logon(user, passwd, server, path, save: string): ref Keyring->Authinfo 89{ 90 (err, info) := login->login(user, passwd, "net!"+server+"!inflogin"); 91 if(err != nil){ 92 sys->fprint(stderr, "getauthinfo: failed to authenticate: %s\n", err); 93 return nil; 94 } 95 96 # save the info somewhere for later access 97 save = promptstring("save in file", save, RAWOFF); 98 if(save[0] != 'y'){ 99 (dir, file) := str->splitr(path, "/"); 100 if(sys->bind("#s", dir, Sys->MBEFORE) < 0){ 101 sys->fprint(stderr, "getauthinfo: can't bind file channel on %s: %r\n", dir); 102 return nil; 103 } 104 filio := sys->file2chan(dir, file); 105 if(filio == nil) { 106 sys->fprint(stderr, "getauthinfo: can't make file2chan %s: %r\n", path); 107 return nil; 108 } 109 sync := chan of int; 110 spawn infofile(filio, sync); 111 <-sync; 112 } 113 114 if(kr->writeauthinfo(path, info) < 0) { 115 sys->fprint(stderr, "getauthinfo: can't write certificate to %s: %r\n", path); 116 return nil; 117 } 118 119 return info; 120} 121 122user(): string 123{ 124 sys = load Sys Sys->PATH; 125 126 fd := sys->open("/dev/user", sys->OREAD); 127 if(fd == nil) 128 return ""; 129 130 buf := array[128] of byte; 131 n := sys->read(fd, buf, len buf); 132 if(n < 0) 133 return ""; 134 135 return string buf[0:n]; 136} 137 138infofile(fileio: ref Sys->FileIO, sync: chan of int) 139{ 140 infodata := array[0] of byte; 141 142 sys->pctl(Sys->NEWPGRP|Sys->NEWFD, nil); 143 sync <-= 1; 144 145 for(;;) alt { 146 (off, nbytes, nil, rc) := <-fileio.read => 147 if(rc == nil) 148 break; 149 if(off > len infodata){ 150 rc <-= (nil, nil); 151 } else { 152 if(off + nbytes > len infodata) 153 nbytes = len infodata - off; 154 rc <-= (infodata[off:off+nbytes], nil); 155 } 156 157 (off, data, nil, wc) := <-fileio.write => 158 if(wc == nil) 159 break; 160 161 if(off != len infodata){ 162 wc <-= (0, "cannot be rewritten"); 163 } else { 164 nid := array[len infodata+len data] of byte; 165 nid[0:] = infodata; 166 nid[len infodata:] = data; 167 infodata = nid; 168 wc <-= (len data, nil); 169 } 170 data = nil; 171 } 172} 173 174# get default signer server name 175defaultsigner(): string 176{ 177 return "$SIGNER"; 178} 179 180nomod(s: string) 181{ 182 sys->fprint(stderr, "getauthinfo: can't load %s: %r\n", s); 183 raise "fail:load"; 184} 185