xref: /plan9/sys/src/cmd/auth/debug.c (revision 2ebbfa15057a80d5ffc355d10c2a61bb0ac12c16)
13ff48bf5SDavid du Colombier /*
23ff48bf5SDavid du Colombier  * Test various aspects of the authentication setup.
33ff48bf5SDavid du Colombier  */
43ff48bf5SDavid du Colombier 
53ff48bf5SDavid du Colombier #include <u.h>
63ff48bf5SDavid du Colombier #include <libc.h>
73ff48bf5SDavid du Colombier #include <bio.h>
83ff48bf5SDavid du Colombier #include <ndb.h>
93ff48bf5SDavid du Colombier #include <auth.h>
103ff48bf5SDavid du Colombier #include <authsrv.h>
113ff48bf5SDavid du Colombier 
123ff48bf5SDavid du Colombier void
133ff48bf5SDavid du Colombier usage(void)
143ff48bf5SDavid du Colombier {
153ff48bf5SDavid du Colombier 	fprint(2, "usage: auth/debug\n");
163ff48bf5SDavid du Colombier 	exits("usage");
173ff48bf5SDavid du Colombier }
183ff48bf5SDavid du Colombier 
193ff48bf5SDavid du Colombier static char*
203ff48bf5SDavid du Colombier readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
213ff48bf5SDavid du Colombier {
223ff48bf5SDavid du Colombier 	int fdin, fdout, ctl, n, m;
233ff48bf5SDavid du Colombier 	char line[10];
243ff48bf5SDavid du Colombier 
253ff48bf5SDavid du Colombier 	fdin = open("/dev/cons", OREAD);
263ff48bf5SDavid du Colombier 	if(fdin < 0)
273ff48bf5SDavid du Colombier 		fdin = 0;
283ff48bf5SDavid du Colombier 	fdout = open("/dev/cons", OWRITE);
293ff48bf5SDavid du Colombier 	if(fdout < 0)
303ff48bf5SDavid du Colombier 		fdout = 1;
313ff48bf5SDavid du Colombier 	if(def != nil)
323ff48bf5SDavid du Colombier 		fprint(fdout, "%s[%s]: ", prompt, def);
333ff48bf5SDavid du Colombier 	else
343ff48bf5SDavid du Colombier 		fprint(fdout, "%s: ", prompt);
353ff48bf5SDavid du Colombier 	if(raw){
363ff48bf5SDavid du Colombier 		ctl = open("/dev/consctl", OWRITE);
373ff48bf5SDavid du Colombier 		if(ctl >= 0)
383ff48bf5SDavid du Colombier 			write(ctl, "rawon", 5);
393ff48bf5SDavid du Colombier 	} else
403ff48bf5SDavid du Colombier 		ctl = -1;
413ff48bf5SDavid du Colombier 
423ff48bf5SDavid du Colombier 	m = 0;
433ff48bf5SDavid du Colombier 	for(;;){
443ff48bf5SDavid du Colombier 		n = read(fdin, line, 1);
453ff48bf5SDavid du Colombier 		if(n == 0){
463ff48bf5SDavid du Colombier 			close(ctl);
473ff48bf5SDavid du Colombier 			werrstr("readcons: EOF");
483ff48bf5SDavid du Colombier 			return nil;
493ff48bf5SDavid du Colombier 		}
503ff48bf5SDavid du Colombier 		if(n < 0){
513ff48bf5SDavid du Colombier 			close(ctl);
523ff48bf5SDavid du Colombier 			werrstr("can't read cons");
533ff48bf5SDavid du Colombier 			return nil;
543ff48bf5SDavid du Colombier 		}
553ff48bf5SDavid du Colombier 		if(line[0] == 0x7f)
563ff48bf5SDavid du Colombier 			exits(0);
573ff48bf5SDavid du Colombier 		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
583ff48bf5SDavid du Colombier 			if(raw){
593ff48bf5SDavid du Colombier 				write(ctl, "rawoff", 6);
603ff48bf5SDavid du Colombier 				write(fdout, "\n", 1);
613ff48bf5SDavid du Colombier 				close(ctl);
623ff48bf5SDavid du Colombier 			}
633ff48bf5SDavid du Colombier 			buf[m] = '\0';
643ff48bf5SDavid du Colombier 			if(buf[0]=='\0' && def)
653ff48bf5SDavid du Colombier 				strcpy(buf, def);
663ff48bf5SDavid du Colombier 			return buf;
673ff48bf5SDavid du Colombier 		}
683ff48bf5SDavid du Colombier 		if(line[0] == '\b'){
693ff48bf5SDavid du Colombier 			if(m > 0)
703ff48bf5SDavid du Colombier 				m--;
713ff48bf5SDavid du Colombier 		}else if(line[0] == 0x15){	/* ^U: line kill */
723ff48bf5SDavid du Colombier 			m = 0;
733ff48bf5SDavid du Colombier 			if(def != nil)
743ff48bf5SDavid du Colombier 				fprint(fdout, "%s[%s]: ", prompt, def);
753ff48bf5SDavid du Colombier 			else
763ff48bf5SDavid du Colombier 				fprint(fdout, "%s: ", prompt);
773ff48bf5SDavid du Colombier 		}else{
783ff48bf5SDavid du Colombier 			if(m >= nbuf-1){
793ff48bf5SDavid du Colombier 				fprint(fdout, "line too long\n");
803ff48bf5SDavid du Colombier 				m = 0;
813ff48bf5SDavid du Colombier 				if(def != nil)
823ff48bf5SDavid du Colombier 					fprint(fdout, "%s[%s]: ", prompt, def);
833ff48bf5SDavid du Colombier 				else
843ff48bf5SDavid du Colombier 					fprint(fdout, "%s: ", prompt);
853ff48bf5SDavid du Colombier 			}else
863ff48bf5SDavid du Colombier 				buf[m++] = line[0];
873ff48bf5SDavid du Colombier 		}
883ff48bf5SDavid du Colombier 	}
893ff48bf5SDavid du Colombier 	return buf;	/* how does this happen */
903ff48bf5SDavid du Colombier }
913ff48bf5SDavid du Colombier 
923ff48bf5SDavid du Colombier void authdialfutz(char*, char*);
933ff48bf5SDavid du Colombier void authfutz(char*, char*);
943ff48bf5SDavid du Colombier 
953ff48bf5SDavid du Colombier /* scan factotum for p9sk1 keys; check them */
963ff48bf5SDavid du Colombier void
973ff48bf5SDavid du Colombier debugfactotumkeys(void)
983ff48bf5SDavid du Colombier {
993ff48bf5SDavid du Colombier 	char *s, *dom, *proto, *user;
1003ff48bf5SDavid du Colombier 	int found;
1013ff48bf5SDavid du Colombier 	Attr *a;
1023ff48bf5SDavid du Colombier 	Biobuf *b;
1033ff48bf5SDavid du Colombier 
1043ff48bf5SDavid du Colombier 	b = Bopen("/mnt/factotum/ctl", OREAD);
1053ff48bf5SDavid du Colombier 	if(b == nil){
1063ff48bf5SDavid du Colombier 		fprint(2, "cannot open /mnt/factotum/ctl");
1073ff48bf5SDavid du Colombier 		return;
1083ff48bf5SDavid du Colombier 	}
1093ff48bf5SDavid du Colombier 	found = 0;
1103ff48bf5SDavid du Colombier 	while((s = Brdstr(b, '\n', 1)) != nil){
1113ff48bf5SDavid du Colombier 		if(strncmp(s, "key ", 4) != 0){
1123ff48bf5SDavid du Colombier 			print("malformed ctl line: %s\n", s);
1133ff48bf5SDavid du Colombier 			free(s);
1143ff48bf5SDavid du Colombier 			continue;
1153ff48bf5SDavid du Colombier 		}
1163ff48bf5SDavid du Colombier 		a = _parseattr(s+4);
1173ff48bf5SDavid du Colombier 		free(s);
118*2ebbfa15SDavid du Colombier 		proto = _strfindattr(a, "proto");
1193ff48bf5SDavid du Colombier 		if(proto==nil || strcmp(proto, "p9sk1")!=0)
1203ff48bf5SDavid du Colombier 			continue;
121*2ebbfa15SDavid du Colombier 		dom = _strfindattr(a, "dom");
1223ff48bf5SDavid du Colombier 		if(dom == nil){
1233ff48bf5SDavid du Colombier 			print("p9sk1 key with no dom: %A\n", a);
1243ff48bf5SDavid du Colombier 			_freeattr(a);
1253ff48bf5SDavid du Colombier 			continue;
1263ff48bf5SDavid du Colombier 		}
127*2ebbfa15SDavid du Colombier 		user = _strfindattr(a, "user");
1283ff48bf5SDavid du Colombier 		if(user == nil){
1293ff48bf5SDavid du Colombier 			print("p9sk1 key with no user: %A\n", a);
1303ff48bf5SDavid du Colombier 			_freeattr(a);
1313ff48bf5SDavid du Colombier 			continue;
1323ff48bf5SDavid du Colombier 		}
1333ff48bf5SDavid du Colombier 		print("p9sk1 key: %A\n", a);
1343ff48bf5SDavid du Colombier 		found = 1;
1353ff48bf5SDavid du Colombier 		authdialfutz(dom, user);
1363ff48bf5SDavid du Colombier 		_freeattr(a);
1373ff48bf5SDavid du Colombier 	}
1383ff48bf5SDavid du Colombier 	if(!found)
1393ff48bf5SDavid du Colombier 		print("no p9sk1 keys found in factotum\n");
1403ff48bf5SDavid du Colombier }
1413ff48bf5SDavid du Colombier 
1423ff48bf5SDavid du Colombier void
1433ff48bf5SDavid du Colombier authdialfutz(char *dom, char *user)
1443ff48bf5SDavid du Colombier {
1453ff48bf5SDavid du Colombier 	int fd;
1463ff48bf5SDavid du Colombier 	Ndbtuple *nt;
1473ff48bf5SDavid du Colombier 	char server[Ndbvlen];
1483ff48bf5SDavid du Colombier 	char *addr;
1493ff48bf5SDavid du Colombier 
1503ff48bf5SDavid du Colombier 	fd = authdial(nil, dom);
1513ff48bf5SDavid du Colombier 	if(fd >= 0){
1523ff48bf5SDavid du Colombier 		print("\tsuccessfully dialed auth server\n");
1533ff48bf5SDavid du Colombier 		close(fd);
1543ff48bf5SDavid du Colombier 		authfutz(dom, user);
1553ff48bf5SDavid du Colombier 		return;
1563ff48bf5SDavid du Colombier 	}
1573ff48bf5SDavid du Colombier 	print("\tcannot dial auth server: %r\n");
1583ff48bf5SDavid du Colombier 	nt = csgetval(nil, "authdom", dom, "auth", server);
1593ff48bf5SDavid du Colombier 	if(nt){
1603ff48bf5SDavid du Colombier 		print("\tcsquery authdom=%q auth=%s\n", dom, server);
1613ff48bf5SDavid du Colombier 		return;
1623ff48bf5SDavid du Colombier 	}
1633ff48bf5SDavid du Colombier 	print("\tcsquery authdom=%q auth=* failed\n", dom);
1643ff48bf5SDavid du Colombier 	nt = csgetval(nil, "dom", dom, "auth", server);
1653ff48bf5SDavid du Colombier 	if(nt){
1663ff48bf5SDavid du Colombier 		print("\tcsquery dom=%q auth=%q\n", dom, server);
1673ff48bf5SDavid du Colombier 		return;
1683ff48bf5SDavid du Colombier 	}
1693ff48bf5SDavid du Colombier 	print("\tcsquery dom=%q auth=%q\n", dom, server);
1703ff48bf5SDavid du Colombier 
1713ff48bf5SDavid du Colombier 	fd = dial(addr=netmkaddr(server, nil, "ticket"), 0, 0, 0);
1723ff48bf5SDavid du Colombier 	if(fd >= 0){
1733ff48bf5SDavid du Colombier 		print("\tdial %s succeeded\n", addr);
1743ff48bf5SDavid du Colombier 		close(fd);
1753ff48bf5SDavid du Colombier 		return;
1763ff48bf5SDavid du Colombier 	}
1773ff48bf5SDavid du Colombier 	print("\tdial %s failed: %r\n", addr);
1783ff48bf5SDavid du Colombier }
1793ff48bf5SDavid du Colombier 
1803ff48bf5SDavid du Colombier void
1813ff48bf5SDavid du Colombier authfutz(char *dom, char *user)
1823ff48bf5SDavid du Colombier {
1833ff48bf5SDavid du Colombier 	int fd, nobootes;
1843ff48bf5SDavid du Colombier 	char pw[128], prompt[128], key[DESKEYLEN], booteskey[DESKEYLEN], tbuf[2*TICKETLEN],
1853ff48bf5SDavid du Colombier 		trbuf[TICKREQLEN];
1863ff48bf5SDavid du Colombier 	Ticket t;
1873ff48bf5SDavid du Colombier 	Ticketreq tr;
1883ff48bf5SDavid du Colombier 
1893ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", user, dom);
1903ff48bf5SDavid du Colombier 	readcons(prompt, nil, 1, pw, sizeof pw);
1913ff48bf5SDavid du Colombier 	if(pw[0] == '\0')
1923ff48bf5SDavid du Colombier 		return;
1933ff48bf5SDavid du Colombier 	passtokey(key, pw);
1943ff48bf5SDavid du Colombier 
1953ff48bf5SDavid du Colombier 	fd = authdial(nil, dom);
1963ff48bf5SDavid du Colombier 	if(fd < 0){
1973ff48bf5SDavid du Colombier 		print("\tauthdial failed(!): %r\n");
1983ff48bf5SDavid du Colombier 		return;
1993ff48bf5SDavid du Colombier 	}
2003ff48bf5SDavid du Colombier 
2013ff48bf5SDavid du Colombier 	/* try ticket request using just user key */
2023ff48bf5SDavid du Colombier 	tr.type = AuthTreq;
2033ff48bf5SDavid du Colombier 	strecpy(tr.authid, tr.authid+sizeof tr.authid, user);
2043ff48bf5SDavid du Colombier 	strecpy(tr.authdom, tr.authdom+sizeof tr.authdom, dom);
2053ff48bf5SDavid du Colombier 	strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
2063ff48bf5SDavid du Colombier 	strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
2073ff48bf5SDavid du Colombier 	memset(tr.chal, 0xAA, sizeof tr.chal);
2083ff48bf5SDavid du Colombier 	convTR2M(&tr, trbuf);
2093ff48bf5SDavid du Colombier 	if(_asgetticket(fd, trbuf, tbuf) < 0){
2103ff48bf5SDavid du Colombier 		close(fd);
2113ff48bf5SDavid du Colombier 		print("\t_asgetticket failed: %r\n");
2123ff48bf5SDavid du Colombier 		return;
2133ff48bf5SDavid du Colombier 	}
2143ff48bf5SDavid du Colombier 	convM2T(tbuf, &t, key);
2153ff48bf5SDavid du Colombier 	if(t.num != AuthTc){
2163ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
2173ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
2183ff48bf5SDavid du Colombier 		return;
2193ff48bf5SDavid du Colombier 	}
2203ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2213ff48bf5SDavid du Colombier 		print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
2223ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2233ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2243ff48bf5SDavid du Colombier 		return;
2253ff48bf5SDavid du Colombier 	}
2263ff48bf5SDavid du Colombier 
2273ff48bf5SDavid du Colombier 	convM2T(tbuf+TICKETLEN, &t, key);
2283ff48bf5SDavid du Colombier 	if(t.num != AuthTs){
2293ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
2303ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
2313ff48bf5SDavid du Colombier 		return;
2323ff48bf5SDavid du Colombier 	}
2333ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2343ff48bf5SDavid du Colombier 		print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
2353ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2363ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2373ff48bf5SDavid du Colombier 		return;
2383ff48bf5SDavid du Colombier 	}
2393ff48bf5SDavid du Colombier 	print("\tticket request using %s@%s key succeeded\n", user, dom);
2403ff48bf5SDavid du Colombier 
2413ff48bf5SDavid du Colombier 	/* try ticket request using bootes key */
2423ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
2433ff48bf5SDavid du Colombier 	readcons(prompt, "bootes", 0, tr.authid, sizeof tr.authid);
2443ff48bf5SDavid du Colombier 	convTR2M(&tr, trbuf);
2453ff48bf5SDavid du Colombier 	if(_asgetticket(fd, trbuf, tbuf) < 0){
2463ff48bf5SDavid du Colombier 		close(fd);
2473ff48bf5SDavid du Colombier 		print("\t_asgetticket failed: %r\n");
2483ff48bf5SDavid du Colombier 		return;
2493ff48bf5SDavid du Colombier 	}
2503ff48bf5SDavid du Colombier 	convM2T(tbuf, &t, key);
2513ff48bf5SDavid du Colombier 	if(t.num != AuthTc){
2523ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
2533ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
2543ff48bf5SDavid du Colombier 		return;
2553ff48bf5SDavid du Colombier 	}
2563ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2573ff48bf5SDavid du Colombier 		print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
2583ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2593ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2603ff48bf5SDavid du Colombier 		return;
2613ff48bf5SDavid du Colombier 	}
2623ff48bf5SDavid du Colombier 
2633ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom);
2643ff48bf5SDavid du Colombier 	readcons(prompt, nil, 1, pw, sizeof pw);
2653ff48bf5SDavid du Colombier 	if(pw[0] == '\0'){
2663ff48bf5SDavid du Colombier 		nobootes=1;
2673ff48bf5SDavid du Colombier 		goto Nobootes;
2683ff48bf5SDavid du Colombier 	}
2693ff48bf5SDavid du Colombier 	nobootes = 0;
2703ff48bf5SDavid du Colombier 	passtokey(booteskey, pw);
2713ff48bf5SDavid du Colombier 
2723ff48bf5SDavid du Colombier 	convM2T(tbuf+TICKETLEN, &t, booteskey);
2733ff48bf5SDavid du Colombier 	if(t.num != AuthTs){
2743ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
2753ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", tr.authid, dom);
2763ff48bf5SDavid du Colombier 		return;
2773ff48bf5SDavid du Colombier 	}
2783ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2793ff48bf5SDavid du Colombier 		print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
2803ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2813ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2823ff48bf5SDavid du Colombier 		return;
2833ff48bf5SDavid du Colombier 	}
2843ff48bf5SDavid du Colombier 	print("\tticket request using %s@%s key succeeded\n", tr.authid, dom);
2853ff48bf5SDavid du Colombier 
2863ff48bf5SDavid du Colombier Nobootes:;
2873ff48bf5SDavid du Colombier 
2883ff48bf5SDavid du Colombier 	/* try p9sk1 exchange with local factotum to test that key is right */
2893ff48bf5SDavid du Colombier 
2903ff48bf5SDavid du Colombier 
2913ff48bf5SDavid du Colombier 	/*
2923ff48bf5SDavid du Colombier 	 * try p9sk1 exchange with factotum on
2933ff48bf5SDavid du Colombier 	 * auth server (assumes running cpu service)
2943ff48bf5SDavid du Colombier 	 * to test that bootes key is right over there
2953ff48bf5SDavid du Colombier 	 */
2963ff48bf5SDavid du Colombier 
2973ff48bf5SDavid du Colombier }
2983ff48bf5SDavid du Colombier 
2993ff48bf5SDavid du Colombier void
3003ff48bf5SDavid du Colombier main(int argc, char **argv)
3013ff48bf5SDavid du Colombier {
3023ff48bf5SDavid du Colombier 	quotefmtinstall();
3033ff48bf5SDavid du Colombier 	fmtinstall('A', _attrfmt);
3043ff48bf5SDavid du Colombier 	fmtinstall('H', encodefmt);
3053ff48bf5SDavid du Colombier 
3063ff48bf5SDavid du Colombier 	ARGBEGIN{
3073ff48bf5SDavid du Colombier 	default:
3083ff48bf5SDavid du Colombier 		usage();
3093ff48bf5SDavid du Colombier 	}ARGEND
3103ff48bf5SDavid du Colombier 
3113ff48bf5SDavid du Colombier 	if(argc != 0)
3123ff48bf5SDavid du Colombier 		usage();
3133ff48bf5SDavid du Colombier 
3143ff48bf5SDavid du Colombier 	debugfactotumkeys();
3153ff48bf5SDavid du Colombier }
316