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 } 90 91 void authdialfutz(char*, char*); 92 void authfutz(char*, char*); 93 94 /* scan factotum for p9sk1 keys; check them */ 95 void 96 debugfactotumkeys(void) 97 { 98 char *s, *dom, *proto, *user; 99 int found; 100 Attr *a; 101 Biobuf *b; 102 103 b = Bopen("/mnt/factotum/ctl", OREAD); 104 if(b == nil){ 105 fprint(2, "debug: cannot open /mnt/factotum/ctl\n"); 106 return; 107 } 108 found = 0; 109 while((s = Brdstr(b, '\n', 1)) != nil){ 110 if(strncmp(s, "key ", 4) != 0){ 111 print("malformed ctl line: %s\n", s); 112 free(s); 113 continue; 114 } 115 a = _parseattr(s+4); 116 free(s); 117 proto = _strfindattr(a, "proto"); 118 if(proto==nil || strcmp(proto, "p9sk1")!=0) 119 continue; 120 dom = _strfindattr(a, "dom"); 121 if(dom == nil){ 122 print("p9sk1 key with no dom: %A\n", a); 123 _freeattr(a); 124 continue; 125 } 126 user = _strfindattr(a, "user"); 127 if(user == nil){ 128 print("p9sk1 key with no user: %A\n", a); 129 _freeattr(a); 130 continue; 131 } 132 print("p9sk1 key: %A\n", a); 133 found = 1; 134 authdialfutz(dom, user); 135 _freeattr(a); 136 } 137 if(!found) 138 print("no p9sk1 keys found in factotum\n"); 139 } 140 141 void 142 authdialfutz(char *dom, char *user) 143 { 144 int fd; 145 char *server; 146 char *addr; 147 148 fd = authdial(nil, dom); 149 if(fd >= 0){ 150 print("\tsuccessfully dialed auth server\n"); 151 close(fd); 152 authfutz(dom, user); 153 return; 154 } 155 print("\tcannot dial auth server: %r\n"); 156 server = csgetvalue(nil, "authdom", dom, "auth", nil); 157 if(server){ 158 print("\tcsquery authdom=%q auth=%s\n", dom, server); 159 free(server); 160 return; 161 } 162 print("\tcsquery authdom=%q auth=* failed\n", dom); 163 server = csgetvalue(nil, "dom", dom, "auth", nil); 164 if(server){ 165 print("\tcsquery dom=%q auth=%q\n", dom, server); 166 free(server); 167 return; 168 } 169 print("\tcsquery dom=%q auth=*\n", dom); 170 171 fd = dial(addr=netmkaddr("$auth", nil, "ticket"), 0, 0, 0); 172 if(fd >= 0){ 173 print("\tdial %s succeeded\n", addr); 174 close(fd); 175 return; 176 } 177 print("\tdial %s failed: %r\n", addr); 178 } 179 180 void 181 authfutz(char *dom, char *user) 182 { 183 int fd, nobootes; 184 char pw[128], prompt[128], key[DESKEYLEN], booteskey[DESKEYLEN], tbuf[2*TICKETLEN], 185 trbuf[TICKREQLEN]; 186 Ticket t; 187 Ticketreq tr; 188 189 snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", user, dom); 190 readcons(prompt, nil, 1, pw, sizeof pw); 191 if(pw[0] == '\0') 192 return; 193 passtokey(key, pw); 194 195 fd = authdial(nil, dom); 196 if(fd < 0){ 197 print("\tauthdial failed(!): %r\n"); 198 return; 199 } 200 201 /* try ticket request using just user key */ 202 tr.type = AuthTreq; 203 strecpy(tr.authid, tr.authid+sizeof tr.authid, user); 204 strecpy(tr.authdom, tr.authdom+sizeof tr.authdom, dom); 205 strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user); 206 strecpy(tr.uid, tr.uid+sizeof tr.uid, user); 207 memset(tr.chal, 0xAA, sizeof tr.chal); 208 convTR2M(&tr, trbuf); 209 if(_asgetticket(fd, trbuf, tbuf) < 0){ 210 close(fd); 211 print("\t_asgetticket failed: %r\n"); 212 return; 213 } 214 convM2T(tbuf, &t, key); 215 if(t.num != AuthTc){ 216 print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num); 217 print("\tauth server and you do not agree on key for %s@%s\n", user, dom); 218 return; 219 } 220 if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){ 221 print("\tbad challenge1 from auth server got %.*H wanted %.*H\n", 222 sizeof t.chal, t.chal, sizeof tr.chal, tr.chal); 223 print("\tauth server is rogue\n"); 224 return; 225 } 226 227 convM2T(tbuf+TICKETLEN, &t, key); 228 if(t.num != AuthTs){ 229 print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num); 230 print("\tauth server and you do not agree on key for %s@%s\n", user, dom); 231 return; 232 } 233 if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){ 234 print("\tbad challenge2 from auth server got %.*H wanted %.*H\n", 235 sizeof t.chal, t.chal, sizeof tr.chal, tr.chal); 236 print("\tauth server is rogue\n"); 237 return; 238 } 239 print("\tticket request using %s@%s key succeeded\n", user, dom); 240 241 /* try ticket request using bootes key */ 242 snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom); 243 readcons(prompt, "bootes", 0, tr.authid, sizeof tr.authid); 244 convTR2M(&tr, trbuf); 245 if(_asgetticket(fd, trbuf, tbuf) < 0){ 246 close(fd); 247 print("\t_asgetticket failed: %r\n"); 248 return; 249 } 250 convM2T(tbuf, &t, key); 251 if(t.num != AuthTc){ 252 print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num); 253 print("\tauth server and you do not agree on key for %s@%s\n", user, dom); 254 return; 255 } 256 if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){ 257 print("\tbad challenge1 from auth server got %.*H wanted %.*H\n", 258 sizeof t.chal, t.chal, sizeof tr.chal, tr.chal); 259 print("\tauth server is rogue\n"); 260 return; 261 } 262 263 snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom); 264 readcons(prompt, nil, 1, pw, sizeof pw); 265 if(pw[0] == '\0'){ 266 nobootes=1; 267 goto Nobootes; 268 } 269 nobootes = 0; 270 passtokey(booteskey, pw); 271 272 convM2T(tbuf+TICKETLEN, &t, booteskey); 273 if(t.num != AuthTs){ 274 print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num); 275 print("\tauth server and you do not agree on key for %s@%s\n", tr.authid, dom); 276 return; 277 } 278 if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){ 279 print("\tbad challenge2 from auth server got %.*H wanted %.*H\n", 280 sizeof t.chal, t.chal, sizeof tr.chal, tr.chal); 281 print("\tauth server is rogue\n"); 282 return; 283 } 284 print("\tticket request using %s@%s key succeeded\n", tr.authid, dom); 285 286 Nobootes:; 287 USED(nobootes); 288 289 /* try p9sk1 exchange with local factotum to test that key is right */ 290 291 292 /* 293 * try p9sk1 exchange with factotum on 294 * auth server (assumes running cpu service) 295 * to test that bootes key is right over there 296 */ 297 298 } 299 300 void 301 main(int argc, char **argv) 302 { 303 quotefmtinstall(); 304 fmtinstall('A', _attrfmt); 305 fmtinstall('H', encodefmt); 306 307 ARGBEGIN{ 308 default: 309 usage(); 310 }ARGEND 311 312 if(argc != 0) 313 usage(); 314 315 debugfactotumkeys(); 316 } 317