chap.c revision 23968
18097Sjkh/* 28097Sjkh * PPP CHAP Module 38097Sjkh * 48097Sjkh * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 58097Sjkh * 68097Sjkh * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 729628Sjkh * 88097Sjkh * Redistribution and use in source and binary forms are permitted 98097Sjkh * provided that the above copyright notice and this paragraph are 108097Sjkh * duplicated in all such forms and that any documentation, 118097Sjkh * advertising materials, and other materials related to such 128097Sjkh * distribution and use acknowledge that the software was developed 138097Sjkh * by the Internet Initiative Japan, Inc. The name of the 148097Sjkh * IIJ may not be used to endorse or promote products derived 158097Sjkh * from this software without specific prior written permission. 168881Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 178881Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 188097Sjkh * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198097Sjkh * 208097Sjkh * $Id: chap.c,v 1.11 1997/03/10 08:04:13 ache Exp $ 218097Sjkh * 228097Sjkh * TODO: 238097Sjkh */ 248097Sjkh#include <sys/types.h> 258097Sjkh#include <time.h> 268097Sjkh#include "fsm.h" 278097Sjkh#include "chap.h" 288097Sjkh#include "lcpproto.h" 298097Sjkh#include "lcp.h" 308097Sjkh#include "hdlc.h" 318097Sjkh#include "phase.h" 328097Sjkh#include "vars.h" 338097Sjkh#include "auth.h" 348097Sjkh 358097Sjkhstatic char *chapcodes[] = { 368097Sjkh "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 378097Sjkh}; 388097Sjkh 398825Sjkhstruct authinfo AuthChapInfo = { 408825Sjkh SendChapChallenge, 418097Sjkh}; 428837Sjkh 438837Sjkhextern char *AuthGetSecret(); 448837Sjkhextern int randinit; 4512661Speter 4612661Spetervoid 4712661SpeterChapOutput(code, id, ptr, count) 488837Sjkhu_int code, id; 498837Sjkhu_char *ptr; 508262Sjkhint count; 518262Sjkh{ 528262Sjkh int plen; 538262Sjkh struct fsmheader lh; 548262Sjkh struct mbuf *bp; 558262Sjkh 568262Sjkh plen = sizeof(struct fsmheader) + count; 578262Sjkh lh.code = code; 5815416Sjkh lh.id = id; 598262Sjkh lh.length = htons(plen); 608347Sjkh bp = mballoc(plen, MB_FSM); 618262Sjkh bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 628262Sjkh if (count) 638314Sjkh bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 6417375Sjkh#ifdef DEBUG 658262Sjkh DumpBp(bp); 668262Sjkh#endif 678262Sjkh LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]); 688262Sjkh HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 698097Sjkh} 708097Sjkh 718097Sjkh 728097Sjkhstatic char challenge_data[80]; 738097Sjkhstatic int challenge_len; 748097Sjkh 758705Sjkhvoid 768705SjkhSendChapChallenge(chapid) 778097Sjkhint chapid; 788705Sjkh{ 798641Sjkh int len, i; 808641Sjkh char *cp; 8117375Sjkh 828641Sjkh if (!randinit) { 838641Sjkh srandom((unsigned long)(time(NULL) ^ getpid())); 848641Sjkh randinit = 1; 8515416Sjkh } 868097Sjkh 878347Sjkh cp = challenge_data; 888097Sjkh *cp++ = challenge_len = random() % 32 + 16; 898705Sjkh for (i = 0; i < challenge_len; i++) 908705Sjkh *cp++ = random() & 0xff; 918705Sjkh len = strlen(VarAuthName); 928705Sjkh bcopy(VarAuthName, cp, len); 938705Sjkh cp += len; 948705Sjkh ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 958705Sjkh} 968705Sjkh 9716366Sjkh#ifdef DEBUG 9817375Sjkhvoid 998262SjkhDumpDigest(mes, cp, len) 10017375Sjkhchar *mes; 1018262Sjkhchar *cp; 1028097Sjkhint len; 1038097Sjkh{ 1048097Sjkh int i; 1058097Sjkh 1068097Sjkh logprintf("%s: ", mes); 1078097Sjkh for (i = 0; i < len; i++) { 1088097Sjkh logprintf(" %02x", *cp++ & 0xff); 1098097Sjkh } 1108262Sjkh logprintf("\n"); 1118097Sjkh} 11215416Sjkh#endif 1138097Sjkh 1148097Sjkhvoid 1158097SjkhRecvChapTalk(chp, bp) 1168097Sjkhstruct fsmheader *chp; 1178262Sjkhstruct mbuf *bp; 1188097Sjkh{ 11916366Sjkh int valsize, len; 12017375Sjkh int arglen, keylen, namelen; 1218262Sjkh char *cp, *argp, *ap, *name, *digest; 1228262Sjkh char *keyp; 1238837Sjkh MD5_CTX context; /* context */ 1248628Sjkh char answer[100]; 1258097Sjkh char cdigest[16]; 1268097Sjkh 1278097Sjkh len = ntohs(chp->length); 1288097Sjkh#ifdef DEBUG 1298097Sjkh logprintf("length: %d\n", len); 1308097Sjkh#endif 1318097Sjkh arglen = len - sizeof(struct fsmheader); 1328097Sjkh cp = (char *)MBUF_CTOP(bp); 1338262Sjkh valsize = *cp++ & 255; 1348097Sjkh name = cp + valsize; 13515416Sjkh namelen = arglen - valsize - 1; 1368097Sjkh name[namelen] = 0; 1378097Sjkh LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name); 1388097Sjkh 1398097Sjkh /* 1408097Sjkh * Get a secret key corresponds to the peer 1418262Sjkh */ 14216366Sjkh keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 14317375Sjkh 1448262Sjkh switch (chp->code) { 1458262Sjkh case CHAP_CHALLENGE: 1468837Sjkh if (keyp) { 1478628Sjkh keylen = strlen(keyp); 1488097Sjkh } else { 1498097Sjkh keylen = strlen(VarAuthKey); 1508097Sjkh keyp = VarAuthKey; 1518097Sjkh } 1528097Sjkh name = VarAuthName; 1538097Sjkh namelen = strlen(VarAuthName); 1548097Sjkh argp = malloc(1 + valsize + namelen + 16); 1558097Sjkh digest = argp; 1568262Sjkh *digest++ = 16; /* value size */ 1578097Sjkh ap = answer; 15815416Sjkh *ap++ = chp->id; 1598097Sjkh bcopy(keyp, ap, keylen); 1608097Sjkh ap += keylen; 1618097Sjkh bcopy(cp, ap, valsize); 1628097Sjkh#ifdef DEBUG 1638097Sjkh DumpDigest("recv", ap, valsize); 1648262Sjkh#endif 16516366Sjkh ap += valsize; 16617375Sjkh MD5Init(&context); 1678097Sjkh MD5Update(&context, answer, ap - answer); 1688097Sjkh MD5Final(digest, &context); 1698097Sjkh#ifdef DEBUG 1708097Sjkh DumpDigest("answer", digest, 16); 1718097Sjkh#endif 1728097Sjkh bcopy(name, digest + 16, namelen); 1738262Sjkh ap += namelen; 1748262Sjkh /* Send answer to the peer */ 1758628Sjkh ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 1768628Sjkh free(argp); 1778097Sjkh break; 17815788Sjkh case CHAP_RESPONSE: 1798097Sjkh if (keyp) { 1808097Sjkh /* 1818208Sjkh * Compute correct digest value 1828208Sjkh */ 1838208Sjkh keylen = strlen(keyp); 1848208Sjkh ap = answer; 1858208Sjkh *ap++ = chp->id; 1868208Sjkh bcopy(keyp, ap, keylen); 1878208Sjkh ap += keylen; 18815416Sjkh MD5Init(&context); 1898208Sjkh MD5Update(&context, answer, ap - answer); 1908208Sjkh MD5Update(&context, challenge_data+1, challenge_len); 1918208Sjkh MD5Final(cdigest, &context); 1928208Sjkh#ifdef DEBUG 1938208Sjkh DumpDigest("got", cp, 16); 1948640Sjkh DumpDigest("expect", cdigest, 16); 1959202Srgrimes#endif 1968641Sjkh /* 1978640Sjkh * Compare with the response 1988556Sjkh */ 1998208Sjkh if (bcmp(cp, cdigest, 16) == 0) { 2008208Sjkh ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 2018302Sjkh NewPhase(PHASE_NETWORK); 2028302Sjkh break; 2038302Sjkh } 2048302Sjkh } 2058302Sjkh /* 2068302Sjkh * Peer is not registerd, or response digest is wrong. 2078302Sjkh */ 20815416Sjkh ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 2098302Sjkh LcpClose(); 2108302Sjkh break; 2118302Sjkh } 2128302Sjkh} 2138302Sjkh 2148837Sjkhvoid 2158837SjkhRecvChapResult(chp, bp) 21617404Sjkhstruct fsmheader *chp; 21729628Sjkhstruct mbuf *bp; 2188302Sjkh{ 2198302Sjkh int len; 2208208Sjkh struct lcpstate *lcp = &LcpInfo; 2218208Sjkh 2228208Sjkh len = ntohs(chp->length); 2238208Sjkh#ifdef DEBUG 2248208Sjkh logprintf("length: %d\n", len); 2258208Sjkh#endif 2268208Sjkh if (chp->code == CHAP_SUCCESS) { 2278208Sjkh if (lcp->auth_iwait == PROTO_CHAP) { 22815416Sjkh lcp->auth_iwait = 0; 2298208Sjkh if (lcp->auth_ineed == 0) 2308208Sjkh NewPhase(PHASE_NETWORK); 2318208Sjkh } 2328208Sjkh } else { 2338208Sjkh /* 2348640Sjkh * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 2359202Srgrimes */ 2368641Sjkh ; 2378640Sjkh } 2388281Sjkh} 2398208Sjkh 2408208Sjkhvoid 2418262SjkhChapInput(struct mbuf *bp) 2428262Sjkh{ 2438262Sjkh int len = plength(bp); 2448262Sjkh struct fsmheader *chp; 2458262Sjkh 2468262Sjkh if (len >= sizeof(struct fsmheader)) { 2478262Sjkh chp = (struct fsmheader *)MBUF_CTOP(bp); 2488278Sjkh if (len >= ntohs(chp->length)) { 2498262Sjkh if (chp->code < 1 || chp->code > 4) 2508262Sjkh chp->code = 0; 25115416Sjkh LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]); 2528262Sjkh 2538262Sjkh bp->offset += sizeof(struct fsmheader); 2548262Sjkh bp->cnt -= sizeof(struct fsmheader); 2558262Sjkh 2568262Sjkh switch (chp->code) { 2578302Sjkh case CHAP_RESPONSE: 25820247Sjkh StopAuthTimer(&AuthChapInfo); 2598302Sjkh /* Fall into.. */ 2608302Sjkh case CHAP_CHALLENGE: 2618640Sjkh RecvChapTalk(chp, bp); 2629202Srgrimes break; 2638641Sjkh case CHAP_SUCCESS: 2648640Sjkh case CHAP_FAILURE: 2658262Sjkh RecvChapResult(chp, bp); 2668262Sjkh break; 2678262Sjkh } 2688262Sjkh } 2698262Sjkh } 2708262Sjkh pfree(bp); 2718262Sjkh} 2728347Sjkh