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