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