chap.c revision 38174
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 * 2038174Sbrian * $Id: chap.c,v 1.35 1998/07/28 21:54:29 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> 3238174Sbrian#include <string.h> 3337192Sbrian#endif 3430715Sbrian#include <md5.h> 3530715Sbrian#include <stdlib.h> 3636285Sbrian#include <termios.h> 3729840Sbrian 3830715Sbrian#include "mbuf.h" 3930715Sbrian#include "log.h" 4030715Sbrian#include "defs.h" 4130715Sbrian#include "timer.h" 426059Samurai#include "fsm.h" 436059Samurai#include "lcpproto.h" 446059Samurai#include "lcp.h" 4536285Sbrian#include "lqr.h" 466059Samurai#include "hdlc.h" 476735Samurai#include "auth.h" 4836285Sbrian#include "chap.h" 4936285Sbrian#include "async.h" 5036285Sbrian#include "throughput.h" 5136285Sbrian#include "descriptor.h" 5236285Sbrian#include "iplist.h" 5336285Sbrian#include "slcompress.h" 5436285Sbrian#include "ipcp.h" 5536285Sbrian#include "filter.h" 5636285Sbrian#include "ccp.h" 5736285Sbrian#include "link.h" 5836285Sbrian#include "physical.h" 5936285Sbrian#include "mp.h" 6036285Sbrian#include "bundle.h" 6136285Sbrian#include "chat.h" 6238174Sbrian#include "cbcp.h" 6336285Sbrian#include "datalink.h" 6437192Sbrian#ifdef HAVE_DES 6536287Sbrian#include "chap_ms.h" 6637192Sbrian#endif 676059Samurai 6831343Sbrianstatic const char *chapcodes[] = { 6919866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 706059Samurai}; 716059Samurai 7230715Sbrianstatic void 7336285SbrianChapOutput(struct physical *physical, u_int code, u_int id, 7437926Sbrian const u_char * ptr, int count, const char *text) 756059Samurai{ 766059Samurai int plen; 776059Samurai struct fsmheader lh; 786059Samurai struct mbuf *bp; 796059Samurai 8028679Sbrian plen = sizeof(struct fsmheader) + count; 816059Samurai lh.code = code; 826059Samurai lh.id = id; 836059Samurai lh.length = htons(plen); 8436285Sbrian bp = mbuf_Alloc(plen, MB_FSM); 8530715Sbrian memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 866059Samurai if (count) 8730715Sbrian memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 8836285Sbrian log_DumpBp(LogDEBUG, "ChapOutput", bp); 8937926Sbrian if (text == NULL) 9037926Sbrian log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); 9137926Sbrian else 9237926Sbrian log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); 9336285Sbrian hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); 946059Samurai} 956059Samurai 9636285Sbrianvoid 9736285Sbrianchap_SendChallenge(struct authinfo *auth, int chapid, struct physical *physical) 986059Samurai{ 9936285Sbrian struct chap *chap = auth2chap(auth); 10013379Sphk int len, i; 1016059Samurai char *cp; 1026059Samurai 10330715Sbrian randinit(); 10436285Sbrian cp = chap->challenge_data; 10536285Sbrian *cp++ = chap->challenge_len = random() % 32 + 16; 10636285Sbrian for (i = 0; i < chap->challenge_len; i++) 1076059Samurai *cp++ = random() & 0xff; 10836285Sbrian len = strlen(physical->dl->bundle->cfg.auth.name); 10936285Sbrian memcpy(cp, physical->dl->bundle->cfg.auth.name, len); 1106059Samurai cp += len; 11136285Sbrian ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, 11237926Sbrian cp - chap->challenge_data, NULL); 1136059Samurai} 1146059Samurai 11530715Sbrianstatic void 11636285SbrianRecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 11736285Sbrian struct physical *physical) 1186059Samurai{ 1196059Samurai int valsize, len; 1206059Samurai int arglen, keylen, namelen; 1216059Samurai char *cp, *argp, *ap, *name, *digest; 1226059Samurai char *keyp; 12329549Sbrian MD5_CTX MD5context; /* context for MD5 */ 1246059Samurai char answer[100]; 1256059Samurai char cdigest[16]; 12629840Sbrian#ifdef HAVE_DES 12729840Sbrian int ix; 12829840Sbrian MD4_CTX MD4context; /* context for MD4 */ 12929840Sbrian#endif 1306059Samurai 1316059Samurai len = ntohs(chp->length); 13236285Sbrian log_Printf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 1336059Samurai arglen = len - sizeof(struct fsmheader); 13428679Sbrian cp = (char *) MBUF_CTOP(bp); 1356059Samurai valsize = *cp++ & 255; 1366059Samurai name = cp + valsize; 1376059Samurai namelen = arglen - valsize - 1; 1386059Samurai name[namelen] = 0; 1396059Samurai 14037926Sbrian log_Printf(LogPHASE, "Chap Input: %s (from %s)\n", 14137926Sbrian chapcodes[chp->code], name); 14237926Sbrian 1436059Samurai switch (chp->code) { 1446059Samurai case CHAP_CHALLENGE: 14536285Sbrian keyp = bundle->cfg.auth.key; 14636285Sbrian keylen = strlen(bundle->cfg.auth.key); 14736285Sbrian name = bundle->cfg.auth.name; 14836285Sbrian namelen = strlen(bundle->cfg.auth.name); 14929840Sbrian 15029840Sbrian#ifdef HAVE_DES 15136285Sbrian if (physical->dl->chap.using_MSChap) 15229840Sbrian argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); 15329840Sbrian else 15429840Sbrian#endif 15529840Sbrian argp = malloc(1 + valsize + namelen + 16); 15629840Sbrian 15725630Sbrian if (argp == NULL) { 15837926Sbrian ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14, NULL); 15925630Sbrian return; 16025630Sbrian } 16129840Sbrian#ifdef HAVE_DES 16236285Sbrian if (physical->dl->chap.using_MSChap) { 16329840Sbrian digest = argp; /* this is the response */ 16429840Sbrian *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 16530715Sbrian memset(digest, '\0', 24); 16630715Sbrian digest += 24; 16729840Sbrian 16829840Sbrian ap = answer; /* this is the challenge */ 16930715Sbrian memcpy(ap, keyp, keylen); 17029840Sbrian ap += 2 * keylen; 17130715Sbrian memcpy(ap, cp, valsize); 17236285Sbrian log_DumpBuff(LogDEBUG, "recv", ap, valsize); 17329840Sbrian ap += valsize; 17429840Sbrian for (ix = keylen; ix > 0 ; ix--) { 17529840Sbrian answer[2*ix-2] = answer[ix-1]; 17629840Sbrian answer[2*ix-1] = 0; 17729840Sbrian } 17829549Sbrian MD4Init(&MD4context); 17929840Sbrian MD4Update(&MD4context, answer, 2 * keylen); 18029549Sbrian MD4Final(digest, &MD4context); 18130715Sbrian memcpy(digest + 25, name, namelen); 18229840Sbrian ap += 2 * keylen; 18336285Sbrian chap_MS(digest, answer + 2 * keylen, valsize); 18436285Sbrian log_DumpBuff(LogDEBUG, "answer", digest, 24); 18536285Sbrian ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, 18637926Sbrian namelen + MS_CHAP_RESPONSE_LEN + 1, name); 18729549Sbrian } else { 18829840Sbrian#endif 18929840Sbrian digest = argp; 19029840Sbrian *digest++ = 16; /* value size */ 19129840Sbrian ap = answer; 19229840Sbrian *ap++ = chp->id; 19330715Sbrian memcpy(ap, keyp, keylen); 19429840Sbrian ap += keylen; 19530715Sbrian memcpy(ap, cp, valsize); 19636285Sbrian log_DumpBuff(LogDEBUG, "recv", ap, valsize); 19729840Sbrian ap += valsize; 19829549Sbrian MD5Init(&MD5context); 19929549Sbrian MD5Update(&MD5context, answer, ap - answer); 20029549Sbrian MD5Final(digest, &MD5context); 20136285Sbrian log_DumpBuff(LogDEBUG, "answer", digest, 16); 20230715Sbrian memcpy(digest + 16, name, namelen); 20329840Sbrian ap += namelen; 20429840Sbrian /* Send answer to the peer */ 20537926Sbrian ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17, name); 20629840Sbrian#ifdef HAVE_DES 20729549Sbrian } 20829840Sbrian#endif 20918885Sjkh free(argp); 21037926Sbrian if (*name == '\0') 21137926Sbrian log_Printf(LogWARN, "Sending empty CHAP authname!\n"); 2126059Samurai break; 2136059Samurai case CHAP_RESPONSE: 21431051Sbrian /* 21531051Sbrian * Get a secret key corresponds to the peer 21631051Sbrian */ 21736285Sbrian keyp = auth_GetSecret(bundle, name, namelen, physical); 2186059Samurai if (keyp) { 2196059Samurai /* 2206059Samurai * Compute correct digest value 2216059Samurai */ 2226059Samurai keylen = strlen(keyp); 2236059Samurai ap = answer; 2246059Samurai *ap++ = chp->id; 22530715Sbrian memcpy(ap, keyp, keylen); 2266059Samurai ap += keylen; 22729840Sbrian MD5Init(&MD5context); 22829840Sbrian MD5Update(&MD5context, answer, ap - answer); 22936285Sbrian MD5Update(&MD5context, physical->dl->chap.challenge_data + 1, 23036285Sbrian physical->dl->chap.challenge_len); 23129840Sbrian MD5Final(cdigest, &MD5context); 23236285Sbrian log_DumpBuff(LogDEBUG, "got", cp, 16); 23336285Sbrian log_DumpBuff(LogDEBUG, "expect", cdigest, 16); 23428679Sbrian 2356059Samurai /* 2366059Samurai * Compare with the response 2376059Samurai */ 23830715Sbrian if (memcmp(cp, cdigest, 16) == 0) { 23936285Sbrian datalink_GotAuthname(physical->dl, name, namelen); 24037926Sbrian ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10, NULL); 24137926Sbrian physical->link.lcp.auth_ineed = 0; 24236285Sbrian if (Enabled(bundle, OPT_UTMP)) 24336285Sbrian physical_Login(physical, name); 24436285Sbrian 24536285Sbrian if (physical->link.lcp.auth_iwait == 0) 24636285Sbrian /* 24736285Sbrian * Either I didn't need to authenticate, or I've already been 24836285Sbrian * told that I got the answer right. 24936285Sbrian */ 25036285Sbrian datalink_AuthOk(physical->dl); 25136285Sbrian 2526059Samurai break; 2536059Samurai } 2546059Samurai } 25528679Sbrian 2566059Samurai /* 2576059Samurai * Peer is not registerd, or response digest is wrong. 2586059Samurai */ 25937926Sbrian ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9, NULL); 26036285Sbrian datalink_AuthNotOk(physical->dl); 2616059Samurai break; 2626059Samurai } 2636059Samurai} 2646059Samurai 26530715Sbrianstatic void 26636285SbrianRecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 26736285Sbrian struct physical *physical) 2686059Samurai{ 2696059Samurai int len; 2706059Samurai 2716059Samurai len = ntohs(chp->length); 27236285Sbrian log_Printf(LogDEBUG, "RecvChapResult: length: %d\n", len); 2736059Samurai if (chp->code == CHAP_SUCCESS) { 27436285Sbrian if (physical->link.lcp.auth_iwait == PROTO_CHAP) { 27536285Sbrian physical->link.lcp.auth_iwait = 0; 27636285Sbrian if (physical->link.lcp.auth_ineed == 0) 27736285Sbrian /* 27836285Sbrian * We've succeeded in our ``login'' 27936285Sbrian * If we're not expecting the peer to authenticate (or he already 28036285Sbrian * has), proceed to network phase. 28136285Sbrian */ 28236285Sbrian datalink_AuthOk(physical->dl); 2836059Samurai } 2846059Samurai } else { 28536285Sbrian /* CHAP failed - it's not going to get any better */ 28637926Sbrian log_Printf(LogPHASE, "Chap Input: Giving up after name/key FAILURE\n"); 28736285Sbrian datalink_AuthNotOk(physical->dl); 2886059Samurai } 2896059Samurai} 2906059Samurai 2916059Samuraivoid 29236285Sbrianchap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) 2936059Samurai{ 29436285Sbrian int len = mbuf_Length(bp); 2956059Samurai struct fsmheader *chp; 2966059Samurai 2976059Samurai if (len >= sizeof(struct fsmheader)) { 29828679Sbrian chp = (struct fsmheader *) MBUF_CTOP(bp); 2996059Samurai if (len >= ntohs(chp->length)) { 3006059Samurai if (chp->code < 1 || chp->code > 4) 3016059Samurai chp->code = 0; 3026059Samurai bp->offset += sizeof(struct fsmheader); 3036059Samurai bp->cnt -= sizeof(struct fsmheader); 3046059Samurai 3056059Samurai switch (chp->code) { 3066735Samurai case CHAP_RESPONSE: 30736285Sbrian auth_StopTimer(&physical->dl->chap.auth); 3086735Samurai /* Fall into.. */ 3096059Samurai case CHAP_CHALLENGE: 31036285Sbrian RecvChapTalk(bundle, chp, bp, physical); 3116059Samurai break; 3126059Samurai case CHAP_SUCCESS: 3136059Samurai case CHAP_FAILURE: 31437926Sbrian log_Printf(LogPHASE, "Chap Input: %s\n", chapcodes[chp->code]); 31536285Sbrian RecvChapResult(bundle, chp, bp, physical); 3166059Samurai break; 3176059Samurai } 3186059Samurai } 3196059Samurai } 32036285Sbrian mbuf_Free(bp); 3216059Samurai} 322