chap.c revision 25630
16059Samurai/* 26059Samurai * PPP CHAP Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198857Srgrimes * 2025630Sbrian * $Id: chap.c,v 1.13 1997/03/24 16:01:42 ache Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2413379Sphk#include <sys/types.h> 2513379Sphk#include <time.h> 266059Samurai#include "fsm.h" 276059Samurai#include "chap.h" 286059Samurai#include "lcpproto.h" 296059Samurai#include "lcp.h" 306059Samurai#include "hdlc.h" 316059Samurai#include "phase.h" 326059Samurai#include "vars.h" 336735Samurai#include "auth.h" 346059Samurai 356059Samuraistatic char *chapcodes[] = { 3619866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 376059Samurai}; 386059Samurai 396735Samuraistruct authinfo AuthChapInfo = { 406735Samurai SendChapChallenge, 416735Samurai}; 426735Samurai 436059Samuraiextern char *AuthGetSecret(); 4423603Sacheextern int randinit; 456059Samurai 466059Samuraivoid 476059SamuraiChapOutput(code, id, ptr, count) 486059Samuraiu_int code, id; 496059Samuraiu_char *ptr; 506059Samuraiint count; 516059Samurai{ 526059Samurai int plen; 536059Samurai struct fsmheader lh; 546059Samurai struct mbuf *bp; 556059Samurai 566059Samurai plen = sizeof(struct fsmheader) + count; 576059Samurai lh.code = code; 586059Samurai lh.id = id; 596059Samurai lh.length = htons(plen); 606059Samurai bp = mballoc(plen, MB_FSM); 616059Samurai bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 626059Samurai if (count) 636059Samurai bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 646059Samurai#ifdef DEBUG 656059Samurai DumpBp(bp); 666059Samurai#endif 6715738Sphk LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]); 6813733Sdfr HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 696059Samurai} 706059Samurai 716059Samurai 726059Samuraistatic char challenge_data[80]; 736059Samuraistatic int challenge_len; 746059Samurai 756059Samuraivoid 766735SamuraiSendChapChallenge(chapid) 776735Samuraiint chapid; 786059Samurai{ 7913379Sphk int len, i; 806059Samurai char *cp; 816059Samurai 8223603Sache if (!randinit) { 8323603Sache randinit = 1; 8424217Sache if (srandomdev() < 0) 8524217Sache srandom((unsigned long)(time(NULL) ^ getpid())); 8623603Sache } 876059Samurai 886059Samurai cp = challenge_data; 896059Samurai *cp++ = challenge_len = random() % 32 + 16; 906059Samurai for (i = 0; i < challenge_len; i++) 916059Samurai *cp++ = random() & 0xff; 926059Samurai len = strlen(VarAuthName); 936059Samurai bcopy(VarAuthName, cp, len); 946059Samurai cp += len; 956059Samurai ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 966059Samurai} 976059Samurai 986059Samurai#ifdef DEBUG 996059Samuraivoid 1006059SamuraiDumpDigest(mes, cp, len) 1016059Samuraichar *mes; 1026059Samuraichar *cp; 1036735Samuraiint len; 1046059Samurai{ 1056059Samurai int i; 1066059Samurai 1076059Samurai logprintf("%s: ", mes); 1086059Samurai for (i = 0; i < len; i++) { 1096059Samurai logprintf(" %02x", *cp++ & 0xff); 1106059Samurai } 1116059Samurai logprintf("\n"); 1126059Samurai} 1136059Samurai#endif 1146059Samurai 1156059Samuraivoid 1166059SamuraiRecvChapTalk(chp, bp) 1176059Samuraistruct fsmheader *chp; 1186059Samuraistruct mbuf *bp; 1196059Samurai{ 1206059Samurai int valsize, len; 1216059Samurai int arglen, keylen, namelen; 1226059Samurai char *cp, *argp, *ap, *name, *digest; 1236059Samurai char *keyp; 1246059Samurai MD5_CTX context; /* context */ 1256059Samurai char answer[100]; 1266059Samurai char cdigest[16]; 1276059Samurai 1286059Samurai len = ntohs(chp->length); 1296059Samurai#ifdef DEBUG 1306059Samurai logprintf("length: %d\n", len); 1316059Samurai#endif 1326059Samurai arglen = len - sizeof(struct fsmheader); 1336059Samurai cp = (char *)MBUF_CTOP(bp); 1346059Samurai valsize = *cp++ & 255; 1356059Samurai name = cp + valsize; 1366059Samurai namelen = arglen - valsize - 1; 1376059Samurai name[namelen] = 0; 13815738Sphk LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name); 1396059Samurai 1406059Samurai /* 1416059Samurai * Get a secret key corresponds to the peer 1426059Samurai */ 1436059Samurai keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 1446059Samurai 1456059Samurai switch (chp->code) { 1466059Samurai case CHAP_CHALLENGE: 1476059Samurai if (keyp) { 1486059Samurai keylen = strlen(keyp); 1496059Samurai } else { 1506059Samurai keylen = strlen(VarAuthKey); 1516059Samurai keyp = VarAuthKey; 1526059Samurai } 1536059Samurai name = VarAuthName; 1546059Samurai namelen = strlen(VarAuthName); 15518885Sjkh argp = malloc(1 + valsize + namelen + 16); 15625630Sbrian if (argp == NULL) { 15725630Sbrian ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); 15825630Sbrian return; 15925630Sbrian } 1606059Samurai digest = argp; 1616059Samurai *digest++ = 16; /* value size */ 1626059Samurai ap = answer; 1636059Samurai *ap++ = chp->id; 1646059Samurai bcopy(keyp, ap, keylen); 1656059Samurai ap += keylen; 1666059Samurai bcopy(cp, ap, valsize); 1676059Samurai#ifdef DEBUG 1686059Samurai DumpDigest("recv", ap, valsize); 1696059Samurai#endif 1706059Samurai ap += valsize; 1716059Samurai MD5Init(&context); 1726059Samurai MD5Update(&context, answer, ap - answer); 1736059Samurai MD5Final(digest, &context); 1746059Samurai#ifdef DEBUG 1756059Samurai DumpDigest("answer", digest, 16); 1766059Samurai#endif 1776059Samurai bcopy(name, digest + 16, namelen); 1786059Samurai ap += namelen; 1796059Samurai /* Send answer to the peer */ 1806059Samurai ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 18118885Sjkh free(argp); 1826059Samurai break; 1836059Samurai case CHAP_RESPONSE: 1846059Samurai if (keyp) { 1856059Samurai /* 1866059Samurai * Compute correct digest value 1876059Samurai */ 1886059Samurai keylen = strlen(keyp); 1896059Samurai ap = answer; 1906059Samurai *ap++ = chp->id; 1916059Samurai bcopy(keyp, ap, keylen); 1926059Samurai ap += keylen; 1936059Samurai MD5Init(&context); 1946059Samurai MD5Update(&context, answer, ap - answer); 1956059Samurai MD5Update(&context, challenge_data+1, challenge_len); 1966059Samurai MD5Final(cdigest, &context); 1976059Samurai#ifdef DEBUG 1986059Samurai DumpDigest("got", cp, 16); 1996059Samurai DumpDigest("expect", cdigest, 16); 2006059Samurai#endif 2016059Samurai /* 2026059Samurai * Compare with the response 2036059Samurai */ 2046059Samurai if (bcmp(cp, cdigest, 16) == 0) { 2056059Samurai ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 2066059Samurai NewPhase(PHASE_NETWORK); 2076059Samurai break; 2086059Samurai } 2096059Samurai } 2106059Samurai /* 2116059Samurai * Peer is not registerd, or response digest is wrong. 2126059Samurai */ 2136059Samurai ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 2146059Samurai LcpClose(); 2156059Samurai break; 2166059Samurai } 2176059Samurai} 2186059Samurai 2196059Samuraivoid 2206059SamuraiRecvChapResult(chp, bp) 2216059Samuraistruct fsmheader *chp; 2226059Samuraistruct mbuf *bp; 2236059Samurai{ 2246059Samurai int len; 2256059Samurai struct lcpstate *lcp = &LcpInfo; 2266059Samurai 2276059Samurai len = ntohs(chp->length); 2286059Samurai#ifdef DEBUG 2296059Samurai logprintf("length: %d\n", len); 2306059Samurai#endif 2316059Samurai if (chp->code == CHAP_SUCCESS) { 2326059Samurai if (lcp->auth_iwait == PROTO_CHAP) { 2336059Samurai lcp->auth_iwait = 0; 2346059Samurai if (lcp->auth_ineed == 0) 2356059Samurai NewPhase(PHASE_NETWORK); 2366059Samurai } 2376059Samurai } else { 2386059Samurai /* 2396059Samurai * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 2406059Samurai */ 2416059Samurai ; 2426059Samurai } 2436059Samurai} 2446059Samurai 2456059Samuraivoid 2466059SamuraiChapInput(struct mbuf *bp) 2476059Samurai{ 2486059Samurai int len = plength(bp); 2496059Samurai struct fsmheader *chp; 2506059Samurai 2516059Samurai if (len >= sizeof(struct fsmheader)) { 2526059Samurai chp = (struct fsmheader *)MBUF_CTOP(bp); 2536059Samurai if (len >= ntohs(chp->length)) { 2546059Samurai if (chp->code < 1 || chp->code > 4) 2556059Samurai chp->code = 0; 25615738Sphk LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]); 2576059Samurai 2586059Samurai bp->offset += sizeof(struct fsmheader); 2596059Samurai bp->cnt -= sizeof(struct fsmheader); 2606059Samurai 2616059Samurai switch (chp->code) { 2626735Samurai case CHAP_RESPONSE: 2636735Samurai StopAuthTimer(&AuthChapInfo); 2646735Samurai /* Fall into.. */ 2656059Samurai case CHAP_CHALLENGE: 2666059Samurai RecvChapTalk(chp, bp); 2676059Samurai break; 2686059Samurai case CHAP_SUCCESS: 2696059Samurai case CHAP_FAILURE: 2706059Samurai RecvChapResult(chp, bp); 2716059Samurai break; 2726059Samurai } 2736059Samurai } 2746059Samurai } 2756059Samurai pfree(bp); 2766059Samurai} 277