1implement Logind; 2 3# 4# certification service (signer) 5# 6 7include "sys.m"; 8 sys: Sys; 9 10include "draw.m"; 11 12include "keyring.m"; 13 kr: Keyring; 14 IPint: import kr; 15 16include "security.m"; 17 ssl: SSL; 18 19include "daytime.m"; 20 daytime: Daytime; 21 22Logind: module 23{ 24 init: fn(ctxt: ref Draw->Context, argv: list of string); 25}; 26 27TimeLimit: con 5*60*1000; # five minutes 28keydb := "/mnt/keys"; 29 30stderr: ref Sys->FD; 31 32init(nil: ref Draw->Context, nil: list of string) 33{ 34 sys = load Sys Sys->PATH; 35 stderr = sys->open("/dev/cons", sys->OWRITE); 36 37 kr = load Keyring Keyring->PATH; 38 39 ssl = load SSL SSL->PATH; 40 if(ssl == nil) 41 nomod(SSL->PATH); 42 43 daytime = load Daytime Daytime->PATH; 44 if(daytime == nil) 45 nomod(Daytime->PATH); 46 47 (err, c) := ssl->connect(sys->fildes(0)); 48 if(c == nil) 49 fatal("pushing ssl: " + err); 50 51 # impose time out to ensure dead network connections recovered well before TCP/IP's long time out 52 53 grpid := sys->pctl(Sys->NEWPGRP,nil); 54 pidc := chan of int; 55 spawn stalker(pidc, grpid); 56 tpid := <-pidc; 57 err = dologin(c); 58 if(err != nil){ 59 sys->fprint(stderr, "logind: %s\n", err); 60 kr->puterror(c.dfd, err); 61 } 62 kill(tpid, "kill"); 63} 64 65dologin(c: ref Sys->Connection): string 66{ 67 ivec: array of byte; 68 69 (info, err) := signerkey("/keydb/signerkey"); 70 if(info == nil) 71 return "can't read signer's own key: "+err; 72 73 # get user name; ack 74 s: string; 75 (s, err) = kr->getstring(c.dfd); 76 if(err != nil) 77 return err; 78 name := s; 79 kr->putstring(c.dfd, name); 80 81 # get initialization vector 82 (ivec, err) = kr->getbytearray(c.dfd); 83 if(err != nil) 84 return "can't get initialization vector: "+err; 85 86 # lookup password 87 pw := getsecret(s); 88 if(pw == nil) 89 return sys->sprint("no password entry for %s: %r", s); 90 if(len pw < Keyring->SHA1dlen) 91 return "bad password for "+s+": not SHA1 hashed?"; 92 userexp := getexpiry(s); 93 if(userexp < 0) 94 return sys->sprint("expiry time for %s: %r", s); 95 96 # generate our random diffie hellman part 97 bits := info.p.bits(); 98 r0 := kr->IPint.random(bits/4, bits); 99 100 # generate alpha0 = alpha**r0 mod p 101 alphar0 := info.alpha.expmod(r0, info.p); 102 103 # start encrypting 104 pwbuf := array[8] of byte; 105 for(i := 0; i < 8; i++) 106 pwbuf[i] = pw[i] ^ pw[8+i]; 107 for(i = 0; i < 4; i++) 108 pwbuf[i] ^= pw[16+i]; 109 for(i = 0; i < 8; i++) 110 pwbuf[i] ^= ivec[i]; 111 err = ssl->secret(c, pwbuf, pwbuf); 112 if(err != nil) 113 return "can't set ssl secret: "+err; 114 115 if(sys->fprint(c.cfd, "alg rc4") < 0) 116 return sys->sprint("can't push alg rc4: %r"); 117 118 # send P(alpha**r0 mod p) 119 if(kr->putstring(c.dfd, alphar0.iptob64()) < 0) 120 return sys->sprint("can't send (alpha**r0 mod p): %r"); 121 122 # stop encrypting 123 if(sys->fprint(c.cfd, "alg clear") < 0) 124 return sys->sprint("can't clear alg: %r"); 125 126 # send alpha, p 127 if(kr->putstring(c.dfd, info.alpha.iptob64()) < 0 || 128 kr->putstring(c.dfd, info.p.iptob64()) < 0) 129 return sys->sprint("can't send alpha, p: %r"); 130 131 # get alpha**r1 mod p 132 (s, err) = kr->getstring(c.dfd); 133 if(err != nil) 134 return "can't get alpha**r1 mod p:"+err; 135 alphar1 := kr->IPint.b64toip(s); 136 137 # compute alpha**(r0*r1) mod p 138 alphar0r1 := alphar1.expmod(r0, info.p); 139 140 # turn on digesting 141 secret := alphar0r1.iptobytes(); 142 err = ssl->secret(c, secret, secret); 143 if(err != nil) 144 return "can't set digest secret: "+err; 145 if(sys->fprint(c.cfd, "alg sha1") < 0) 146 return sys->sprint("can't push alg sha1: %r"); 147 148 # send our public key 149 if(kr->putstring(c.dfd, kr->pktostr(kr->sktopk(info.mysk))) < 0) 150 return sys->sprint("can't send signer's public key: %r"); 151 152 # get his public key 153 (s, err) = kr->getstring(c.dfd); 154 if(err != nil) 155 return "client public key: "+err; 156 hisPKbuf := array of byte s; 157 hisPK := kr->strtopk(s); 158 if(hisPK.owner != name) 159 return "pk name doesn't match user name"; 160 161 # sign and return 162 state := kr->sha1(hisPKbuf, len hisPKbuf, nil, nil); 163 cert := kr->sign(info.mysk, userexp, state, "sha1"); 164 165 if(kr->putstring(c.dfd, kr->certtostr(cert)) < 0) 166 return sys->sprint("can't send certificate: %r"); 167 168 return nil; 169} 170 171nomod(mod: string) 172{ 173 fatal(sys->sprint("can't load %s: %r",mod)); 174} 175 176fatal(msg: string) 177{ 178 sys->fprint(stderr, "logind: %s\n", msg); 179 exit; 180} 181 182signerkey(filename: string): (ref Keyring->Authinfo, string) 183{ 184 185 info := kr->readauthinfo(filename); 186 if(info == nil) 187 return (nil, sys->sprint("readauthinfo %r")); 188 189 # validate signer key 190 now := daytime->now(); 191 if(info.cert.exp != 0 && info.cert.exp < now) 192 return (nil, sys->sprint("signer key expired")); 193 194 return (info, nil); 195} 196 197getsecret(id: string): array of byte 198{ 199 fd := sys->open(sys->sprint("%s/%s/secret", keydb, id), Sys->OREAD); 200 if(fd == nil) 201 return nil; 202 (ok, d) := sys->fstat(fd); 203 if(ok < 0) 204 return nil; 205 a := array[int d.length] of byte; 206 n := sys->read(fd, a, len a); 207 if(n < 0) 208 return nil; 209 return a[0:n]; 210} 211 212getexpiry(id: string): int 213{ 214 fd := sys->open(sys->sprint("%s/%s/expire", keydb, id), Sys->OREAD); 215 if(fd == nil) 216 return -1; 217 a := array[Sys->NAMEMAX] of byte; 218 n := sys->read(fd, a, len a); 219 if(n < 0) 220 return -1; 221 s := string a[0:n]; 222 if(s == "never") 223 return 0; 224 if(s == "expired"){ 225 sys->werrstr(sys->sprint("entry for %s expired", id)); 226 return -1; 227 } 228 return int s; 229} 230 231stalker(pidc: chan of int, killpid: int) 232{ 233 pidc <-= sys->pctl(0, nil); 234 sys->sleep(TimeLimit); 235 sys->fprint(stderr, "logind: login timed out\n"); 236 kill(killpid, "killgrp"); 237} 238 239kill(pid: int, how: string) 240{ 241 fd := sys->open("#p/" + string pid + "/ctl", Sys->OWRITE); 242 if(fd == nil || sys->fprint(fd, "%s", how) < 0) 243 sys->fprint(stderr, "logind: can't %s %d: %r\n", how, pid); 244} 245