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 Ndbtuple *nt; 147 char server[Ndbvlen]; 148 char *addr; 149 150 fd = authdial(nil, dom); 151 if(fd >= 0){ 152 print("\tsuccessfully dialed auth server\n"); 153 close(fd); 154 authfutz(dom, user); 155 return; 156 } 157 print("\tcannot dial auth server: %r\n"); 158 nt = csgetval(nil, "authdom", dom, "auth", server); 159 if(nt){ 160 print("\tcsquery authdom=%q auth=%s\n", dom, server); 161 return; 162 } 163 print("\tcsquery authdom=%q auth=* failed\n", dom); 164 nt = csgetval(nil, "dom", dom, "auth", server); 165 if(nt){ 166 print("\tcsquery dom=%q auth=%q\n", dom, server); 167 return; 168 } 169 print("\tcsquery dom=%q auth=%q\n", dom, server); 170 171 fd = dial(addr=netmkaddr(server, 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 288 /* try p9sk1 exchange with local factotum to test that key is right */ 289 290 291 /* 292 * try p9sk1 exchange with factotum on 293 * auth server (assumes running cpu service) 294 * to test that bootes key is right over there 295 */ 296 297 } 298 299 void 300 main(int argc, char **argv) 301 { 302 quotefmtinstall(); 303 fmtinstall('A', _attrfmt); 304 fmtinstall('H', encodefmt); 305 306 ARGBEGIN{ 307 default: 308 usage(); 309 }ARGEND 310 311 if(argc != 0) 312 usage(); 313 314 debugfactotumkeys(); 315 } 316