137da2899SCharles.Forsythimplement Logind; 237da2899SCharles.Forsyth 337da2899SCharles.Forsyth# 437da2899SCharles.Forsyth# certification service (signer) 537da2899SCharles.Forsyth# 637da2899SCharles.Forsyth 737da2899SCharles.Forsythinclude "sys.m"; 837da2899SCharles.Forsyth sys: Sys; 937da2899SCharles.Forsyth 1037da2899SCharles.Forsythinclude "draw.m"; 1137da2899SCharles.Forsyth 1237da2899SCharles.Forsythinclude "keyring.m"; 1337da2899SCharles.Forsyth kr: Keyring; 1437da2899SCharles.Forsyth IPint: import kr; 1537da2899SCharles.Forsyth 16*62d7827bScharles forsythinclude "dial.m"; 17*62d7827bScharles forsyth 1837da2899SCharles.Forsythinclude "security.m"; 1937da2899SCharles.Forsyth ssl: SSL; 2037da2899SCharles.Forsyth 2137da2899SCharles.Forsythinclude "daytime.m"; 2237da2899SCharles.Forsyth daytime: Daytime; 2337da2899SCharles.Forsyth 2437da2899SCharles.ForsythLogind: module 2537da2899SCharles.Forsyth{ 2637da2899SCharles.Forsyth init: fn(ctxt: ref Draw->Context, argv: list of string); 2737da2899SCharles.Forsyth}; 2837da2899SCharles.Forsyth 2937da2899SCharles.ForsythTimeLimit: con 5*60*1000; # five minutes 3037da2899SCharles.Forsythkeydb := "/mnt/keys"; 3137da2899SCharles.Forsyth 3237da2899SCharles.Forsythstderr: ref Sys->FD; 3337da2899SCharles.Forsyth 3437da2899SCharles.Forsythinit(nil: ref Draw->Context, nil: list of string) 3537da2899SCharles.Forsyth{ 3637da2899SCharles.Forsyth sys = load Sys Sys->PATH; 3737da2899SCharles.Forsyth stderr = sys->open("/dev/cons", sys->OWRITE); 3837da2899SCharles.Forsyth 3937da2899SCharles.Forsyth kr = load Keyring Keyring->PATH; 4037da2899SCharles.Forsyth 4137da2899SCharles.Forsyth ssl = load SSL SSL->PATH; 4237da2899SCharles.Forsyth if(ssl == nil) 4337da2899SCharles.Forsyth nomod(SSL->PATH); 4437da2899SCharles.Forsyth 4537da2899SCharles.Forsyth daytime = load Daytime Daytime->PATH; 4637da2899SCharles.Forsyth if(daytime == nil) 4737da2899SCharles.Forsyth nomod(Daytime->PATH); 4837da2899SCharles.Forsyth 4937da2899SCharles.Forsyth (err, c) := ssl->connect(sys->fildes(0)); 5037da2899SCharles.Forsyth if(c == nil) 5137da2899SCharles.Forsyth fatal("pushing ssl: " + err); 5237da2899SCharles.Forsyth 5337da2899SCharles.Forsyth # impose time out to ensure dead network connections recovered well before TCP/IP's long time out 5437da2899SCharles.Forsyth 5537da2899SCharles.Forsyth grpid := sys->pctl(Sys->NEWPGRP,nil); 5637da2899SCharles.Forsyth pidc := chan of int; 5737da2899SCharles.Forsyth spawn stalker(pidc, grpid); 5837da2899SCharles.Forsyth tpid := <-pidc; 5937da2899SCharles.Forsyth err = dologin(c); 6037da2899SCharles.Forsyth if(err != nil){ 6137da2899SCharles.Forsyth sys->fprint(stderr, "logind: %s\n", err); 6237da2899SCharles.Forsyth kr->puterror(c.dfd, err); 6337da2899SCharles.Forsyth } 6437da2899SCharles.Forsyth kill(tpid, "kill"); 6537da2899SCharles.Forsyth} 6637da2899SCharles.Forsyth 67*62d7827bScharles forsythdologin(c: ref Dial->Connection): string 6837da2899SCharles.Forsyth{ 6937da2899SCharles.Forsyth ivec: array of byte; 7037da2899SCharles.Forsyth 7137da2899SCharles.Forsyth (info, err) := signerkey("/keydb/signerkey"); 7237da2899SCharles.Forsyth if(info == nil) 7337da2899SCharles.Forsyth return "can't read signer's own key: "+err; 7437da2899SCharles.Forsyth 7537da2899SCharles.Forsyth # get user name; ack 7637da2899SCharles.Forsyth s: string; 7737da2899SCharles.Forsyth (s, err) = kr->getstring(c.dfd); 7837da2899SCharles.Forsyth if(err != nil) 7937da2899SCharles.Forsyth return err; 8037da2899SCharles.Forsyth name := s; 8137da2899SCharles.Forsyth kr->putstring(c.dfd, name); 8237da2899SCharles.Forsyth 8337da2899SCharles.Forsyth # get initialization vector 8437da2899SCharles.Forsyth (ivec, err) = kr->getbytearray(c.dfd); 8537da2899SCharles.Forsyth if(err != nil) 8637da2899SCharles.Forsyth return "can't get initialization vector: "+err; 8737da2899SCharles.Forsyth 8837da2899SCharles.Forsyth # lookup password 8937da2899SCharles.Forsyth pw := getsecret(s); 9037da2899SCharles.Forsyth if(pw == nil) 9137da2899SCharles.Forsyth return sys->sprint("no password entry for %s: %r", s); 9237da2899SCharles.Forsyth if(len pw < Keyring->SHA1dlen) 9337da2899SCharles.Forsyth return "bad password for "+s+": not SHA1 hashed?"; 9437da2899SCharles.Forsyth userexp := getexpiry(s); 9537da2899SCharles.Forsyth if(userexp < 0) 9637da2899SCharles.Forsyth return sys->sprint("expiry time for %s: %r", s); 9737da2899SCharles.Forsyth 9837da2899SCharles.Forsyth # generate our random diffie hellman part 9937da2899SCharles.Forsyth bits := info.p.bits(); 10037da2899SCharles.Forsyth r0 := kr->IPint.random(bits/4, bits); 10137da2899SCharles.Forsyth 10237da2899SCharles.Forsyth # generate alpha0 = alpha**r0 mod p 10337da2899SCharles.Forsyth alphar0 := info.alpha.expmod(r0, info.p); 10437da2899SCharles.Forsyth 10537da2899SCharles.Forsyth # start encrypting 10637da2899SCharles.Forsyth pwbuf := array[8] of byte; 10737da2899SCharles.Forsyth for(i := 0; i < 8; i++) 10837da2899SCharles.Forsyth pwbuf[i] = pw[i] ^ pw[8+i]; 10937da2899SCharles.Forsyth for(i = 0; i < 4; i++) 11037da2899SCharles.Forsyth pwbuf[i] ^= pw[16+i]; 11137da2899SCharles.Forsyth for(i = 0; i < 8; i++) 11237da2899SCharles.Forsyth pwbuf[i] ^= ivec[i]; 11337da2899SCharles.Forsyth err = ssl->secret(c, pwbuf, pwbuf); 11437da2899SCharles.Forsyth if(err != nil) 11537da2899SCharles.Forsyth return "can't set ssl secret: "+err; 11637da2899SCharles.Forsyth 11737da2899SCharles.Forsyth if(sys->fprint(c.cfd, "alg rc4") < 0) 11837da2899SCharles.Forsyth return sys->sprint("can't push alg rc4: %r"); 11937da2899SCharles.Forsyth 12037da2899SCharles.Forsyth # send P(alpha**r0 mod p) 12137da2899SCharles.Forsyth if(kr->putstring(c.dfd, alphar0.iptob64()) < 0) 12237da2899SCharles.Forsyth return sys->sprint("can't send (alpha**r0 mod p): %r"); 12337da2899SCharles.Forsyth 12437da2899SCharles.Forsyth # stop encrypting 12537da2899SCharles.Forsyth if(sys->fprint(c.cfd, "alg clear") < 0) 12637da2899SCharles.Forsyth return sys->sprint("can't clear alg: %r"); 12737da2899SCharles.Forsyth 12837da2899SCharles.Forsyth # send alpha, p 12937da2899SCharles.Forsyth if(kr->putstring(c.dfd, info.alpha.iptob64()) < 0 || 13037da2899SCharles.Forsyth kr->putstring(c.dfd, info.p.iptob64()) < 0) 13137da2899SCharles.Forsyth return sys->sprint("can't send alpha, p: %r"); 13237da2899SCharles.Forsyth 13337da2899SCharles.Forsyth # get alpha**r1 mod p 13437da2899SCharles.Forsyth (s, err) = kr->getstring(c.dfd); 13537da2899SCharles.Forsyth if(err != nil) 13637da2899SCharles.Forsyth return "can't get alpha**r1 mod p:"+err; 13737da2899SCharles.Forsyth alphar1 := kr->IPint.b64toip(s); 13837da2899SCharles.Forsyth 13937da2899SCharles.Forsyth # compute alpha**(r0*r1) mod p 14037da2899SCharles.Forsyth alphar0r1 := alphar1.expmod(r0, info.p); 14137da2899SCharles.Forsyth 14237da2899SCharles.Forsyth # turn on digesting 14337da2899SCharles.Forsyth secret := alphar0r1.iptobytes(); 14437da2899SCharles.Forsyth err = ssl->secret(c, secret, secret); 14537da2899SCharles.Forsyth if(err != nil) 14637da2899SCharles.Forsyth return "can't set digest secret: "+err; 14737da2899SCharles.Forsyth if(sys->fprint(c.cfd, "alg sha1") < 0) 14837da2899SCharles.Forsyth return sys->sprint("can't push alg sha1: %r"); 14937da2899SCharles.Forsyth 15037da2899SCharles.Forsyth # send our public key 15137da2899SCharles.Forsyth if(kr->putstring(c.dfd, kr->pktostr(kr->sktopk(info.mysk))) < 0) 15237da2899SCharles.Forsyth return sys->sprint("can't send signer's public key: %r"); 15337da2899SCharles.Forsyth 15437da2899SCharles.Forsyth # get his public key 15537da2899SCharles.Forsyth (s, err) = kr->getstring(c.dfd); 15637da2899SCharles.Forsyth if(err != nil) 15737da2899SCharles.Forsyth return "client public key: "+err; 15837da2899SCharles.Forsyth hisPKbuf := array of byte s; 15937da2899SCharles.Forsyth hisPK := kr->strtopk(s); 16037da2899SCharles.Forsyth if(hisPK.owner != name) 16137da2899SCharles.Forsyth return "pk name doesn't match user name"; 16237da2899SCharles.Forsyth 16337da2899SCharles.Forsyth # sign and return 16437da2899SCharles.Forsyth state := kr->sha1(hisPKbuf, len hisPKbuf, nil, nil); 16537da2899SCharles.Forsyth cert := kr->sign(info.mysk, userexp, state, "sha1"); 16637da2899SCharles.Forsyth 16737da2899SCharles.Forsyth if(kr->putstring(c.dfd, kr->certtostr(cert)) < 0) 16837da2899SCharles.Forsyth return sys->sprint("can't send certificate: %r"); 16937da2899SCharles.Forsyth 17037da2899SCharles.Forsyth return nil; 17137da2899SCharles.Forsyth} 17237da2899SCharles.Forsyth 17337da2899SCharles.Forsythnomod(mod: string) 17437da2899SCharles.Forsyth{ 17537da2899SCharles.Forsyth fatal(sys->sprint("can't load %s: %r",mod)); 17637da2899SCharles.Forsyth} 17737da2899SCharles.Forsyth 17837da2899SCharles.Forsythfatal(msg: string) 17937da2899SCharles.Forsyth{ 18037da2899SCharles.Forsyth sys->fprint(stderr, "logind: %s\n", msg); 18137da2899SCharles.Forsyth exit; 18237da2899SCharles.Forsyth} 18337da2899SCharles.Forsyth 18437da2899SCharles.Forsythsignerkey(filename: string): (ref Keyring->Authinfo, string) 18537da2899SCharles.Forsyth{ 18637da2899SCharles.Forsyth 18737da2899SCharles.Forsyth info := kr->readauthinfo(filename); 18837da2899SCharles.Forsyth if(info == nil) 18937da2899SCharles.Forsyth return (nil, sys->sprint("readauthinfo %r")); 19037da2899SCharles.Forsyth 19137da2899SCharles.Forsyth # validate signer key 19237da2899SCharles.Forsyth now := daytime->now(); 19337da2899SCharles.Forsyth if(info.cert.exp != 0 && info.cert.exp < now) 19437da2899SCharles.Forsyth return (nil, sys->sprint("signer key expired")); 19537da2899SCharles.Forsyth 19637da2899SCharles.Forsyth return (info, nil); 19737da2899SCharles.Forsyth} 19837da2899SCharles.Forsyth 19937da2899SCharles.Forsythgetsecret(id: string): array of byte 20037da2899SCharles.Forsyth{ 20137da2899SCharles.Forsyth fd := sys->open(sys->sprint("%s/%s/secret", keydb, id), Sys->OREAD); 20237da2899SCharles.Forsyth if(fd == nil) 20337da2899SCharles.Forsyth return nil; 20437da2899SCharles.Forsyth (ok, d) := sys->fstat(fd); 20537da2899SCharles.Forsyth if(ok < 0) 20637da2899SCharles.Forsyth return nil; 20737da2899SCharles.Forsyth a := array[int d.length] of byte; 20837da2899SCharles.Forsyth n := sys->read(fd, a, len a); 20937da2899SCharles.Forsyth if(n < 0) 21037da2899SCharles.Forsyth return nil; 21137da2899SCharles.Forsyth return a[0:n]; 21237da2899SCharles.Forsyth} 21337da2899SCharles.Forsyth 21437da2899SCharles.Forsythgetexpiry(id: string): int 21537da2899SCharles.Forsyth{ 21637da2899SCharles.Forsyth fd := sys->open(sys->sprint("%s/%s/expire", keydb, id), Sys->OREAD); 21737da2899SCharles.Forsyth if(fd == nil) 21837da2899SCharles.Forsyth return -1; 21937da2899SCharles.Forsyth a := array[Sys->NAMEMAX] of byte; 22037da2899SCharles.Forsyth n := sys->read(fd, a, len a); 22137da2899SCharles.Forsyth if(n < 0) 22237da2899SCharles.Forsyth return -1; 22337da2899SCharles.Forsyth s := string a[0:n]; 22437da2899SCharles.Forsyth if(s == "never") 22537da2899SCharles.Forsyth return 0; 22637da2899SCharles.Forsyth if(s == "expired"){ 22737da2899SCharles.Forsyth sys->werrstr(sys->sprint("entry for %s expired", id)); 22837da2899SCharles.Forsyth return -1; 22937da2899SCharles.Forsyth } 23037da2899SCharles.Forsyth return int s; 23137da2899SCharles.Forsyth} 23237da2899SCharles.Forsyth 23337da2899SCharles.Forsythstalker(pidc: chan of int, killpid: int) 23437da2899SCharles.Forsyth{ 23537da2899SCharles.Forsyth pidc <-= sys->pctl(0, nil); 23637da2899SCharles.Forsyth sys->sleep(TimeLimit); 23737da2899SCharles.Forsyth sys->fprint(stderr, "logind: login timed out\n"); 23837da2899SCharles.Forsyth kill(killpid, "killgrp"); 23937da2899SCharles.Forsyth} 24037da2899SCharles.Forsyth 24137da2899SCharles.Forsythkill(pid: int, how: string) 24237da2899SCharles.Forsyth{ 24337da2899SCharles.Forsyth fd := sys->open("#p/" + string pid + "/ctl", Sys->OWRITE); 24437da2899SCharles.Forsyth if(fd == nil || sys->fprint(fd, "%s", how) < 0) 24537da2899SCharles.Forsyth sys->fprint(stderr, "logind: can't %s %d: %r\n", how, pid); 24637da2899SCharles.Forsyth} 247