xref: /plan9-contrib/sys/src/cmd/auth/debug.c (revision 453ee12c5ca2e4fdd97e94dd56f9cc72c0d42ba4)
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);
1182ebbfa15SDavid du Colombier 		proto = _strfindattr(a, "proto");
1193ff48bf5SDavid du Colombier 		if(proto==nil || strcmp(proto, "p9sk1")!=0)
1203ff48bf5SDavid du Colombier 			continue;
1212ebbfa15SDavid 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 		}
1272ebbfa15SDavid 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;
14657837e0bSDavid du Colombier 	char *server;
1473ff48bf5SDavid du Colombier 	char *addr;
1483ff48bf5SDavid du Colombier 
1493ff48bf5SDavid du Colombier 	fd = authdial(nil, dom);
1503ff48bf5SDavid du Colombier 	if(fd >= 0){
1513ff48bf5SDavid du Colombier 		print("\tsuccessfully dialed auth server\n");
1523ff48bf5SDavid du Colombier 		close(fd);
1533ff48bf5SDavid du Colombier 		authfutz(dom, user);
1543ff48bf5SDavid du Colombier 		return;
1553ff48bf5SDavid du Colombier 	}
1563ff48bf5SDavid du Colombier 	print("\tcannot dial auth server: %r\n");
15757837e0bSDavid du Colombier 	server = csgetvalue(nil, "authdom", dom, "auth", nil);
15857837e0bSDavid du Colombier 	if(server){
1593ff48bf5SDavid du Colombier 		print("\tcsquery authdom=%q auth=%s\n", dom, server);
16057837e0bSDavid du Colombier 		free(server);
1613ff48bf5SDavid du Colombier 		return;
1623ff48bf5SDavid du Colombier 	}
1633ff48bf5SDavid du Colombier 	print("\tcsquery authdom=%q auth=* failed\n", dom);
16457837e0bSDavid du Colombier 	server = csgetvalue(nil, "dom", dom, "auth", nil);
16557837e0bSDavid du Colombier 	if(server){
1663ff48bf5SDavid du Colombier 		print("\tcsquery dom=%q auth=%q\n", dom, server);
16757837e0bSDavid du Colombier 		free(server);
1683ff48bf5SDavid du Colombier 		return;
1693ff48bf5SDavid du Colombier 	}
17057837e0bSDavid du Colombier 	print("\tcsquery dom=%q auth=*\n", dom);
1713ff48bf5SDavid du Colombier 
17257837e0bSDavid du Colombier 	fd = dial(addr=netmkaddr("$auth", nil, "ticket"), 0, 0, 0);
1733ff48bf5SDavid du Colombier 	if(fd >= 0){
1743ff48bf5SDavid du Colombier 		print("\tdial %s succeeded\n", addr);
1753ff48bf5SDavid du Colombier 		close(fd);
1763ff48bf5SDavid du Colombier 		return;
1773ff48bf5SDavid du Colombier 	}
1783ff48bf5SDavid du Colombier 	print("\tdial %s failed: %r\n", addr);
1793ff48bf5SDavid du Colombier }
1803ff48bf5SDavid du Colombier 
1813ff48bf5SDavid du Colombier void
1823ff48bf5SDavid du Colombier authfutz(char *dom, char *user)
1833ff48bf5SDavid du Colombier {
1843ff48bf5SDavid du Colombier 	int fd, nobootes;
1853ff48bf5SDavid du Colombier 	char pw[128], prompt[128], key[DESKEYLEN], booteskey[DESKEYLEN], tbuf[2*TICKETLEN],
1863ff48bf5SDavid du Colombier 		trbuf[TICKREQLEN];
1873ff48bf5SDavid du Colombier 	Ticket t;
1883ff48bf5SDavid du Colombier 	Ticketreq tr;
1893ff48bf5SDavid du Colombier 
1903ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", user, dom);
1913ff48bf5SDavid du Colombier 	readcons(prompt, nil, 1, pw, sizeof pw);
1923ff48bf5SDavid du Colombier 	if(pw[0] == '\0')
1933ff48bf5SDavid du Colombier 		return;
1943ff48bf5SDavid du Colombier 	passtokey(key, pw);
1953ff48bf5SDavid du Colombier 
1963ff48bf5SDavid du Colombier 	fd = authdial(nil, dom);
1973ff48bf5SDavid du Colombier 	if(fd < 0){
1983ff48bf5SDavid du Colombier 		print("\tauthdial failed(!): %r\n");
1993ff48bf5SDavid du Colombier 		return;
2003ff48bf5SDavid du Colombier 	}
2013ff48bf5SDavid du Colombier 
2023ff48bf5SDavid du Colombier 	/* try ticket request using just user key */
2033ff48bf5SDavid du Colombier 	tr.type = AuthTreq;
2043ff48bf5SDavid du Colombier 	strecpy(tr.authid, tr.authid+sizeof tr.authid, user);
2053ff48bf5SDavid du Colombier 	strecpy(tr.authdom, tr.authdom+sizeof tr.authdom, dom);
2063ff48bf5SDavid du Colombier 	strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
2073ff48bf5SDavid du Colombier 	strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
2083ff48bf5SDavid du Colombier 	memset(tr.chal, 0xAA, sizeof tr.chal);
2093ff48bf5SDavid du Colombier 	convTR2M(&tr, trbuf);
2103ff48bf5SDavid du Colombier 	if(_asgetticket(fd, trbuf, tbuf) < 0){
2113ff48bf5SDavid du Colombier 		close(fd);
2123ff48bf5SDavid du Colombier 		print("\t_asgetticket failed: %r\n");
2133ff48bf5SDavid du Colombier 		return;
2143ff48bf5SDavid du Colombier 	}
2153ff48bf5SDavid du Colombier 	convM2T(tbuf, &t, key);
2163ff48bf5SDavid du Colombier 	if(t.num != AuthTc){
2173ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
2183ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
2193ff48bf5SDavid du Colombier 		return;
2203ff48bf5SDavid du Colombier 	}
2213ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2223ff48bf5SDavid du Colombier 		print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
2233ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2243ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2253ff48bf5SDavid du Colombier 		return;
2263ff48bf5SDavid du Colombier 	}
2273ff48bf5SDavid du Colombier 
2283ff48bf5SDavid du Colombier 	convM2T(tbuf+TICKETLEN, &t, key);
2293ff48bf5SDavid du Colombier 	if(t.num != AuthTs){
2303ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
2313ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
2323ff48bf5SDavid du Colombier 		return;
2333ff48bf5SDavid du Colombier 	}
2343ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2353ff48bf5SDavid du Colombier 		print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
2363ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2373ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2383ff48bf5SDavid du Colombier 		return;
2393ff48bf5SDavid du Colombier 	}
2403ff48bf5SDavid du Colombier 	print("\tticket request using %s@%s key succeeded\n", user, dom);
2413ff48bf5SDavid du Colombier 
2423ff48bf5SDavid du Colombier 	/* try ticket request using bootes key */
2433ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
2443ff48bf5SDavid du Colombier 	readcons(prompt, "bootes", 0, tr.authid, sizeof tr.authid);
2453ff48bf5SDavid du Colombier 	convTR2M(&tr, trbuf);
2463ff48bf5SDavid du Colombier 	if(_asgetticket(fd, trbuf, tbuf) < 0){
2473ff48bf5SDavid du Colombier 		close(fd);
2483ff48bf5SDavid du Colombier 		print("\t_asgetticket failed: %r\n");
2493ff48bf5SDavid du Colombier 		return;
2503ff48bf5SDavid du Colombier 	}
2513ff48bf5SDavid du Colombier 	convM2T(tbuf, &t, key);
2523ff48bf5SDavid du Colombier 	if(t.num != AuthTc){
2533ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
2543ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
2553ff48bf5SDavid du Colombier 		return;
2563ff48bf5SDavid du Colombier 	}
2573ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2583ff48bf5SDavid du Colombier 		print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
2593ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2603ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2613ff48bf5SDavid du Colombier 		return;
2623ff48bf5SDavid du Colombier 	}
2633ff48bf5SDavid du Colombier 
2643ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom);
2653ff48bf5SDavid du Colombier 	readcons(prompt, nil, 1, pw, sizeof pw);
2663ff48bf5SDavid du Colombier 	if(pw[0] == '\0'){
2673ff48bf5SDavid du Colombier 		nobootes=1;
2683ff48bf5SDavid du Colombier 		goto Nobootes;
2693ff48bf5SDavid du Colombier 	}
2703ff48bf5SDavid du Colombier 	nobootes = 0;
2713ff48bf5SDavid du Colombier 	passtokey(booteskey, pw);
2723ff48bf5SDavid du Colombier 
2733ff48bf5SDavid du Colombier 	convM2T(tbuf+TICKETLEN, &t, booteskey);
2743ff48bf5SDavid du Colombier 	if(t.num != AuthTs){
2753ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
2763ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", tr.authid, dom);
2773ff48bf5SDavid du Colombier 		return;
2783ff48bf5SDavid du Colombier 	}
2793ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
2803ff48bf5SDavid du Colombier 		print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
2813ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
2823ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
2833ff48bf5SDavid du Colombier 		return;
2843ff48bf5SDavid du Colombier 	}
2853ff48bf5SDavid du Colombier 	print("\tticket request using %s@%s key succeeded\n", tr.authid, dom);
2863ff48bf5SDavid du Colombier 
2873ff48bf5SDavid du Colombier Nobootes:;
288*453ee12cSDavid du Colombier 	USED(nobootes);
2893ff48bf5SDavid du Colombier 
2903ff48bf5SDavid du Colombier 	/* try p9sk1 exchange with local factotum to test that key is right */
2913ff48bf5SDavid du Colombier 
2923ff48bf5SDavid du Colombier 
2933ff48bf5SDavid du Colombier 	/*
2943ff48bf5SDavid du Colombier 	 * try p9sk1 exchange with factotum on
2953ff48bf5SDavid du Colombier 	 * auth server (assumes running cpu service)
2963ff48bf5SDavid du Colombier 	 * to test that bootes key is right over there
2973ff48bf5SDavid du Colombier 	 */
2983ff48bf5SDavid du Colombier 
2993ff48bf5SDavid du Colombier }
3003ff48bf5SDavid du Colombier 
3013ff48bf5SDavid du Colombier void
3023ff48bf5SDavid du Colombier main(int argc, char **argv)
3033ff48bf5SDavid du Colombier {
3043ff48bf5SDavid du Colombier 	quotefmtinstall();
3053ff48bf5SDavid du Colombier 	fmtinstall('A', _attrfmt);
3063ff48bf5SDavid du Colombier 	fmtinstall('H', encodefmt);
3073ff48bf5SDavid du Colombier 
3083ff48bf5SDavid du Colombier 	ARGBEGIN{
3093ff48bf5SDavid du Colombier 	default:
3103ff48bf5SDavid du Colombier 		usage();
3113ff48bf5SDavid du Colombier 	}ARGEND
3123ff48bf5SDavid du Colombier 
3133ff48bf5SDavid du Colombier 	if(argc != 0)
3143ff48bf5SDavid du Colombier 		usage();
3153ff48bf5SDavid du Colombier 
3163ff48bf5SDavid du Colombier 	debugfactotumkeys();
3173ff48bf5SDavid du Colombier }
318