chap.c revision 48817
10SN/A/* 23294SN/A * PPP CHAP Module 30SN/A * 40SN/A * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 50SN/A * 60SN/A * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7553SN/A * 80SN/A * Redistribution and use in source and binary forms are permitted 9553SN/A * provided that the above copyright notice and this paragraph are 100SN/A * duplicated in all such forms and that any documentation, 110SN/A * advertising materials, and other materials related to such 120SN/A * distribution and use acknowledge that the software was developed 130SN/A * by the Internet Initiative Japan, Inc. The name of the 140SN/A * IIJ may not be used to endorse or promote products derived 150SN/A * from this software without specific prior written permission. 160SN/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 170SN/A * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 180SN/A * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 190SN/A * 200SN/A * $Id: chap.c,v 1.52 1999/06/09 08:47:29 brian Exp $ 21553SN/A * 22553SN/A * TODO: 23553SN/A */ 240SN/A#include <sys/param.h> 250SN/A#include <netinet/in.h> 263386Sjjg#include <netinet/in_systm.h> 270SN/A#include <netinet/ip.h> 281356SN/A#include <sys/un.h> 29196SN/A 301356SN/A#include <errno.h> 31196SN/A#include <fcntl.h> 320SN/A#ifdef HAVE_DES 33196SN/A#include <md4.h> 341442SN/A#endif 350SN/A#include <md5.h> 362528SN/A#include <paths.h> 370SN/A#include <signal.h> 380SN/A#include <stdlib.h> 390SN/A#include <string.h> 40196SN/A#include <sys/wait.h> 410SN/A#include <termios.h> 420SN/A#include <unistd.h> 430SN/A 440SN/A#include "layer.h" 450SN/A#include "mbuf.h" 462528SN/A#include "log.h" 472528SN/A#include "defs.h" 480SN/A#include "timer.h" 490SN/A#include "fsm.h" 500SN/A#include "proto.h" 510SN/A#include "lcp.h" 520SN/A#include "lqr.h" 531358SN/A#include "hdlc.h" 541358SN/A#include "auth.h" 551358SN/A#include "async.h" 561358SN/A#include "throughput.h" 571358SN/A#include "descriptor.h" 580SN/A#include "chap.h" 590SN/A#include "iplist.h" 600SN/A#include "slcompress.h" 610SN/A#include "ipcp.h" 620SN/A#include "filter.h" 630SN/A#include "ccp.h" 640SN/A#include "link.h" 653445Sjjg#include "physical.h" 660SN/A#include "mp.h" 670SN/A#ifndef NORADIUS 683294SN/A#include "radius.h" 690SN/A#endif 700SN/A#include "bundle.h" 71196SN/A#include "chat.h" 720SN/A#include "cbcp.h" 730SN/A#include "command.h" 740SN/A#include "datalink.h" 750SN/A#ifdef HAVE_DES 760SN/A#include "chap_ms.h" 770SN/A#endif 780SN/A 790SN/Astatic const char *chapcodes[] = { 800SN/A "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 810SN/A}; 821442SN/A#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1) 830SN/A 840SN/Astatic void 850SN/AChapOutput(struct physical *physical, u_int code, u_int id, 860SN/A const u_char *ptr, int count, const char *text) 870SN/A{ 881442SN/A int plen; 891442SN/A struct fsmheader lh; 900SN/A struct mbuf *bp; 911442SN/A 920SN/A plen = sizeof(struct fsmheader) + count; 930SN/A lh.code = code; 940SN/A lh.id = id; 950SN/A lh.length = htons(plen); 960SN/A bp = mbuf_Alloc(plen, MB_CHAPOUT); 970SN/A memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 980SN/A if (count) 991442SN/A memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 1001442SN/A log_DumpBp(LogDEBUG, "ChapOutput", bp); 1010SN/A if (text == NULL) 1020SN/A log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); 1030SN/A else 1040SN/A log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); 1050SN/A link_PushPacket(&physical->link, bp, physical->dl->bundle, 1060SN/A PRI_LINK, PROTO_CHAP); 1071050SN/A} 108196SN/A 109196SN/Astatic char * 1100SN/Achap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type 1110SN/A#ifdef HAVE_DES 1120SN/A , int lanman 113196SN/A#endif 1140SN/A ) 1150SN/A{ 1160SN/A char *result, *digest; 117196SN/A size_t nlen, klen; 1180SN/A 1190SN/A nlen = strlen(name); 1200SN/A klen = strlen(key); 1210SN/A 1220SN/A#ifdef HAVE_DES 1230SN/A if (type == 0x80) { 1240SN/A char expkey[AUTHLEN << 2]; 1250SN/A MD4_CTX MD4context; 1260SN/A int f; 1270SN/A 1280SN/A if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL) 1290SN/A return result; 1300SN/A 1310SN/A digest = result; /* the response */ 1320SN/A *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 1330SN/A memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen); 1340SN/A if (lanman) { 1350SN/A memset(digest + 24, '\0', 25); 1360SN/A mschap_LANMan(digest, challenge + 1, key); /* LANMan response */ 1370SN/A } else { 1380SN/A memset(digest, '\0', 25); 1390SN/A digest += 24; 1400SN/A 1410SN/A for (f = 0; f < klen; f++) { 1420SN/A expkey[2*f] = key[f]; 1430SN/A expkey[2*f+1] = '\0'; 1440SN/A } 1450SN/A /* 1460SN/A * ----------- 1470SN/A * expkey = | k\0e\0y\0 | 1480SN/A * ----------- 1490SN/A */ 1500SN/A MD4Init(&MD4context); 1512233SN/A MD4Update(&MD4context, expkey, klen << 1); 1522528SN/A MD4Final(digest, &MD4context); 1532528SN/A 1542528SN/A /* 1550SN/A * ---- -------- ---------------- ------- ------ 1560SN/A * result = | 49 | LANMan | 16 byte digest | 9 * ? | name | 1570SN/A * ---- -------- ---------------- ------- ------ 1580SN/A */ 1590SN/A mschap_NT(digest, challenge + 1); 1600SN/A } 1610SN/A /* 1620SN/A * ---- -------- ------------- ----- ------ 1630SN/A * | | struct MS_ChapResponse24 | | 1640SN/A * result = | 49 | LANMan | NT digest | 0/1 | name | 1650SN/A * ---- -------- ------------- ----- ------ 1660SN/A * where only one of LANMan & NT digest are set. 1670SN/A */ 1680SN/A } else 1690SN/A#endif 1700SN/A if ((result = malloc(nlen + 17)) != NULL) { 1710SN/A /* Normal MD5 stuff */ 1720SN/A MD5_CTX MD5context; 1730SN/A 1740SN/A digest = result; 1750SN/A *digest++ = 16; /* value size */ 1760SN/A 1770SN/A MD5Init(&MD5context); 1780SN/A MD5Update(&MD5context, &id, 1); 1790SN/A MD5Update(&MD5context, key, klen); 1800SN/A MD5Update(&MD5context, challenge + 1, *challenge); 1810SN/A MD5Final(digest, &MD5context); 1820SN/A 1830SN/A memcpy(digest + 16, name, nlen); 1840SN/A /* 1850SN/A * ---- -------- ------ 1860SN/A * result = | 16 | digest | name | 1870SN/A * ---- -------- ------ 1880SN/A */ 1890SN/A } 1900SN/A 1910SN/A return result; 1920SN/A} 1930SN/A 1940SN/Astatic void 1950SN/Achap_StartChild(struct chap *chap, char *prog, const char *name) 1960SN/A{ 1970SN/A char *argv[MAXARGS], *nargv[MAXARGS]; 1980SN/A int argc, fd; 1990SN/A int in[2], out[2]; 2000SN/A pid_t pid; 2010SN/A 2020SN/A if (chap->child.fd != -1) { 2030SN/A log_Printf(LogWARN, "Chap: %s: Program already running\n", prog); 2042233SN/A return; 2050SN/A } 2060SN/A 2070SN/A if (pipe(in) == -1) { 2080SN/A log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 2090SN/A return; 2100SN/A } 2110SN/A 2120SN/A if (pipe(out) == -1) { 2130SN/A log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 2140SN/A close(in[0]); 2150SN/A close(in[1]); 2160SN/A return; 2170SN/A } 2180SN/A 2192233SN/A pid = getpid(); 2200SN/A switch ((chap->child.pid = fork())) { 2210SN/A case -1: 2220SN/A log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno)); 2230SN/A close(in[0]); 2240SN/A close(in[1]); 2250SN/A close(out[0]); 2260SN/A close(out[1]); 2270SN/A chap->child.pid = 0; 2280SN/A return; 2290SN/A 2300SN/A case 0: 2310SN/A timer_TermService(); 2320SN/A close(in[1]); 2330SN/A close(out[0]); 2342233SN/A if (out[1] == STDIN_FILENO) { 2350SN/A fd = dup(out[1]); 2360SN/A close(out[1]); 2370SN/A out[1] = fd; 2380SN/A } 2390SN/A dup2(in[0], STDIN_FILENO); 2400SN/A dup2(out[1], STDOUT_FILENO); 2410SN/A if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 2420SN/A log_Printf(LogALERT, "Chap: Failed to open %s: %s\n", 2430SN/A _PATH_DEVNULL, strerror(errno)); 2440SN/A exit(1); 2450SN/A } 2460SN/A dup2(fd, STDERR_FILENO); 2470SN/A fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */ 2480SN/A 2492233SN/A setuid(geteuid()); 2500SN/A argc = command_Interpret(prog, strlen(prog), argv); 2510SN/A command_Expand(nargv, argc, (char const *const *)argv, 2520SN/A chap->auth.physical->dl->bundle, 0, pid); 2530SN/A execvp(nargv[0], nargv); 2540SN/A 2550SN/A log_Printf(LogWARN, "exec() of %s failed: %s\n", 2560SN/A nargv[0], strerror(errno)); 2570SN/A exit(255); 2580SN/A 2590SN/A default: 2600SN/A close(in[0]); 2610SN/A close(out[1]); 2620SN/A chap->child.fd = out[0]; 2630SN/A chap->child.buf.len = 0; 2642233SN/A write(in[1], chap->auth.in.name, strlen(chap->auth.in.name)); 2650SN/A write(in[1], "\n", 1); 2660SN/A write(in[1], chap->challenge.peer + 1, *chap->challenge.peer); 2670SN/A write(in[1], "\n", 1); 2680SN/A write(in[1], name, strlen(name)); 2690SN/A write(in[1], "\n", 1); 2700SN/A close(in[1]); 2710SN/A break; 2720SN/A } 2730SN/A} 2740SN/A 2750SN/Astatic void 2760SN/Achap_Cleanup(struct chap *chap, int sig) 2770SN/A{ 2780SN/A if (chap->child.pid) { 2792233SN/A int status; 2800SN/A 2810SN/A close(chap->child.fd); 2820SN/A chap->child.fd = -1; 2830SN/A if (sig) 2840SN/A kill(chap->child.pid, SIGTERM); 2850SN/A chap->child.pid = 0; 2860SN/A chap->child.buf.len = 0; 2870SN/A 2880SN/A if (wait(&status) == -1) 2890SN/A log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno)); 2900SN/A else if (WIFSIGNALED(status)) 2910SN/A log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status)); 2920SN/A else if (WIFEXITED(status) && WEXITSTATUS(status)) 2931463SN/A log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status)); 2940SN/A } 2951463SN/A *chap->challenge.local = *chap->challenge.peer = '\0'; 2960SN/A#ifdef HAVE_DES 2970SN/A chap->peertries = 0; 2980SN/A#endif 2990SN/A} 3000SN/A 3010SN/Astatic void 3020SN/Achap_Respond(struct chap *chap, char *name, char *key, u_char type 3030SN/A#ifdef HAVE_DES 3040SN/A , int lm 3050SN/A#endif 3060SN/A ) 3070SN/A{ 3080SN/A u_char *ans; 3090SN/A 3100SN/A ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type 3110SN/A#ifdef HAVE_DES 3120SN/A , lm 3130SN/A#endif 3140SN/A ); 3150SN/A 3160SN/A if (ans) { 3170SN/A ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id, 3180SN/A ans, *ans + 1 + strlen(name), name); 3190SN/A#ifdef HAVE_DES 3200SN/A chap->NTRespSent = !lm; 3210SN/A#endif 3220SN/A free(ans); 3230SN/A } else 3240SN/A ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id, 3250SN/A "Out of memory!", 14, NULL); 3260SN/A} 3270SN/A 3280SN/Astatic int 3290SN/Achap_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 3300SN/A{ 3310SN/A struct chap *chap = descriptor2chap(d); 3320SN/A 3330SN/A if (r && chap && chap->child.fd != -1) { 3340SN/A FD_SET(chap->child.fd, r); 3350SN/A if (*n < chap->child.fd + 1) 3360SN/A *n = chap->child.fd + 1; 3370SN/A log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd); 3380SN/A return 1; 3391705SN/A } 3401705SN/A 3411705SN/A return 0; 3421705SN/A} 3431705SN/A 3441705SN/Astatic int 3451705SN/Achap_IsSet(struct descriptor *d, const fd_set *fdset) 3460SN/A{ 3470SN/A struct chap *chap = descriptor2chap(d); 3481705SN/A 3491705SN/A return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset); 3500SN/A} 3510SN/A 3520SN/Astatic void 353196SN/Achap_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3540SN/A{ 3550SN/A struct chap *chap = descriptor2chap(d); 3560SN/A int got; 357196SN/A 358196SN/A got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len, 3590SN/A sizeof chap->child.buf.ptr - chap->child.buf.len - 1); 3600SN/A if (got == -1) { 3610SN/A log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno)); 3620SN/A chap_Cleanup(chap, SIGTERM); 3630SN/A } else if (got == 0) { 3640SN/A log_Printf(LogWARN, "Chap: Read: Child terminated connection\n"); 3650SN/A chap_Cleanup(chap, SIGTERM); 3660SN/A } else { 3670SN/A char *name, *key, *end; 3680SN/A 3690SN/A chap->child.buf.len += got; 3700SN/A chap->child.buf.ptr[chap->child.buf.len] = '\0'; 3710SN/A name = chap->child.buf.ptr; 3720SN/A name += strspn(name, " \t"); 3730SN/A if ((key = strchr(name, '\n')) == NULL) 3740SN/A end = NULL; 3750SN/A else 3760SN/A end = strchr(++key, '\n'); 3770SN/A 3780SN/A if (end == NULL) { 3790SN/A if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) { 3800SN/A log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n"); 3810SN/A chap_Cleanup(chap, SIGTERM); 3820SN/A } 3830SN/A } else { 3840SN/A#ifdef HAVE_DES 3850SN/A int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 && 3860SN/A ((chap->NTRespSent && 387196SN/A IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) || 3880SN/A !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt)); 3890SN/A#endif 3900SN/A 391 while (end >= name && strchr(" \t\r\n", *end)) 392 *end-- = '\0'; 393 end = key - 1; 394 while (end >= name && strchr(" \t\r\n", *end)) 395 *end-- = '\0'; 396 key += strspn(key, " \t"); 397 398 chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype 399#ifdef HAVE_DES 400 , lanman 401#endif 402 ); 403 chap_Cleanup(chap, 0); 404 } 405 } 406} 407 408static int 409chap_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 410{ 411 /* We never want to write here ! */ 412 log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n"); 413 return 0; 414} 415 416static void 417chap_Challenge(struct authinfo *authp) 418{ 419 struct chap *chap = auth2chap(authp); 420 int len, i; 421 char *cp; 422 423 len = strlen(authp->physical->dl->bundle->cfg.auth.name); 424 425 if (!*chap->challenge.local) { 426 randinit(); 427 cp = chap->challenge.local; 428 429#ifndef NORADIUS 430 if (*authp->physical->dl->bundle->radius.cfg.file) { 431 /* For radius, our challenge is 16 readable NUL terminated bytes :*/ 432 *cp++ = 16; 433 for (i = 0; i < 16; i++) 434 *cp++ = (random() % 10) + '0'; 435 } else 436#endif 437 { 438#ifdef HAVE_DES 439 if (authp->physical->link.lcp.want_authtype == 0x80) 440 *cp++ = 8; /* MS does 8 byte callenges :-/ */ 441 else 442#endif 443 *cp++ = random() % (CHAPCHALLENGELEN-16) + 16; 444 for (i = 0; i < *chap->challenge.local; i++) 445 *cp++ = random() & 0xff; 446 } 447 memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len); 448 } 449 ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge.local, 450 1 + *chap->challenge.local + len, NULL); 451} 452 453static void 454chap_Success(struct authinfo *authp) 455{ 456 datalink_GotAuthname(authp->physical->dl, authp->in.name); 457 ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, "Welcome!!", 10, NULL); 458 authp->physical->link.lcp.auth_ineed = 0; 459 if (Enabled(authp->physical->dl->bundle, OPT_UTMP)) 460 physical_Login(authp->physical, authp->in.name); 461 462 if (authp->physical->link.lcp.auth_iwait == 0) 463 /* 464 * Either I didn't need to authenticate, or I've already been 465 * told that I got the answer right. 466 */ 467 datalink_AuthOk(authp->physical->dl); 468} 469 470static void 471chap_Failure(struct authinfo *authp) 472{ 473 ChapOutput(authp->physical, CHAP_FAILURE, authp->id, "Invalid!!", 9, NULL); 474 datalink_AuthNotOk(authp->physical->dl); 475} 476 477static int 478chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen 479#ifdef HAVE_DES 480 , int lm 481#endif 482 ) 483{ 484 if (mylen != hislen) 485 return 0; 486#ifdef HAVE_DES 487 else if (type == 0x80) { 488 int off = lm ? 0 : 24; 489 490 if (memcmp(myans + off, hisans + off, 24)) 491 return 0; 492 } 493#endif 494 else if (memcmp(myans, hisans, mylen)) 495 return 0; 496 497 return 1; 498} 499 500#ifdef HAVE_DES 501static int 502chap_HaveAnotherGo(struct chap *chap) 503{ 504 if (++chap->peertries < 3) { 505 /* Give the peer another shot */ 506 *chap->challenge.local = '\0'; 507 chap_Challenge(&chap->auth); 508 return 1; 509 } 510 511 return 0; 512} 513#endif 514 515void 516chap_Init(struct chap *chap, struct physical *p) 517{ 518 chap->desc.type = CHAP_DESCRIPTOR; 519 chap->desc.UpdateSet = chap_UpdateSet; 520 chap->desc.IsSet = chap_IsSet; 521 chap->desc.Read = chap_Read; 522 chap->desc.Write = chap_Write; 523 chap->child.pid = 0; 524 chap->child.fd = -1; 525 auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure); 526 *chap->challenge.local = *chap->challenge.peer = '\0'; 527#ifdef HAVE_DES 528 chap->NTRespSent = 0; 529 chap->peertries = 0; 530#endif 531} 532 533void 534chap_ReInit(struct chap *chap) 535{ 536 chap_Cleanup(chap, SIGTERM); 537} 538 539struct mbuf * 540chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 541{ 542 struct physical *p = link2physical(l); 543 struct chap *chap = &p->dl->chap; 544 char *name, *key, *ans; 545 int len, nlen; 546 u_char alen; 547#ifdef HAVE_DES 548 int lanman; 549#endif 550 551 if (p == NULL) { 552 log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n"); 553 mbuf_Free(bp); 554 return NULL; 555 } 556 557 if (bundle_Phase(bundle) != PHASE_NETWORK && 558 bundle_Phase(bundle) != PHASE_AUTHENTICATE) { 559 log_Printf(LogPHASE, "Unexpected chap input - dropped !\n"); 560 mbuf_Free(bp); 561 return NULL; 562 } 563 564 mbuf_SetType(bp, MB_CHAPIN); 565 if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL && 566 ntohs(chap->auth.in.hdr.length) == 0) 567 log_Printf(LogWARN, "Chap Input: Truncated header !\n"); 568 else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE) 569 log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n", 570 chap->auth.in.hdr.code); 571 else { 572 len = mbuf_Length(bp); 573 ans = NULL; 574 575 if (chap->auth.in.hdr.code != CHAP_CHALLENGE && 576 chap->auth.id != chap->auth.in.hdr.id && 577 Enabled(bundle, OPT_IDCHECK)) { 578 /* Wrong conversation dude ! */ 579 log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n", 580 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id, 581 chap->auth.id); 582 mbuf_Free(bp); 583 return NULL; 584 } 585 chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */ 586 587#ifdef HAVE_DES 588 lanman = 0; 589#endif 590 switch (chap->auth.in.hdr.code) { 591 case CHAP_CHALLENGE: 592 bp = mbuf_Read(bp, &alen, 1); 593 len -= alen + 1; 594 if (len < 0) { 595 log_Printf(LogERROR, "Chap Input: Truncated challenge !\n"); 596 mbuf_Free(bp); 597 return NULL; 598 } 599 *chap->challenge.peer = alen; 600 bp = mbuf_Read(bp, chap->challenge.peer + 1, alen); 601 bp = auth_ReadName(&chap->auth, bp, len); 602#ifdef HAVE_DES 603 lanman = p->link.lcp.his_authtype == 0x80 && 604 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) || 605 !IsAccepted(p->link.lcp.cfg.chap80nt)); 606#endif 607 break; 608 609 case CHAP_RESPONSE: 610 auth_StopTimer(&chap->auth); 611 bp = mbuf_Read(bp, &alen, 1); 612 len -= alen + 1; 613 if (len < 0) { 614 log_Printf(LogERROR, "Chap Input: Truncated response !\n"); 615 mbuf_Free(bp); 616 return NULL; 617 } 618 if ((ans = malloc(alen + 2)) == NULL) { 619 log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 620 mbuf_Free(bp); 621 return NULL; 622 } 623 *ans = chap->auth.id; 624 bp = mbuf_Read(bp, ans + 1, alen); 625 ans[alen+1] = '\0'; 626 bp = auth_ReadName(&chap->auth, bp, len); 627#ifdef HAVE_DES 628 lanman = alen == 49 && ans[alen] == 0; 629#endif 630 break; 631 632 case CHAP_SUCCESS: 633 case CHAP_FAILURE: 634 /* chap->auth.in.name is already set up at CHALLENGE time */ 635 if ((ans = malloc(len + 1)) == NULL) { 636 log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 637 mbuf_Free(bp); 638 return NULL; 639 } 640 bp = mbuf_Read(bp, ans, len); 641 ans[len] = '\0'; 642 break; 643 } 644 645 switch (chap->auth.in.hdr.code) { 646 case CHAP_CHALLENGE: 647 case CHAP_RESPONSE: 648 if (*chap->auth.in.name) 649 log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n", 650 chapcodes[chap->auth.in.hdr.code], alen, 651 chap->auth.in.name, 652#ifdef HAVE_DES 653 lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? 654 " - lanman" : 655#endif 656 ""); 657 else 658 log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n", 659 chapcodes[chap->auth.in.hdr.code], alen, 660#ifdef HAVE_DES 661 lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? 662 " - lanman" : 663#endif 664 ""); 665 break; 666 667 case CHAP_SUCCESS: 668 case CHAP_FAILURE: 669 if (*ans) 670 log_Printf(LogPHASE, "Chap Input: %s (%s)\n", 671 chapcodes[chap->auth.in.hdr.code], ans); 672 else 673 log_Printf(LogPHASE, "Chap Input: %s\n", 674 chapcodes[chap->auth.in.hdr.code]); 675 break; 676 } 677 678 switch (chap->auth.in.hdr.code) { 679 case CHAP_CHALLENGE: 680 if (*bundle->cfg.auth.key == '!') 681 chap_StartChild(chap, bundle->cfg.auth.key + 1, 682 bundle->cfg.auth.name); 683 else 684 chap_Respond(chap, bundle->cfg.auth.name, 685 bundle->cfg.auth.key, p->link.lcp.his_authtype 686#ifdef HAVE_DES 687 , lanman 688#endif 689 ); 690 break; 691 692 case CHAP_RESPONSE: 693 name = chap->auth.in.name; 694 nlen = strlen(name); 695#ifndef NORADIUS 696 if (*bundle->radius.cfg.file) { 697 u_char end; 698 699 end = chap->challenge.local[*chap->challenge.local+1]; 700 chap->challenge.local[*chap->challenge.local+1] = '\0'; 701 radius_Authenticate(&bundle->radius, &chap->auth, 702 chap->auth.in.name, ans, 703 chap->challenge.local + 1); 704 chap->challenge.local[*chap->challenge.local+1] = end; 705 } else 706#endif 707 { 708 key = auth_GetSecret(bundle, name, nlen, p); 709 if (key) { 710 char *myans; 711#ifdef HAVE_DES 712 if (lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) { 713 log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n"); 714 if (chap_HaveAnotherGo(chap)) 715 break; 716 key = NULL; 717 } else if (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt) && 718 p->link.lcp.want_authtype == 0x80) { 719 log_Printf(LogPHASE, "Auth failure: mschap not enabled\n"); 720 if (chap_HaveAnotherGo(chap)) 721 break; 722 key = NULL; 723 } else 724#endif 725 { 726 myans = chap_BuildAnswer(name, key, chap->auth.id, 727 chap->challenge.local, 728 p->link.lcp.want_authtype 729#ifdef HAVE_DES 730 , lanman 731#endif 732 ); 733 if (myans == NULL) 734 key = NULL; 735 else { 736 if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans, 737 ans + 1, alen 738#ifdef HAVE_DES 739 , lanman 740#endif 741 )) 742 key = NULL; 743 free(myans); 744 } 745 } 746 } 747 748 if (key) 749 chap_Success(&chap->auth); 750 else 751 chap_Failure(&chap->auth); 752 } 753 754 break; 755 756 case CHAP_SUCCESS: 757 if (p->link.lcp.auth_iwait == PROTO_CHAP) { 758 p->link.lcp.auth_iwait = 0; 759 if (p->link.lcp.auth_ineed == 0) 760 /* 761 * We've succeeded in our ``login'' 762 * If we're not expecting the peer to authenticate (or he already 763 * has), proceed to network phase. 764 */ 765 datalink_AuthOk(p->dl); 766 } 767 break; 768 769 case CHAP_FAILURE: 770 datalink_AuthNotOk(p->dl); 771 break; 772 } 773 free(ans); 774 } 775 776 mbuf_Free(bp); 777 return NULL; 778} 779