chap.c revision 36287
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 * 2036287Sbrian * $Id: chap.c,v 1.31 1998/05/21 21:44:25 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 3036287Sbrian#include <md4.h> 3130715Sbrian#include <md5.h> 3230715Sbrian#include <stdlib.h> 3336287Sbrian#include <string.h> 3436285Sbrian#include <termios.h> 3529840Sbrian 3630715Sbrian#include "mbuf.h" 3730715Sbrian#include "log.h" 3830715Sbrian#include "defs.h" 3930715Sbrian#include "timer.h" 406059Samurai#include "fsm.h" 416059Samurai#include "lcpproto.h" 426059Samurai#include "lcp.h" 4336285Sbrian#include "lqr.h" 446059Samurai#include "hdlc.h" 456735Samurai#include "auth.h" 4636285Sbrian#include "chap.h" 4736285Sbrian#include "async.h" 4836285Sbrian#include "throughput.h" 4936285Sbrian#include "descriptor.h" 5036285Sbrian#include "iplist.h" 5136285Sbrian#include "slcompress.h" 5236285Sbrian#include "ipcp.h" 5336285Sbrian#include "filter.h" 5436285Sbrian#include "ccp.h" 5536285Sbrian#include "link.h" 5636285Sbrian#include "physical.h" 5736285Sbrian#include "mp.h" 5836285Sbrian#include "bundle.h" 5936285Sbrian#include "chat.h" 6036285Sbrian#include "datalink.h" 6136287Sbrian#include "chap_ms.h" 626059Samurai 6331343Sbrianstatic const char *chapcodes[] = { 6419866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 656059Samurai}; 666059Samurai 6730715Sbrianstatic void 6836285SbrianChapOutput(struct physical *physical, u_int code, u_int id, 6936285Sbrian const u_char * ptr, int count) 706059Samurai{ 716059Samurai int plen; 726059Samurai struct fsmheader lh; 736059Samurai struct mbuf *bp; 746059Samurai 7528679Sbrian plen = sizeof(struct fsmheader) + count; 766059Samurai lh.code = code; 776059Samurai lh.id = id; 786059Samurai lh.length = htons(plen); 7936285Sbrian bp = mbuf_Alloc(plen, MB_FSM); 8030715Sbrian memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 816059Samurai if (count) 8230715Sbrian memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 8336285Sbrian log_DumpBp(LogDEBUG, "ChapOutput", bp); 8436285Sbrian log_Printf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 8536285Sbrian hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); 866059Samurai} 876059Samurai 8836285Sbrianvoid 8936285Sbrianchap_SendChallenge(struct authinfo *auth, int chapid, struct physical *physical) 906059Samurai{ 9136285Sbrian struct chap *chap = auth2chap(auth); 9213379Sphk int len, i; 936059Samurai char *cp; 946059Samurai 9530715Sbrian randinit(); 9636285Sbrian cp = chap->challenge_data; 9736285Sbrian *cp++ = chap->challenge_len = random() % 32 + 16; 9836285Sbrian for (i = 0; i < chap->challenge_len; i++) 996059Samurai *cp++ = random() & 0xff; 10036285Sbrian len = strlen(physical->dl->bundle->cfg.auth.name); 10136285Sbrian memcpy(cp, physical->dl->bundle->cfg.auth.name, len); 1026059Samurai cp += len; 10336285Sbrian ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, 10436285Sbrian cp - chap->challenge_data); 1056059Samurai} 1066059Samurai 10730715Sbrianstatic void 10836285SbrianRecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 10936285Sbrian struct physical *physical) 1106059Samurai{ 1116059Samurai int valsize, len; 1126059Samurai int arglen, keylen, namelen; 1136059Samurai char *cp, *argp, *ap, *name, *digest; 1146059Samurai char *keyp; 11529549Sbrian MD5_CTX MD5context; /* context for MD5 */ 1166059Samurai char answer[100]; 1176059Samurai char cdigest[16]; 11829840Sbrian#ifdef HAVE_DES 11929840Sbrian int ix; 12029840Sbrian MD4_CTX MD4context; /* context for MD4 */ 12129840Sbrian#endif 1226059Samurai 1236059Samurai len = ntohs(chp->length); 12436285Sbrian log_Printf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 1256059Samurai arglen = len - sizeof(struct fsmheader); 12628679Sbrian cp = (char *) MBUF_CTOP(bp); 1276059Samurai valsize = *cp++ & 255; 1286059Samurai name = cp + valsize; 1296059Samurai namelen = arglen - valsize - 1; 1306059Samurai name[namelen] = 0; 13136285Sbrian log_Printf(LogLCP, " Valsize = %d, Name = \"%s\"\n", valsize, name); 1326059Samurai 1336059Samurai switch (chp->code) { 1346059Samurai case CHAP_CHALLENGE: 13536285Sbrian keyp = bundle->cfg.auth.key; 13636285Sbrian keylen = strlen(bundle->cfg.auth.key); 13736285Sbrian name = bundle->cfg.auth.name; 13836285Sbrian namelen = strlen(bundle->cfg.auth.name); 13929840Sbrian 14029840Sbrian#ifdef HAVE_DES 14136285Sbrian if (physical->dl->chap.using_MSChap) 14229840Sbrian argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); 14329840Sbrian else 14429840Sbrian#endif 14529840Sbrian argp = malloc(1 + valsize + namelen + 16); 14629840Sbrian 14725630Sbrian if (argp == NULL) { 14836285Sbrian ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14); 14925630Sbrian return; 15025630Sbrian } 15129840Sbrian#ifdef HAVE_DES 15236285Sbrian if (physical->dl->chap.using_MSChap) { 15329840Sbrian digest = argp; /* this is the response */ 15429840Sbrian *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 15530715Sbrian memset(digest, '\0', 24); 15630715Sbrian digest += 24; 15729840Sbrian 15829840Sbrian ap = answer; /* this is the challenge */ 15930715Sbrian memcpy(ap, keyp, keylen); 16029840Sbrian ap += 2 * keylen; 16130715Sbrian memcpy(ap, cp, valsize); 16236285Sbrian log_DumpBuff(LogDEBUG, "recv", ap, valsize); 16329840Sbrian ap += valsize; 16429840Sbrian for (ix = keylen; ix > 0 ; ix--) { 16529840Sbrian answer[2*ix-2] = answer[ix-1]; 16629840Sbrian answer[2*ix-1] = 0; 16729840Sbrian } 16829549Sbrian MD4Init(&MD4context); 16929840Sbrian MD4Update(&MD4context, answer, 2 * keylen); 17029549Sbrian MD4Final(digest, &MD4context); 17130715Sbrian memcpy(digest + 25, name, namelen); 17229840Sbrian ap += 2 * keylen; 17336285Sbrian chap_MS(digest, answer + 2 * keylen, valsize); 17436285Sbrian log_DumpBuff(LogDEBUG, "answer", digest, 24); 17536285Sbrian ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, 17636285Sbrian namelen + MS_CHAP_RESPONSE_LEN + 1); 17729549Sbrian } else { 17829840Sbrian#endif 17929840Sbrian digest = argp; 18029840Sbrian *digest++ = 16; /* value size */ 18129840Sbrian ap = answer; 18229840Sbrian *ap++ = chp->id; 18330715Sbrian memcpy(ap, keyp, keylen); 18429840Sbrian ap += keylen; 18530715Sbrian memcpy(ap, cp, valsize); 18636285Sbrian log_DumpBuff(LogDEBUG, "recv", ap, valsize); 18729840Sbrian ap += valsize; 18829549Sbrian MD5Init(&MD5context); 18929549Sbrian MD5Update(&MD5context, answer, ap - answer); 19029549Sbrian MD5Final(digest, &MD5context); 19136285Sbrian log_DumpBuff(LogDEBUG, "answer", digest, 16); 19230715Sbrian memcpy(digest + 16, name, namelen); 19329840Sbrian ap += namelen; 19429840Sbrian /* Send answer to the peer */ 19536285Sbrian ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17); 19629840Sbrian#ifdef HAVE_DES 19729549Sbrian } 19829840Sbrian#endif 19918885Sjkh free(argp); 2006059Samurai break; 2016059Samurai case CHAP_RESPONSE: 20231051Sbrian /* 20331051Sbrian * Get a secret key corresponds to the peer 20431051Sbrian */ 20536285Sbrian keyp = auth_GetSecret(bundle, name, namelen, physical); 2066059Samurai if (keyp) { 2076059Samurai /* 2086059Samurai * Compute correct digest value 2096059Samurai */ 2106059Samurai keylen = strlen(keyp); 2116059Samurai ap = answer; 2126059Samurai *ap++ = chp->id; 21330715Sbrian memcpy(ap, keyp, keylen); 2146059Samurai ap += keylen; 21529840Sbrian MD5Init(&MD5context); 21629840Sbrian MD5Update(&MD5context, answer, ap - answer); 21736285Sbrian MD5Update(&MD5context, physical->dl->chap.challenge_data + 1, 21836285Sbrian physical->dl->chap.challenge_len); 21929840Sbrian MD5Final(cdigest, &MD5context); 22036285Sbrian log_DumpBuff(LogDEBUG, "got", cp, 16); 22136285Sbrian log_DumpBuff(LogDEBUG, "expect", cdigest, 16); 22228679Sbrian 2236059Samurai /* 2246059Samurai * Compare with the response 2256059Samurai */ 22630715Sbrian if (memcmp(cp, cdigest, 16) == 0) { 22736285Sbrian datalink_GotAuthname(physical->dl, name, namelen); 22836285Sbrian ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10); 22936285Sbrian if (Enabled(bundle, OPT_UTMP)) 23036285Sbrian physical_Login(physical, name); 23136285Sbrian 23236285Sbrian if (physical->link.lcp.auth_iwait == 0) 23336285Sbrian /* 23436285Sbrian * Either I didn't need to authenticate, or I've already been 23536285Sbrian * told that I got the answer right. 23636285Sbrian */ 23736285Sbrian datalink_AuthOk(physical->dl); 23836285Sbrian 2396059Samurai break; 2406059Samurai } 2416059Samurai } 24228679Sbrian 2436059Samurai /* 2446059Samurai * Peer is not registerd, or response digest is wrong. 2456059Samurai */ 24636285Sbrian ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9); 24736285Sbrian datalink_AuthNotOk(physical->dl); 2486059Samurai break; 2496059Samurai } 2506059Samurai} 2516059Samurai 25230715Sbrianstatic void 25336285SbrianRecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 25436285Sbrian struct physical *physical) 2556059Samurai{ 2566059Samurai int len; 2576059Samurai 2586059Samurai len = ntohs(chp->length); 25936285Sbrian log_Printf(LogDEBUG, "RecvChapResult: length: %d\n", len); 2606059Samurai if (chp->code == CHAP_SUCCESS) { 26136285Sbrian if (physical->link.lcp.auth_iwait == PROTO_CHAP) { 26236285Sbrian physical->link.lcp.auth_iwait = 0; 26336285Sbrian if (physical->link.lcp.auth_ineed == 0) 26436285Sbrian /* 26536285Sbrian * We've succeeded in our ``login'' 26636285Sbrian * If we're not expecting the peer to authenticate (or he already 26736285Sbrian * has), proceed to network phase. 26836285Sbrian */ 26936285Sbrian datalink_AuthOk(physical->dl); 2706059Samurai } 2716059Samurai } else { 27236285Sbrian /* CHAP failed - it's not going to get any better */ 27336285Sbrian log_Printf(LogPHASE, "Received CHAP_FAILURE\n"); 27436285Sbrian datalink_AuthNotOk(physical->dl); 2756059Samurai } 2766059Samurai} 2776059Samurai 2786059Samuraivoid 27936285Sbrianchap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) 2806059Samurai{ 28136285Sbrian int len = mbuf_Length(bp); 2826059Samurai struct fsmheader *chp; 2836059Samurai 2846059Samurai if (len >= sizeof(struct fsmheader)) { 28528679Sbrian chp = (struct fsmheader *) MBUF_CTOP(bp); 2866059Samurai if (len >= ntohs(chp->length)) { 2876059Samurai if (chp->code < 1 || chp->code > 4) 2886059Samurai chp->code = 0; 28936285Sbrian log_Printf(LogLCP, "chap_Input: %s\n", chapcodes[chp->code]); 2906059Samurai 2916059Samurai bp->offset += sizeof(struct fsmheader); 2926059Samurai bp->cnt -= sizeof(struct fsmheader); 2936059Samurai 2946059Samurai switch (chp->code) { 2956735Samurai case CHAP_RESPONSE: 29636285Sbrian auth_StopTimer(&physical->dl->chap.auth); 2976735Samurai /* Fall into.. */ 2986059Samurai case CHAP_CHALLENGE: 29936285Sbrian RecvChapTalk(bundle, chp, bp, physical); 3006059Samurai break; 3016059Samurai case CHAP_SUCCESS: 3026059Samurai case CHAP_FAILURE: 30336285Sbrian RecvChapResult(bundle, chp, bp, physical); 3046059Samurai break; 3056059Samurai } 3066059Samurai } 3076059Samurai } 30836285Sbrian mbuf_Free(bp); 3096059Samurai} 310