xref: /plan9-contrib/sys/src/cmd/auth/debug.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
1*3ff48bf5SDavid du Colombier /*
2*3ff48bf5SDavid du Colombier  * Test various aspects of the authentication setup.
3*3ff48bf5SDavid du Colombier  */
4*3ff48bf5SDavid du Colombier 
5*3ff48bf5SDavid du Colombier #include <u.h>
6*3ff48bf5SDavid du Colombier #include <libc.h>
7*3ff48bf5SDavid du Colombier #include <bio.h>
8*3ff48bf5SDavid du Colombier #include <ndb.h>
9*3ff48bf5SDavid du Colombier #include <auth.h>
10*3ff48bf5SDavid du Colombier #include <authsrv.h>
11*3ff48bf5SDavid du Colombier 
12*3ff48bf5SDavid du Colombier void
13*3ff48bf5SDavid du Colombier usage(void)
14*3ff48bf5SDavid du Colombier {
15*3ff48bf5SDavid du Colombier 	fprint(2, "usage: auth/debug\n");
16*3ff48bf5SDavid du Colombier 	exits("usage");
17*3ff48bf5SDavid du Colombier }
18*3ff48bf5SDavid du Colombier 
19*3ff48bf5SDavid du Colombier static char*
20*3ff48bf5SDavid du Colombier readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
21*3ff48bf5SDavid du Colombier {
22*3ff48bf5SDavid du Colombier 	int fdin, fdout, ctl, n, m;
23*3ff48bf5SDavid du Colombier 	char line[10];
24*3ff48bf5SDavid du Colombier 
25*3ff48bf5SDavid du Colombier 	fdin = open("/dev/cons", OREAD);
26*3ff48bf5SDavid du Colombier 	if(fdin < 0)
27*3ff48bf5SDavid du Colombier 		fdin = 0;
28*3ff48bf5SDavid du Colombier 	fdout = open("/dev/cons", OWRITE);
29*3ff48bf5SDavid du Colombier 	if(fdout < 0)
30*3ff48bf5SDavid du Colombier 		fdout = 1;
31*3ff48bf5SDavid du Colombier 	if(def != nil)
32*3ff48bf5SDavid du Colombier 		fprint(fdout, "%s[%s]: ", prompt, def);
33*3ff48bf5SDavid du Colombier 	else
34*3ff48bf5SDavid du Colombier 		fprint(fdout, "%s: ", prompt);
35*3ff48bf5SDavid du Colombier 	if(raw){
36*3ff48bf5SDavid du Colombier 		ctl = open("/dev/consctl", OWRITE);
37*3ff48bf5SDavid du Colombier 		if(ctl >= 0)
38*3ff48bf5SDavid du Colombier 			write(ctl, "rawon", 5);
39*3ff48bf5SDavid du Colombier 	} else
40*3ff48bf5SDavid du Colombier 		ctl = -1;
41*3ff48bf5SDavid du Colombier 
42*3ff48bf5SDavid du Colombier 	m = 0;
43*3ff48bf5SDavid du Colombier 	for(;;){
44*3ff48bf5SDavid du Colombier 		n = read(fdin, line, 1);
45*3ff48bf5SDavid du Colombier 		if(n == 0){
46*3ff48bf5SDavid du Colombier 			close(ctl);
47*3ff48bf5SDavid du Colombier 			werrstr("readcons: EOF");
48*3ff48bf5SDavid du Colombier 			return nil;
49*3ff48bf5SDavid du Colombier 		}
50*3ff48bf5SDavid du Colombier 		if(n < 0){
51*3ff48bf5SDavid du Colombier 			close(ctl);
52*3ff48bf5SDavid du Colombier 			werrstr("can't read cons");
53*3ff48bf5SDavid du Colombier 			return nil;
54*3ff48bf5SDavid du Colombier 		}
55*3ff48bf5SDavid du Colombier 		if(line[0] == 0x7f)
56*3ff48bf5SDavid du Colombier 			exits(0);
57*3ff48bf5SDavid du Colombier 		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
58*3ff48bf5SDavid du Colombier 			if(raw){
59*3ff48bf5SDavid du Colombier 				write(ctl, "rawoff", 6);
60*3ff48bf5SDavid du Colombier 				write(fdout, "\n", 1);
61*3ff48bf5SDavid du Colombier 				close(ctl);
62*3ff48bf5SDavid du Colombier 			}
63*3ff48bf5SDavid du Colombier 			buf[m] = '\0';
64*3ff48bf5SDavid du Colombier 			if(buf[0]=='\0' && def)
65*3ff48bf5SDavid du Colombier 				strcpy(buf, def);
66*3ff48bf5SDavid du Colombier 			return buf;
67*3ff48bf5SDavid du Colombier 		}
68*3ff48bf5SDavid du Colombier 		if(line[0] == '\b'){
69*3ff48bf5SDavid du Colombier 			if(m > 0)
70*3ff48bf5SDavid du Colombier 				m--;
71*3ff48bf5SDavid du Colombier 		}else if(line[0] == 0x15){	/* ^U: line kill */
72*3ff48bf5SDavid du Colombier 			m = 0;
73*3ff48bf5SDavid du Colombier 			if(def != nil)
74*3ff48bf5SDavid du Colombier 				fprint(fdout, "%s[%s]: ", prompt, def);
75*3ff48bf5SDavid du Colombier 			else
76*3ff48bf5SDavid du Colombier 				fprint(fdout, "%s: ", prompt);
77*3ff48bf5SDavid du Colombier 		}else{
78*3ff48bf5SDavid du Colombier 			if(m >= nbuf-1){
79*3ff48bf5SDavid du Colombier 				fprint(fdout, "line too long\n");
80*3ff48bf5SDavid du Colombier 				m = 0;
81*3ff48bf5SDavid du Colombier 				if(def != nil)
82*3ff48bf5SDavid du Colombier 					fprint(fdout, "%s[%s]: ", prompt, def);
83*3ff48bf5SDavid du Colombier 				else
84*3ff48bf5SDavid du Colombier 					fprint(fdout, "%s: ", prompt);
85*3ff48bf5SDavid du Colombier 			}else
86*3ff48bf5SDavid du Colombier 				buf[m++] = line[0];
87*3ff48bf5SDavid du Colombier 		}
88*3ff48bf5SDavid du Colombier 	}
89*3ff48bf5SDavid du Colombier 	return buf;	/* how does this happen */
90*3ff48bf5SDavid du Colombier }
91*3ff48bf5SDavid du Colombier 
92*3ff48bf5SDavid du Colombier void authdialfutz(char*, char*);
93*3ff48bf5SDavid du Colombier void authfutz(char*, char*);
94*3ff48bf5SDavid du Colombier 
95*3ff48bf5SDavid du Colombier /* scan factotum for p9sk1 keys; check them */
96*3ff48bf5SDavid du Colombier void
97*3ff48bf5SDavid du Colombier debugfactotumkeys(void)
98*3ff48bf5SDavid du Colombier {
99*3ff48bf5SDavid du Colombier 	char *s, *dom, *proto, *user;
100*3ff48bf5SDavid du Colombier 	int found;
101*3ff48bf5SDavid du Colombier 	Attr *a;
102*3ff48bf5SDavid du Colombier 	Biobuf *b;
103*3ff48bf5SDavid du Colombier 
104*3ff48bf5SDavid du Colombier 	b = Bopen("/mnt/factotum/ctl", OREAD);
105*3ff48bf5SDavid du Colombier 	if(b == nil){
106*3ff48bf5SDavid du Colombier 		fprint(2, "cannot open /mnt/factotum/ctl");
107*3ff48bf5SDavid du Colombier 		return;
108*3ff48bf5SDavid du Colombier 	}
109*3ff48bf5SDavid du Colombier 	found = 0;
110*3ff48bf5SDavid du Colombier 	while((s = Brdstr(b, '\n', 1)) != nil){
111*3ff48bf5SDavid du Colombier 		if(strncmp(s, "key ", 4) != 0){
112*3ff48bf5SDavid du Colombier 			print("malformed ctl line: %s\n", s);
113*3ff48bf5SDavid du Colombier 			free(s);
114*3ff48bf5SDavid du Colombier 			continue;
115*3ff48bf5SDavid du Colombier 		}
116*3ff48bf5SDavid du Colombier 		a = _parseattr(s+4);
117*3ff48bf5SDavid du Colombier 		free(s);
118*3ff48bf5SDavid du Colombier 		proto = _str_findattr(a, "proto");
119*3ff48bf5SDavid du Colombier 		if(proto==nil || strcmp(proto, "p9sk1")!=0)
120*3ff48bf5SDavid du Colombier 			continue;
121*3ff48bf5SDavid du Colombier 		dom = _str_findattr(a, "dom");
122*3ff48bf5SDavid du Colombier 		if(dom == nil){
123*3ff48bf5SDavid du Colombier 			print("p9sk1 key with no dom: %A\n", a);
124*3ff48bf5SDavid du Colombier 			_freeattr(a);
125*3ff48bf5SDavid du Colombier 			continue;
126*3ff48bf5SDavid du Colombier 		}
127*3ff48bf5SDavid du Colombier 		user = _str_findattr(a, "user");
128*3ff48bf5SDavid du Colombier 		if(user == nil){
129*3ff48bf5SDavid du Colombier 			print("p9sk1 key with no user: %A\n", a);
130*3ff48bf5SDavid du Colombier 			_freeattr(a);
131*3ff48bf5SDavid du Colombier 			continue;
132*3ff48bf5SDavid du Colombier 		}
133*3ff48bf5SDavid du Colombier 		print("p9sk1 key: %A\n", a);
134*3ff48bf5SDavid du Colombier 		found = 1;
135*3ff48bf5SDavid du Colombier 		authdialfutz(dom, user);
136*3ff48bf5SDavid du Colombier 		_freeattr(a);
137*3ff48bf5SDavid du Colombier 	}
138*3ff48bf5SDavid du Colombier 	if(!found)
139*3ff48bf5SDavid du Colombier 		print("no p9sk1 keys found in factotum\n");
140*3ff48bf5SDavid du Colombier }
141*3ff48bf5SDavid du Colombier 
142*3ff48bf5SDavid du Colombier void
143*3ff48bf5SDavid du Colombier authdialfutz(char *dom, char *user)
144*3ff48bf5SDavid du Colombier {
145*3ff48bf5SDavid du Colombier 	int fd;
146*3ff48bf5SDavid du Colombier 	Ndbtuple *nt;
147*3ff48bf5SDavid du Colombier 	char server[Ndbvlen];
148*3ff48bf5SDavid du Colombier 	char *addr;
149*3ff48bf5SDavid du Colombier 
150*3ff48bf5SDavid du Colombier 	fd = authdial(nil, dom);
151*3ff48bf5SDavid du Colombier 	if(fd >= 0){
152*3ff48bf5SDavid du Colombier 		print("\tsuccessfully dialed auth server\n");
153*3ff48bf5SDavid du Colombier 		close(fd);
154*3ff48bf5SDavid du Colombier 		authfutz(dom, user);
155*3ff48bf5SDavid du Colombier 		return;
156*3ff48bf5SDavid du Colombier 	}
157*3ff48bf5SDavid du Colombier 	print("\tcannot dial auth server: %r\n");
158*3ff48bf5SDavid du Colombier 	nt = csgetval(nil, "authdom", dom, "auth", server);
159*3ff48bf5SDavid du Colombier 	if(nt){
160*3ff48bf5SDavid du Colombier 		print("\tcsquery authdom=%q auth=%s\n", dom, server);
161*3ff48bf5SDavid du Colombier 		return;
162*3ff48bf5SDavid du Colombier 	}
163*3ff48bf5SDavid du Colombier 	print("\tcsquery authdom=%q auth=* failed\n", dom);
164*3ff48bf5SDavid du Colombier 	nt = csgetval(nil, "dom", dom, "auth", server);
165*3ff48bf5SDavid du Colombier 	if(nt){
166*3ff48bf5SDavid du Colombier 		print("\tcsquery dom=%q auth=%q\n", dom, server);
167*3ff48bf5SDavid du Colombier 		return;
168*3ff48bf5SDavid du Colombier 	}
169*3ff48bf5SDavid du Colombier 	print("\tcsquery dom=%q auth=%q\n", dom, server);
170*3ff48bf5SDavid du Colombier 
171*3ff48bf5SDavid du Colombier 	fd = dial(addr=netmkaddr(server, nil, "ticket"), 0, 0, 0);
172*3ff48bf5SDavid du Colombier 	if(fd >= 0){
173*3ff48bf5SDavid du Colombier 		print("\tdial %s succeeded\n", addr);
174*3ff48bf5SDavid du Colombier 		close(fd);
175*3ff48bf5SDavid du Colombier 		return;
176*3ff48bf5SDavid du Colombier 	}
177*3ff48bf5SDavid du Colombier 	print("\tdial %s failed: %r\n", addr);
178*3ff48bf5SDavid du Colombier }
179*3ff48bf5SDavid du Colombier 
180*3ff48bf5SDavid du Colombier void
181*3ff48bf5SDavid du Colombier authfutz(char *dom, char *user)
182*3ff48bf5SDavid du Colombier {
183*3ff48bf5SDavid du Colombier 	int fd, nobootes;
184*3ff48bf5SDavid du Colombier 	char pw[128], prompt[128], key[DESKEYLEN], booteskey[DESKEYLEN], tbuf[2*TICKETLEN],
185*3ff48bf5SDavid du Colombier 		trbuf[TICKREQLEN];
186*3ff48bf5SDavid du Colombier 	Ticket t;
187*3ff48bf5SDavid du Colombier 	Ticketreq tr;
188*3ff48bf5SDavid du Colombier 
189*3ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", user, dom);
190*3ff48bf5SDavid du Colombier 	readcons(prompt, nil, 1, pw, sizeof pw);
191*3ff48bf5SDavid du Colombier 	if(pw[0] == '\0')
192*3ff48bf5SDavid du Colombier 		return;
193*3ff48bf5SDavid du Colombier 	passtokey(key, pw);
194*3ff48bf5SDavid du Colombier 
195*3ff48bf5SDavid du Colombier 	fd = authdial(nil, dom);
196*3ff48bf5SDavid du Colombier 	if(fd < 0){
197*3ff48bf5SDavid du Colombier 		print("\tauthdial failed(!): %r\n");
198*3ff48bf5SDavid du Colombier 		return;
199*3ff48bf5SDavid du Colombier 	}
200*3ff48bf5SDavid du Colombier 
201*3ff48bf5SDavid du Colombier 	/* try ticket request using just user key */
202*3ff48bf5SDavid du Colombier 	tr.type = AuthTreq;
203*3ff48bf5SDavid du Colombier 	strecpy(tr.authid, tr.authid+sizeof tr.authid, user);
204*3ff48bf5SDavid du Colombier 	strecpy(tr.authdom, tr.authdom+sizeof tr.authdom, dom);
205*3ff48bf5SDavid du Colombier 	strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
206*3ff48bf5SDavid du Colombier 	strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
207*3ff48bf5SDavid du Colombier 	memset(tr.chal, 0xAA, sizeof tr.chal);
208*3ff48bf5SDavid du Colombier 	convTR2M(&tr, trbuf);
209*3ff48bf5SDavid du Colombier 	if(_asgetticket(fd, trbuf, tbuf) < 0){
210*3ff48bf5SDavid du Colombier 		close(fd);
211*3ff48bf5SDavid du Colombier 		print("\t_asgetticket failed: %r\n");
212*3ff48bf5SDavid du Colombier 		return;
213*3ff48bf5SDavid du Colombier 	}
214*3ff48bf5SDavid du Colombier 	convM2T(tbuf, &t, key);
215*3ff48bf5SDavid du Colombier 	if(t.num != AuthTc){
216*3ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
217*3ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
218*3ff48bf5SDavid du Colombier 		return;
219*3ff48bf5SDavid du Colombier 	}
220*3ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
221*3ff48bf5SDavid du Colombier 		print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
222*3ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
223*3ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
224*3ff48bf5SDavid du Colombier 		return;
225*3ff48bf5SDavid du Colombier 	}
226*3ff48bf5SDavid du Colombier 
227*3ff48bf5SDavid du Colombier 	convM2T(tbuf+TICKETLEN, &t, key);
228*3ff48bf5SDavid du Colombier 	if(t.num != AuthTs){
229*3ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
230*3ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
231*3ff48bf5SDavid du Colombier 		return;
232*3ff48bf5SDavid du Colombier 	}
233*3ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
234*3ff48bf5SDavid du Colombier 		print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
235*3ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
236*3ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
237*3ff48bf5SDavid du Colombier 		return;
238*3ff48bf5SDavid du Colombier 	}
239*3ff48bf5SDavid du Colombier 	print("\tticket request using %s@%s key succeeded\n", user, dom);
240*3ff48bf5SDavid du Colombier 
241*3ff48bf5SDavid du Colombier 	/* try ticket request using bootes key */
242*3ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
243*3ff48bf5SDavid du Colombier 	readcons(prompt, "bootes", 0, tr.authid, sizeof tr.authid);
244*3ff48bf5SDavid du Colombier 	convTR2M(&tr, trbuf);
245*3ff48bf5SDavid du Colombier 	if(_asgetticket(fd, trbuf, tbuf) < 0){
246*3ff48bf5SDavid du Colombier 		close(fd);
247*3ff48bf5SDavid du Colombier 		print("\t_asgetticket failed: %r\n");
248*3ff48bf5SDavid du Colombier 		return;
249*3ff48bf5SDavid du Colombier 	}
250*3ff48bf5SDavid du Colombier 	convM2T(tbuf, &t, key);
251*3ff48bf5SDavid du Colombier 	if(t.num != AuthTc){
252*3ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
253*3ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
254*3ff48bf5SDavid du Colombier 		return;
255*3ff48bf5SDavid du Colombier 	}
256*3ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
257*3ff48bf5SDavid du Colombier 		print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
258*3ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
259*3ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
260*3ff48bf5SDavid du Colombier 		return;
261*3ff48bf5SDavid du Colombier 	}
262*3ff48bf5SDavid du Colombier 
263*3ff48bf5SDavid du Colombier 	snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom);
264*3ff48bf5SDavid du Colombier 	readcons(prompt, nil, 1, pw, sizeof pw);
265*3ff48bf5SDavid du Colombier 	if(pw[0] == '\0'){
266*3ff48bf5SDavid du Colombier 		nobootes=1;
267*3ff48bf5SDavid du Colombier 		goto Nobootes;
268*3ff48bf5SDavid du Colombier 	}
269*3ff48bf5SDavid du Colombier 	nobootes = 0;
270*3ff48bf5SDavid du Colombier 	passtokey(booteskey, pw);
271*3ff48bf5SDavid du Colombier 
272*3ff48bf5SDavid du Colombier 	convM2T(tbuf+TICKETLEN, &t, booteskey);
273*3ff48bf5SDavid du Colombier 	if(t.num != AuthTs){
274*3ff48bf5SDavid du Colombier 		print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
275*3ff48bf5SDavid du Colombier 		print("\tauth server and you do not agree on key for %s@%s\n", tr.authid, dom);
276*3ff48bf5SDavid du Colombier 		return;
277*3ff48bf5SDavid du Colombier 	}
278*3ff48bf5SDavid du Colombier 	if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
279*3ff48bf5SDavid du Colombier 		print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
280*3ff48bf5SDavid du Colombier 			sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
281*3ff48bf5SDavid du Colombier 		print("\tauth server is rogue\n");
282*3ff48bf5SDavid du Colombier 		return;
283*3ff48bf5SDavid du Colombier 	}
284*3ff48bf5SDavid du Colombier 	print("\tticket request using %s@%s key succeeded\n", tr.authid, dom);
285*3ff48bf5SDavid du Colombier 
286*3ff48bf5SDavid du Colombier Nobootes:;
287*3ff48bf5SDavid du Colombier 
288*3ff48bf5SDavid du Colombier 	/* try p9sk1 exchange with local factotum to test that key is right */
289*3ff48bf5SDavid du Colombier 
290*3ff48bf5SDavid du Colombier 
291*3ff48bf5SDavid du Colombier 	/*
292*3ff48bf5SDavid du Colombier 	 * try p9sk1 exchange with factotum on
293*3ff48bf5SDavid du Colombier 	 * auth server (assumes running cpu service)
294*3ff48bf5SDavid du Colombier 	 * to test that bootes key is right over there
295*3ff48bf5SDavid du Colombier 	 */
296*3ff48bf5SDavid du Colombier 
297*3ff48bf5SDavid du Colombier }
298*3ff48bf5SDavid du Colombier 
299*3ff48bf5SDavid du Colombier void
300*3ff48bf5SDavid du Colombier main(int argc, char **argv)
301*3ff48bf5SDavid du Colombier {
302*3ff48bf5SDavid du Colombier 	quotefmtinstall();
303*3ff48bf5SDavid du Colombier 	fmtinstall('A', _attrfmt);
304*3ff48bf5SDavid du Colombier 	fmtinstall('H', encodefmt);
305*3ff48bf5SDavid du Colombier 
306*3ff48bf5SDavid du Colombier 	ARGBEGIN{
307*3ff48bf5SDavid du Colombier 	default:
308*3ff48bf5SDavid du Colombier 		usage();
309*3ff48bf5SDavid du Colombier 	}ARGEND
310*3ff48bf5SDavid du Colombier 
311*3ff48bf5SDavid du Colombier 	if(argc != 0)
312*3ff48bf5SDavid du Colombier 		usage();
313*3ff48bf5SDavid du Colombier 
314*3ff48bf5SDavid du Colombier 	debugfactotumkeys();
315*3ff48bf5SDavid du Colombier }
316