xref: /inferno-os/appl/cmd/auth/logind.b (revision 62d7827bc358c000db9ff48fe61bd28ac352a884)
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