chap.c revision 37192
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 * 2037192Sbrian * $Id: chap.c,v 1.32 1998/05/21 22:55:02 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2436285Sbrian#include <sys/types.h> 2530715Sbrian#include <netinet/in.h> 2636285Sbrian#include <netinet/in_systm.h> 2736285Sbrian#include <netinet/ip.h> 2836285Sbrian#include <sys/un.h> 2930715Sbrian 3037192Sbrian#ifdef HAVE_DES 3136287Sbrian#include <md4.h> 3237192Sbrian#endif 3330715Sbrian#include <md5.h> 3430715Sbrian#include <stdlib.h> 3536285Sbrian#include <termios.h> 3629840Sbrian 3730715Sbrian#include "mbuf.h" 3830715Sbrian#include "log.h" 3930715Sbrian#include "defs.h" 4030715Sbrian#include "timer.h" 416059Samurai#include "fsm.h" 426059Samurai#include "lcpproto.h" 436059Samurai#include "lcp.h" 4436285Sbrian#include "lqr.h" 456059Samurai#include "hdlc.h" 466735Samurai#include "auth.h" 4736285Sbrian#include "chap.h" 4836285Sbrian#include "async.h" 4936285Sbrian#include "throughput.h" 5036285Sbrian#include "descriptor.h" 5136285Sbrian#include "iplist.h" 5236285Sbrian#include "slcompress.h" 5336285Sbrian#include "ipcp.h" 5436285Sbrian#include "filter.h" 5536285Sbrian#include "ccp.h" 5636285Sbrian#include "link.h" 5736285Sbrian#include "physical.h" 5836285Sbrian#include "mp.h" 5936285Sbrian#include "bundle.h" 6036285Sbrian#include "chat.h" 6136285Sbrian#include "datalink.h" 6237192Sbrian#ifdef HAVE_DES 6336287Sbrian#include "chap_ms.h" 6437192Sbrian#endif 656059Samurai 6631343Sbrianstatic const char *chapcodes[] = { 6719866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 686059Samurai}; 696059Samurai 7030715Sbrianstatic void 7136285SbrianChapOutput(struct physical *physical, u_int code, u_int id, 7236285Sbrian const u_char * ptr, int count) 736059Samurai{ 746059Samurai int plen; 756059Samurai struct fsmheader lh; 766059Samurai struct mbuf *bp; 776059Samurai 7828679Sbrian plen = sizeof(struct fsmheader) + count; 796059Samurai lh.code = code; 806059Samurai lh.id = id; 816059Samurai lh.length = htons(plen); 8236285Sbrian bp = mbuf_Alloc(plen, MB_FSM); 8330715Sbrian memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 846059Samurai if (count) 8530715Sbrian memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 8636285Sbrian log_DumpBp(LogDEBUG, "ChapOutput", bp); 8736285Sbrian log_Printf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 8836285Sbrian hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); 896059Samurai} 906059Samurai 9136285Sbrianvoid 9236285Sbrianchap_SendChallenge(struct authinfo *auth, int chapid, struct physical *physical) 936059Samurai{ 9436285Sbrian struct chap *chap = auth2chap(auth); 9513379Sphk int len, i; 966059Samurai char *cp; 976059Samurai 9830715Sbrian randinit(); 9936285Sbrian cp = chap->challenge_data; 10036285Sbrian *cp++ = chap->challenge_len = random() % 32 + 16; 10136285Sbrian for (i = 0; i < chap->challenge_len; i++) 1026059Samurai *cp++ = random() & 0xff; 10336285Sbrian len = strlen(physical->dl->bundle->cfg.auth.name); 10436285Sbrian memcpy(cp, physical->dl->bundle->cfg.auth.name, len); 1056059Samurai cp += len; 10636285Sbrian ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, 10736285Sbrian cp - chap->challenge_data); 1086059Samurai} 1096059Samurai 11030715Sbrianstatic void 11136285SbrianRecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 11236285Sbrian struct physical *physical) 1136059Samurai{ 1146059Samurai int valsize, len; 1156059Samurai int arglen, keylen, namelen; 1166059Samurai char *cp, *argp, *ap, *name, *digest; 1176059Samurai char *keyp; 11829549Sbrian MD5_CTX MD5context; /* context for MD5 */ 1196059Samurai char answer[100]; 1206059Samurai char cdigest[16]; 12129840Sbrian#ifdef HAVE_DES 12229840Sbrian int ix; 12329840Sbrian MD4_CTX MD4context; /* context for MD4 */ 12429840Sbrian#endif 1256059Samurai 1266059Samurai len = ntohs(chp->length); 12736285Sbrian log_Printf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 1286059Samurai arglen = len - sizeof(struct fsmheader); 12928679Sbrian cp = (char *) MBUF_CTOP(bp); 1306059Samurai valsize = *cp++ & 255; 1316059Samurai name = cp + valsize; 1326059Samurai namelen = arglen - valsize - 1; 1336059Samurai name[namelen] = 0; 13436285Sbrian log_Printf(LogLCP, " Valsize = %d, Name = \"%s\"\n", valsize, name); 1356059Samurai 1366059Samurai switch (chp->code) { 1376059Samurai case CHAP_CHALLENGE: 13836285Sbrian keyp = bundle->cfg.auth.key; 13936285Sbrian keylen = strlen(bundle->cfg.auth.key); 14036285Sbrian name = bundle->cfg.auth.name; 14136285Sbrian namelen = strlen(bundle->cfg.auth.name); 14229840Sbrian 14329840Sbrian#ifdef HAVE_DES 14436285Sbrian if (physical->dl->chap.using_MSChap) 14529840Sbrian argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); 14629840Sbrian else 14729840Sbrian#endif 14829840Sbrian argp = malloc(1 + valsize + namelen + 16); 14929840Sbrian 15025630Sbrian if (argp == NULL) { 15136285Sbrian ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14); 15225630Sbrian return; 15325630Sbrian } 15429840Sbrian#ifdef HAVE_DES 15536285Sbrian if (physical->dl->chap.using_MSChap) { 15629840Sbrian digest = argp; /* this is the response */ 15729840Sbrian *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 15830715Sbrian memset(digest, '\0', 24); 15930715Sbrian digest += 24; 16029840Sbrian 16129840Sbrian ap = answer; /* this is the challenge */ 16230715Sbrian memcpy(ap, keyp, keylen); 16329840Sbrian ap += 2 * keylen; 16430715Sbrian memcpy(ap, cp, valsize); 16536285Sbrian log_DumpBuff(LogDEBUG, "recv", ap, valsize); 16629840Sbrian ap += valsize; 16729840Sbrian for (ix = keylen; ix > 0 ; ix--) { 16829840Sbrian answer[2*ix-2] = answer[ix-1]; 16929840Sbrian answer[2*ix-1] = 0; 17029840Sbrian } 17129549Sbrian MD4Init(&MD4context); 17229840Sbrian MD4Update(&MD4context, answer, 2 * keylen); 17329549Sbrian MD4Final(digest, &MD4context); 17430715Sbrian memcpy(digest + 25, name, namelen); 17529840Sbrian ap += 2 * keylen; 17636285Sbrian chap_MS(digest, answer + 2 * keylen, valsize); 17736285Sbrian log_DumpBuff(LogDEBUG, "answer", digest, 24); 17836285Sbrian ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, 17936285Sbrian namelen + MS_CHAP_RESPONSE_LEN + 1); 18029549Sbrian } else { 18129840Sbrian#endif 18229840Sbrian digest = argp; 18329840Sbrian *digest++ = 16; /* value size */ 18429840Sbrian ap = answer; 18529840Sbrian *ap++ = chp->id; 18630715Sbrian memcpy(ap, keyp, keylen); 18729840Sbrian ap += keylen; 18830715Sbrian memcpy(ap, cp, valsize); 18936285Sbrian log_DumpBuff(LogDEBUG, "recv", ap, valsize); 19029840Sbrian ap += valsize; 19129549Sbrian MD5Init(&MD5context); 19229549Sbrian MD5Update(&MD5context, answer, ap - answer); 19329549Sbrian MD5Final(digest, &MD5context); 19436285Sbrian log_DumpBuff(LogDEBUG, "answer", digest, 16); 19530715Sbrian memcpy(digest + 16, name, namelen); 19629840Sbrian ap += namelen; 19729840Sbrian /* Send answer to the peer */ 19836285Sbrian ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17); 19929840Sbrian#ifdef HAVE_DES 20029549Sbrian } 20129840Sbrian#endif 20218885Sjkh free(argp); 2036059Samurai break; 2046059Samurai case CHAP_RESPONSE: 20531051Sbrian /* 20631051Sbrian * Get a secret key corresponds to the peer 20731051Sbrian */ 20836285Sbrian keyp = auth_GetSecret(bundle, name, namelen, physical); 2096059Samurai if (keyp) { 2106059Samurai /* 2116059Samurai * Compute correct digest value 2126059Samurai */ 2136059Samurai keylen = strlen(keyp); 2146059Samurai ap = answer; 2156059Samurai *ap++ = chp->id; 21630715Sbrian memcpy(ap, keyp, keylen); 2176059Samurai ap += keylen; 21829840Sbrian MD5Init(&MD5context); 21929840Sbrian MD5Update(&MD5context, answer, ap - answer); 22036285Sbrian MD5Update(&MD5context, physical->dl->chap.challenge_data + 1, 22136285Sbrian physical->dl->chap.challenge_len); 22229840Sbrian MD5Final(cdigest, &MD5context); 22336285Sbrian log_DumpBuff(LogDEBUG, "got", cp, 16); 22436285Sbrian log_DumpBuff(LogDEBUG, "expect", cdigest, 16); 22528679Sbrian 2266059Samurai /* 2276059Samurai * Compare with the response 2286059Samurai */ 22930715Sbrian if (memcmp(cp, cdigest, 16) == 0) { 23036285Sbrian datalink_GotAuthname(physical->dl, name, namelen); 23136285Sbrian ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10); 23236285Sbrian if (Enabled(bundle, OPT_UTMP)) 23336285Sbrian physical_Login(physical, name); 23436285Sbrian 23536285Sbrian if (physical->link.lcp.auth_iwait == 0) 23636285Sbrian /* 23736285Sbrian * Either I didn't need to authenticate, or I've already been 23836285Sbrian * told that I got the answer right. 23936285Sbrian */ 24036285Sbrian datalink_AuthOk(physical->dl); 24136285Sbrian 2426059Samurai break; 2436059Samurai } 2446059Samurai } 24528679Sbrian 2466059Samurai /* 2476059Samurai * Peer is not registerd, or response digest is wrong. 2486059Samurai */ 24936285Sbrian ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9); 25036285Sbrian datalink_AuthNotOk(physical->dl); 2516059Samurai break; 2526059Samurai } 2536059Samurai} 2546059Samurai 25530715Sbrianstatic void 25636285SbrianRecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 25736285Sbrian struct physical *physical) 2586059Samurai{ 2596059Samurai int len; 2606059Samurai 2616059Samurai len = ntohs(chp->length); 26236285Sbrian log_Printf(LogDEBUG, "RecvChapResult: length: %d\n", len); 2636059Samurai if (chp->code == CHAP_SUCCESS) { 26436285Sbrian if (physical->link.lcp.auth_iwait == PROTO_CHAP) { 26536285Sbrian physical->link.lcp.auth_iwait = 0; 26636285Sbrian if (physical->link.lcp.auth_ineed == 0) 26736285Sbrian /* 26836285Sbrian * We've succeeded in our ``login'' 26936285Sbrian * If we're not expecting the peer to authenticate (or he already 27036285Sbrian * has), proceed to network phase. 27136285Sbrian */ 27236285Sbrian datalink_AuthOk(physical->dl); 2736059Samurai } 2746059Samurai } else { 27536285Sbrian /* CHAP failed - it's not going to get any better */ 27636285Sbrian log_Printf(LogPHASE, "Received CHAP_FAILURE\n"); 27736285Sbrian datalink_AuthNotOk(physical->dl); 2786059Samurai } 2796059Samurai} 2806059Samurai 2816059Samuraivoid 28236285Sbrianchap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) 2836059Samurai{ 28436285Sbrian int len = mbuf_Length(bp); 2856059Samurai struct fsmheader *chp; 2866059Samurai 2876059Samurai if (len >= sizeof(struct fsmheader)) { 28828679Sbrian chp = (struct fsmheader *) MBUF_CTOP(bp); 2896059Samurai if (len >= ntohs(chp->length)) { 2906059Samurai if (chp->code < 1 || chp->code > 4) 2916059Samurai chp->code = 0; 29236285Sbrian log_Printf(LogLCP, "chap_Input: %s\n", chapcodes[chp->code]); 2936059Samurai 2946059Samurai bp->offset += sizeof(struct fsmheader); 2956059Samurai bp->cnt -= sizeof(struct fsmheader); 2966059Samurai 2976059Samurai switch (chp->code) { 2986735Samurai case CHAP_RESPONSE: 29936285Sbrian auth_StopTimer(&physical->dl->chap.auth); 3006735Samurai /* Fall into.. */ 3016059Samurai case CHAP_CHALLENGE: 30236285Sbrian RecvChapTalk(bundle, chp, bp, physical); 3036059Samurai break; 3046059Samurai case CHAP_SUCCESS: 3056059Samurai case CHAP_FAILURE: 30636285Sbrian RecvChapResult(bundle, chp, bp, physical); 3076059Samurai break; 3086059Samurai } 3096059Samurai } 3106059Samurai } 31136285Sbrian mbuf_Free(bp); 3126059Samurai} 313