1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <ndb.h> 5 #include <regexp.h> 6 #include <mp.h> 7 #include <libsec.h> 8 #include <authsrv.h> 9 #include "authcmdlib.h" 10 11 int debug; 12 Ndb *db; 13 char raddr[128]; 14 15 /* Microsoft auth constants */ 16 enum { 17 MShashlen = 16, 18 MSchallen = 8, 19 MSresplen = 24, 20 }; 21 22 int ticketrequest(Ticketreq*); 23 void challengebox(Ticketreq*); 24 void changepasswd(Ticketreq*); 25 void apop(Ticketreq*, int); 26 void chap(Ticketreq*); 27 void mschap(Ticketreq*); 28 void http(Ticketreq*); 29 void vnc(Ticketreq*); 30 int speaksfor(char*, char*); 31 void replyerror(char*, ...); 32 void getraddr(char*); 33 void mkkey(char*); 34 void randombytes(uchar*, int); 35 void nthash(uchar hash[MShashlen], char *passwd); 36 void lmhash(uchar hash[MShashlen], char *passwd); 37 void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]); 38 void desencrypt(uchar data[8], uchar key[7]); 39 int tickauthreply(Ticketreq*, char*); 40 void safecpy(char*, char*, int); 41 42 43 void 44 main(int argc, char *argv[]) 45 { 46 char buf[TICKREQLEN]; 47 Ticketreq tr; 48 49 ARGBEGIN{ 50 case 'd': 51 debug++; 52 }ARGEND 53 54 strcpy(raddr, "unknown"); 55 if(argc >= 1) 56 getraddr(argv[argc-1]); 57 58 alarm(10*60*1000); /* kill a connection after 10 minutes */ 59 60 db = ndbopen("/lib/ndb/auth"); 61 if(db == 0) 62 syslog(0, AUTHLOG, "no /lib/ndb/auth"); 63 64 srand(time(0)*getpid()); 65 for(;;){ 66 if(readn(0, buf, TICKREQLEN) <= 0) 67 exits(0); 68 69 convM2TR(buf, &tr); 70 switch(buf[0]){ 71 case AuthTreq: 72 ticketrequest(&tr); 73 break; 74 case AuthChal: 75 challengebox(&tr); 76 break; 77 case AuthPass: 78 changepasswd(&tr); 79 break; 80 case AuthApop: 81 apop(&tr, AuthApop); 82 break; 83 case AuthChap: 84 chap(&tr); 85 break; 86 case AuthMSchap: 87 mschap(&tr); 88 break; 89 case AuthCram: 90 apop(&tr, AuthCram); 91 break; 92 case AuthHttp: 93 http(&tr); 94 break; 95 case AuthVNC: 96 vnc(&tr); 97 break; 98 default: 99 syslog(0, AUTHLOG, "unknown ticket request type: %d", buf[0]); 100 exits(0); 101 } 102 } 103 /* not reached */ 104 } 105 106 int 107 ticketrequest(Ticketreq *tr) 108 { 109 char akey[DESKEYLEN]; 110 char hkey[DESKEYLEN]; 111 Ticket t; 112 char tbuf[2*TICKETLEN+1]; 113 114 if(findkey(KEYDB, tr->authid, akey) == 0){ 115 /* make one up so caller doesn't know it was wrong */ 116 mkkey(akey); 117 if(debug) 118 syslog(0, AUTHLOG, "tr-fail authid %s", raddr); 119 } 120 if(findkey(KEYDB, tr->hostid, hkey) == 0){ 121 /* make one up so caller doesn't know it was wrong */ 122 mkkey(hkey); 123 if(debug) 124 syslog(0, AUTHLOG, "tr-fail hostid %s(%s)", tr->hostid, raddr); 125 } 126 127 memset(&t, 0, sizeof(t)); 128 memmove(t.chal, tr->chal, CHALLEN); 129 strcpy(t.cuid, tr->uid); 130 if(speaksfor(tr->hostid, tr->uid)) 131 strcpy(t.suid, tr->uid); 132 else { 133 mkkey(akey); 134 mkkey(hkey); 135 if(debug) 136 syslog(0, AUTHLOG, "tr-fail %s@%s(%s) -> %s@%s no speaks for", 137 tr->uid, tr->hostid, raddr, tr->uid, tr->authid); 138 } 139 140 mkkey(t.key); 141 142 tbuf[0] = AuthOK; 143 t.num = AuthTc; 144 convT2M(&t, tbuf+1, hkey); 145 t.num = AuthTs; 146 convT2M(&t, tbuf+1+TICKETLEN, akey); 147 if(write(1, tbuf, 2*TICKETLEN+1) < 0){ 148 if(debug) 149 syslog(0, AUTHLOG, "tr-fail %s@%s(%s): hangup", 150 tr->uid, tr->hostid, raddr); 151 exits(0); 152 } 153 if(debug) 154 syslog(0, AUTHLOG, "tr-ok %s@%s(%s) -> %s@%s", 155 tr->uid, tr->hostid, raddr, tr->uid, tr->authid); 156 157 return 0; 158 } 159 160 void 161 challengebox(Ticketreq *tr) 162 { 163 long chal; 164 char *key, *netkey; 165 char kbuf[DESKEYLEN], nkbuf[DESKEYLEN], hkey[DESKEYLEN]; 166 char buf[NETCHLEN+1]; 167 char *err; 168 169 key = findkey(KEYDB, tr->uid, kbuf); 170 netkey = findkey(NETKEYDB, tr->uid, nkbuf); 171 if(key == 0 && netkey == 0){ 172 /* make one up so caller doesn't know it was wrong */ 173 mkkey(nkbuf); 174 netkey = nkbuf; 175 if(debug) 176 syslog(0, AUTHLOG, "cr-fail uid %s@%s", tr->uid, raddr); 177 } 178 if(findkey(KEYDB, tr->hostid, hkey) == 0){ 179 /* make one up so caller doesn't know it was wrong */ 180 mkkey(hkey); 181 if(debug) 182 syslog(0, AUTHLOG, "cr-fail hostid %s %s@%s", tr->hostid, 183 tr->uid, raddr); 184 } 185 186 /* 187 * challenge-response 188 */ 189 memset(buf, 0, sizeof(buf)); 190 buf[0] = AuthOK; 191 chal = lnrand(MAXNETCHAL); 192 sprint(buf+1, "%lud", chal); 193 if(write(1, buf, NETCHLEN+1) < 0) 194 exits(0); 195 if(readn(0, buf, NETCHLEN) < 0) 196 exits(0); 197 if(!(key && netcheck(key, chal, buf)) 198 && !(netkey && netcheck(netkey, chal, buf)) 199 && (err = secureidcheck(tr->uid, buf)) != nil){ 200 replyerror("cr-fail %s %s %s", err, tr->uid, raddr); 201 logfail(tr->uid); 202 if(debug) 203 syslog(0, AUTHLOG, "cr-fail %s@%s(%s): bad resp", 204 tr->uid, tr->hostid, raddr); 205 return; 206 } 207 succeed(tr->uid); 208 209 /* 210 * reply with ticket & authenticator 211 */ 212 if(tickauthreply(tr, hkey) < 0){ 213 if(debug) 214 syslog(0, AUTHLOG, "cr-fail %s@%s(%s): hangup", 215 tr->uid, tr->hostid, raddr); 216 exits(0); 217 } 218 219 if(debug) 220 syslog(0, AUTHLOG, "cr-ok %s@%s(%s)", 221 tr->uid, tr->hostid, raddr); 222 } 223 224 void 225 changepasswd(Ticketreq *tr) 226 { 227 Ticket t; 228 char tbuf[TICKETLEN+1]; 229 char prbuf[PASSREQLEN]; 230 Passwordreq pr; 231 char okey[DESKEYLEN], nkey[DESKEYLEN]; 232 char *err; 233 234 if(findkey(KEYDB, tr->uid, okey) == 0){ 235 /* make one up so caller doesn't know it was wrong */ 236 mkkey(okey); 237 syslog(0, AUTHLOG, "cp-fail uid %s", raddr); 238 } 239 240 /* send back a ticket with a new key */ 241 memmove(t.chal, tr->chal, CHALLEN); 242 mkkey(t.key); 243 tbuf[0] = AuthOK; 244 t.num = AuthTp; 245 safecpy(t.cuid, tr->uid, sizeof(t.cuid)); 246 safecpy(t.suid, tr->uid, sizeof(t.suid)); 247 convT2M(&t, tbuf+1, okey); 248 write(1, tbuf, sizeof(tbuf)); 249 250 /* loop trying passwords out */ 251 for(;;){ 252 if(readn(0, prbuf, PASSREQLEN) < 0) 253 exits(0); 254 convM2PR(prbuf, &pr, t.key); 255 if(pr.num != AuthPass){ 256 replyerror("protocol botch1: %s", raddr); 257 exits(0); 258 } 259 passtokey(nkey, pr.old); 260 if(memcmp(nkey, okey, DESKEYLEN)){ 261 replyerror("protocol botch2: %s", raddr); 262 continue; 263 } 264 if(*pr.new){ 265 err = okpasswd(pr.new); 266 if(err){ 267 replyerror("%s %s", err, raddr); 268 continue; 269 } 270 passtokey(nkey, pr.new); 271 } 272 if(pr.changesecret && setsecret(KEYDB, tr->uid, pr.secret) == 0){ 273 replyerror("can't write secret %s", raddr); 274 continue; 275 } 276 if(*pr.new && setkey(KEYDB, tr->uid, nkey) == 0){ 277 replyerror("can't write key %s", raddr); 278 continue; 279 } 280 break; 281 } 282 283 prbuf[0] = AuthOK; 284 write(1, prbuf, 1); 285 succeed(tr->uid); 286 return; 287 } 288 289 void 290 http(Ticketreq *tr) 291 { 292 Ticket t; 293 char tbuf[TICKETLEN+1]; 294 char key[DESKEYLEN]; 295 char *p; 296 Biobuf *b; 297 int n; 298 299 n = strlen(tr->uid); 300 b = Bopen("/sys/lib/httppasswords", OREAD); 301 if(b == nil){ 302 replyerror("no password file", raddr); 303 return; 304 } 305 306 /* find key */ 307 for(;;){ 308 p = Brdline(b, '\n'); 309 if(p == nil) 310 break; 311 p[Blinelen(b)-1] = 0; 312 if(strncmp(p, tr->uid, n) == 0) 313 if(p[n] == ' ' || p[n] == '\t'){ 314 p += n; 315 break; 316 } 317 } 318 Bterm(b); 319 if(p == nil) { 320 randombytes((uchar*)key, DESKEYLEN); 321 } else { 322 while(*p == ' ' || *p == '\t') 323 p++; 324 passtokey(key, p); 325 } 326 327 /* send back a ticket encrypted with the key */ 328 randombytes((uchar*)t.chal, CHALLEN); 329 mkkey(t.key); 330 tbuf[0] = AuthOK; 331 t.num = AuthHr; 332 safecpy(t.cuid, tr->uid, sizeof(t.cuid)); 333 safecpy(t.suid, tr->uid, sizeof(t.suid)); 334 convT2M(&t, tbuf+1, key); 335 write(1, tbuf, sizeof(tbuf)); 336 } 337 338 static char* 339 domainname(void) 340 { 341 static char sysname[Maxpath]; 342 static char *domain; 343 int n; 344 345 if(domain) 346 return domain; 347 if(*sysname) 348 return sysname; 349 350 domain = csgetvalue(0, "sys", sysname, "dom", nil); 351 if(domain) 352 return domain; 353 354 n = readfile("/dev/sysname", sysname, sizeof(sysname)-1); 355 if(n < 0){ 356 strcpy(sysname, "kremvax"); 357 return sysname; 358 } 359 sysname[n] = 0; 360 361 return sysname; 362 } 363 364 static int 365 h2b(char c) 366 { 367 if(c >= '0' && c <= '9') 368 return c - '0'; 369 if(c >= 'A' && c <= 'F') 370 return c - 'A' + 10; 371 if(c >= 'a' && c <= 'f') 372 return c - 'a' + 10; 373 return 0; 374 } 375 376 void 377 apop(Ticketreq *tr, int type) 378 { 379 int challen, i, tries; 380 char *secret, *hkey, *p; 381 Ticketreq treq; 382 DigestState *s; 383 char sbuf[SECRETLEN], hbuf[DESKEYLEN]; 384 char tbuf[TICKREQLEN]; 385 char buf[MD5dlen*2]; 386 uchar digest[MD5dlen], resp[MD5dlen]; 387 ulong rb[4]; 388 char chal[256]; 389 390 USED(tr); 391 392 /* 393 * Create a challenge and send it. 394 */ 395 randombytes((uchar*)rb, sizeof(rb)); 396 p = chal; 397 p += snprint(p, sizeof(chal), "<%lux%lux.%lux%lux@%s>", 398 rb[0], rb[1], rb[2], rb[3], domainname()); 399 challen = p - chal; 400 print("%c%-5d%s", AuthOKvar, challen, chal); 401 402 /* give user a few attempts */ 403 for(tries = 0; ; tries++) { 404 /* 405 * get ticket request 406 */ 407 if(readn(0, tbuf, TICKREQLEN) < 0) 408 exits(0); 409 convM2TR(tbuf, &treq); 410 tr = &treq; 411 if(tr->type != type) 412 exits(0); 413 414 /* 415 * read response 416 */ 417 if(readn(0, buf, MD5dlen*2) < 0) 418 exits(0); 419 for(i = 0; i < MD5dlen; i++) 420 resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]); 421 422 /* 423 * lookup 424 */ 425 secret = findsecret(KEYDB, tr->uid, sbuf); 426 hkey = findkey(KEYDB, tr->hostid, hbuf); 427 if(hkey == 0 || secret == 0){ 428 replyerror("apop-fail bad response %s", raddr); 429 logfail(tr->uid); 430 if(tries > 5) 431 return; 432 continue; 433 } 434 435 /* 436 * check for match 437 */ 438 if(type == AuthCram){ 439 hmac_md5((uchar*)chal, challen, 440 (uchar*)secret, strlen(secret), 441 digest, nil); 442 } else { 443 s = md5((uchar*)chal, challen, 0, 0); 444 md5((uchar*)secret, strlen(secret), digest, s); 445 } 446 if(memcmp(digest, resp, MD5dlen) != 0){ 447 replyerror("apop-fail bad response %s", raddr); 448 logfail(tr->uid); 449 if(tries > 5) 450 return; 451 continue; 452 } 453 break; 454 } 455 456 succeed(tr->uid); 457 458 /* 459 * reply with ticket & authenticator 460 */ 461 if(tickauthreply(tr, hkey) < 0) 462 exits(0); 463 464 if(debug){ 465 if(type == AuthCram) 466 syslog(0, AUTHLOG, "cram-ok %s %s", tr->uid, raddr); 467 else 468 syslog(0, AUTHLOG, "apop-ok %s %s", tr->uid, raddr); 469 } 470 } 471 472 enum { 473 VNCchallen= 16, 474 }; 475 476 /* VNC reverses the bits of each byte before using as a des key */ 477 uchar swizzletab[256] = { 478 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 479 0x8, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 480 0x4, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 481 0xc, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 482 0x2, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 483 0xa, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 484 0x6, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 485 0xe, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 486 0x1, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 487 0x9, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 488 0x5, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 489 0xd, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 490 0x3, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 491 0xb, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 492 0x7, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 493 0xf, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 494 }; 495 496 void 497 vnc(Ticketreq *tr) 498 { 499 uchar chal[VNCchallen+6]; 500 uchar reply[VNCchallen]; 501 char *secret, *hkey; 502 char sbuf[SECRETLEN], hbuf[DESKEYLEN]; 503 DESstate s; 504 int i; 505 506 /* 507 * Create a challenge and send it. 508 */ 509 randombytes(chal+6, VNCchallen); 510 chal[0] = AuthOKvar; 511 sprint((char*)chal+1, "%-5d", VNCchallen); 512 if(write(1, chal, sizeof(chal)) != sizeof(chal)) 513 return; 514 515 /* 516 * lookup keys (and swizzle bits) 517 */ 518 memset(sbuf, 0, sizeof(sbuf)); 519 secret = findsecret(KEYDB, tr->uid, sbuf); 520 if(secret == 0){ 521 randombytes((uchar*)sbuf, sizeof(sbuf)); 522 secret = sbuf; 523 } 524 for(i = 0; i < 8; i++) 525 secret[i] = swizzletab[(uchar)secret[i]]; 526 527 hkey = findkey(KEYDB, tr->hostid, hbuf); 528 if(hkey == 0){ 529 randombytes((uchar*)hbuf, sizeof(hbuf)); 530 hkey = hbuf; 531 } 532 533 /* 534 * get response 535 */ 536 if(readn(0, reply, sizeof(reply)) != sizeof(reply)) 537 return; 538 539 /* 540 * decrypt response and compare 541 */ 542 setupDESstate(&s, (uchar*)secret, nil); 543 desECBdecrypt(reply, sizeof(reply), &s); 544 if(memcmp(reply, chal+6, VNCchallen) != 0){ 545 replyerror("vnc-fail bad response %s", raddr); 546 logfail(tr->uid); 547 return; 548 } 549 succeed(tr->uid); 550 551 /* 552 * reply with ticket & authenticator 553 */ 554 if(tickauthreply(tr, hkey) < 0) 555 exits(0); 556 557 if(debug) 558 syslog(0, AUTHLOG, "vnc-ok %s %s", tr->uid, raddr); 559 } 560 561 void 562 chap(Ticketreq *tr) 563 { 564 char *secret, *hkey; 565 DigestState *s; 566 char sbuf[SECRETLEN], hbuf[DESKEYLEN]; 567 uchar digest[MD5dlen]; 568 char chal[CHALLEN]; 569 OChapreply reply; 570 571 /* 572 * Create a challenge and send it. 573 */ 574 randombytes((uchar*)chal, sizeof(chal)); 575 write(1, chal, sizeof(chal)); 576 577 /* 578 * get chap reply 579 */ 580 if(readn(0, &reply, sizeof(reply)) < 0) 581 exits(0); 582 safecpy(tr->uid, reply.uid, sizeof(tr->uid)); 583 584 /* 585 * lookup 586 */ 587 secret = findsecret(KEYDB, tr->uid, sbuf); 588 hkey = findkey(KEYDB, tr->hostid, hbuf); 589 if(hkey == 0 || secret == 0){ 590 replyerror("chap-fail bad response %s", raddr); 591 logfail(tr->uid); 592 exits(0); 593 } 594 595 /* 596 * check for match 597 */ 598 s = md5(&reply.id, 1, 0, 0); 599 md5((uchar*)secret, strlen(secret), 0, s); 600 md5((uchar*)chal, sizeof(chal), digest, s); 601 602 if(memcmp(digest, reply.resp, MD5dlen) != 0){ 603 replyerror("chap-fail bad response %s", raddr); 604 logfail(tr->uid); 605 exits(0); 606 } 607 608 succeed(tr->uid); 609 610 /* 611 * reply with ticket & authenticator 612 */ 613 if(tickauthreply(tr, hkey) < 0) 614 exits(0); 615 616 if(debug) 617 syslog(0, AUTHLOG, "chap-ok %s %s", tr->uid, raddr); 618 } 619 620 void 621 printresp(uchar resp[MSresplen]) 622 { 623 char buf[200], *p; 624 int i; 625 626 p = buf; 627 for(i=0; i<MSresplen; i++) 628 p += sprint(p, "%.2ux ", resp[i]); 629 syslog(0, AUTHLOG, "resp = %s", buf); 630 } 631 632 633 void 634 mschap(Ticketreq *tr) 635 { 636 637 char *secret, *hkey; 638 char sbuf[SECRETLEN], hbuf[DESKEYLEN]; 639 uchar chal[CHALLEN]; 640 uchar hash[MShashlen]; 641 uchar hash2[MShashlen]; 642 uchar resp[MSresplen]; 643 OMSchapreply reply; 644 int lmok, ntok; 645 DigestState *s; 646 uchar digest[SHA1dlen]; 647 648 /* 649 * Create a challenge and send it. 650 */ 651 randombytes((uchar*)chal, sizeof(chal)); 652 write(1, chal, sizeof(chal)); 653 654 /* 655 * get chap reply 656 */ 657 if(readn(0, &reply, sizeof(reply)) < 0) 658 exits(0); 659 660 safecpy(tr->uid, reply.uid, sizeof(tr->uid)); 661 /* 662 * lookup 663 */ 664 secret = findsecret(KEYDB, tr->uid, sbuf); 665 hkey = findkey(KEYDB, tr->hostid, hbuf); 666 if(hkey == 0 || secret == 0){ 667 replyerror("mschap-fail bad response %s", raddr); 668 logfail(tr->uid); 669 exits(0); 670 } 671 672 /* 673 * check for match on LM algorithm 674 */ 675 lmhash(hash, secret); 676 mschalresp(resp, hash, chal); 677 lmok = memcmp(resp, reply.LMresp, MSresplen) == 0; 678 679 nthash(hash, secret); 680 mschalresp(resp, hash, chal); 681 ntok = memcmp(resp, reply.NTresp, MSresplen) == 0; 682 683 if(!ntok){ 684 replyerror("mschap-fail bad response %s %ux", raddr, (lmok<<1)|ntok); 685 logfail(tr->uid); 686 exits(0); 687 } 688 689 succeed(tr->uid); 690 691 /* 692 * reply with ticket & authenticator 693 */ 694 if(tickauthreply(tr, hkey) < 0) 695 exits(0); 696 697 if(debug) 698 syslog(0, AUTHLOG, "mschap-ok %s %s %ux", tr->uid, raddr, (lmok<<1)|ntok); 699 700 nthash(hash, secret); 701 md4(hash, 16, hash2, 0); 702 s = sha1(hash2, 16, 0, 0); 703 sha1(hash2, 16, 0, s); 704 sha1(chal, 8, digest, s); 705 706 if(write(1, digest, 16) < 0) 707 exits(0); 708 } 709 710 void 711 nthash(uchar hash[MShashlen], char *passwd) 712 { 713 uchar buf[512]; 714 int i; 715 716 for (i = 0; *passwd && i + 1 < sizeof(buf);) { 717 Rune r; 718 passwd += chartorune(&r, passwd); 719 buf[i++] = r; 720 buf[i++] = r >> 8; 721 } 722 723 memset(hash, 0, 16); 724 725 md4(buf, i, hash, 0); 726 } 727 728 void 729 lmhash(uchar hash[MShashlen], char *passwd) 730 { 731 uchar buf[14]; 732 char *stdtext = "KGS!@#$%"; 733 int i; 734 735 strncpy((char*)buf, passwd, sizeof(buf)); 736 for(i=0; i<sizeof(buf); i++) 737 if(buf[i] >= 'a' && buf[i] <= 'z') 738 buf[i] += 'A' - 'a'; 739 740 memset(hash, 0, 16); 741 memcpy(hash, stdtext, 8); 742 memcpy(hash+8, stdtext, 8); 743 744 desencrypt(hash, buf); 745 desencrypt(hash+8, buf+7); 746 } 747 748 void 749 mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]) 750 { 751 int i; 752 uchar buf[21]; 753 754 memset(buf, 0, sizeof(buf)); 755 memcpy(buf, hash, MShashlen); 756 757 for(i=0; i<3; i++) { 758 memmove(resp+i*MSchallen, chal, MSchallen); 759 desencrypt(resp+i*MSchallen, buf+i*7); 760 } 761 } 762 763 void 764 desencrypt(uchar data[8], uchar key[7]) 765 { 766 ulong ekey[32]; 767 768 key_setup(key, ekey); 769 block_cipher(ekey, data, 0); 770 } 771 772 /* 773 * return true of the speaker may speak for the user 774 * 775 * a speaker may always speak for himself/herself 776 */ 777 int 778 speaksfor(char *speaker, char *user) 779 { 780 Ndbtuple *tp, *ntp; 781 Ndbs s; 782 int ok; 783 char notuser[Maxpath]; 784 785 if(strcmp(speaker, user) == 0) 786 return 1; 787 788 if(db == 0) 789 return 0; 790 791 tp = ndbsearch(db, &s, "hostid", speaker); 792 if(tp == 0) 793 return 0; 794 795 ok = 0; 796 snprint(notuser, sizeof notuser, "!%s", user); 797 for(ntp = tp; ntp; ntp = ntp->entry) 798 if(strcmp(ntp->attr, "uid") == 0){ 799 if(strcmp(ntp->val, notuser) == 0) 800 break; 801 if(*ntp->val == '*' || strcmp(ntp->val, user) == 0) 802 ok = 1; 803 } 804 ndbfree(tp); 805 return ok; 806 } 807 808 /* 809 * return an error reply 810 */ 811 void 812 replyerror(char *fmt, ...) 813 { 814 char buf[AERRLEN+1]; 815 va_list arg; 816 817 memset(buf, 0, sizeof(buf)); 818 va_start(arg, fmt); 819 vseprint(buf + 1, buf + sizeof(buf), fmt, arg); 820 va_end(arg); 821 buf[AERRLEN] = 0; 822 buf[0] = AuthErr; 823 write(1, buf, AERRLEN+1); 824 syslog(0, AUTHLOG, buf+1); 825 } 826 827 void 828 getraddr(char *dir) 829 { 830 int n; 831 char *cp; 832 char file[Maxpath]; 833 834 raddr[0] = 0; 835 snprint(file, sizeof(file), "%s/remote", dir); 836 n = readfile(file, raddr, sizeof(raddr)-1); 837 if(n < 0) 838 return; 839 raddr[n] = 0; 840 841 cp = strchr(raddr, '\n'); 842 if(cp) 843 *cp = 0; 844 cp = strchr(raddr, '!'); 845 if(cp) 846 *cp = 0; 847 } 848 849 void 850 mkkey(char *k) 851 { 852 randombytes((uchar*)k, DESKEYLEN); 853 } 854 855 void 856 randombytes(uchar *buf, int len) 857 { 858 int i; 859 860 if(readfile("/dev/random", (char*)buf, len) >= 0) 861 return; 862 863 for(i = 0; i < len; i++) 864 buf[i] = rand(); 865 } 866 867 /* 868 * reply with ticket and authenticator 869 */ 870 int 871 tickauthreply(Ticketreq *tr, char *hkey) 872 { 873 Ticket t; 874 Authenticator a; 875 char buf[TICKETLEN+AUTHENTLEN+1]; 876 877 memset(&t, 0, sizeof(t)); 878 memmove(t.chal, tr->chal, CHALLEN); 879 safecpy(t.cuid, tr->uid, sizeof t.cuid); 880 safecpy(t.suid, tr->uid, sizeof t.suid); 881 mkkey(t.key); 882 buf[0] = AuthOK; 883 t.num = AuthTs; 884 convT2M(&t, buf+1, hkey); 885 memmove(a.chal, t.chal, CHALLEN); 886 a.num = AuthAc; 887 a.id = 0; 888 convA2M(&a, buf+TICKETLEN+1, t.key); 889 if(write(1, buf, TICKETLEN+AUTHENTLEN+1) < 0) 890 return -1; 891 return 0; 892 } 893 894 void 895 safecpy(char *to, char *from, int len) 896 { 897 strncpy(to, from, len); 898 to[len-1] = 0; 899 } 900