chap.c revision 29840
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 * 2029840Sbrian * $Id: chap.c,v 1.22 1997/09/22 23:59:13 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2413379Sphk#include <sys/types.h> 2513379Sphk#include <time.h> 2629729Sbrian#include <utmp.h> 2729840Sbrian#include <ctype.h> 2829840Sbrian 296059Samurai#include "fsm.h" 306059Samurai#include "chap.h" 3129840Sbrian#include "chap_ms.h" 326059Samurai#include "lcpproto.h" 336059Samurai#include "lcp.h" 346059Samurai#include "hdlc.h" 356059Samurai#include "phase.h" 3626142Sbrian#include "loadalias.h" 376059Samurai#include "vars.h" 386735Samurai#include "auth.h" 3929729Sbrian#ifdef __OpenBSD__ 4029729Sbrian#include "util.h" 4129729Sbrian#else 4229729Sbrian#include "libutil.h" 4329729Sbrian#endif 446059Samurai 456059Samuraistatic char *chapcodes[] = { 4619866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 476059Samurai}; 486059Samurai 4928679Sbrianstruct authinfo AuthChapInfo = { 506735Samurai SendChapChallenge, 516735Samurai}; 526735Samurai 536059Samuraiextern char *AuthGetSecret(); 5423603Sacheextern int randinit; 556059Samurai 566059Samuraivoid 5728679SbrianChapOutput(u_int code, u_int id, u_char * ptr, int count) 586059Samurai{ 596059Samurai int plen; 606059Samurai struct fsmheader lh; 616059Samurai struct mbuf *bp; 626059Samurai 6328679Sbrian plen = sizeof(struct fsmheader) + count; 646059Samurai lh.code = code; 656059Samurai lh.id = id; 666059Samurai lh.length = htons(plen); 676059Samurai bp = mballoc(plen, MB_FSM); 686059Samurai bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 696059Samurai if (count) 706059Samurai bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 7126516Sbrian LogDumpBp(LogDEBUG, "ChapOutput", bp); 7226516Sbrian LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 7313733Sdfr HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 746059Samurai} 756059Samurai 766059Samurai 776059Samuraistatic char challenge_data[80]; 7828679Sbrianstatic int challenge_len; 796059Samurai 806059Samuraivoid 8128679SbrianSendChapChallenge(int chapid) 826059Samurai{ 8313379Sphk int len, i; 846059Samurai char *cp; 856059Samurai 8623603Sache if (!randinit) { 8723603Sache randinit = 1; 8826626Sache srandomdev(); 8923603Sache } 906059Samurai cp = challenge_data; 916059Samurai *cp++ = challenge_len = random() % 32 + 16; 926059Samurai for (i = 0; i < challenge_len; i++) 936059Samurai *cp++ = random() & 0xff; 946059Samurai len = strlen(VarAuthName); 956059Samurai bcopy(VarAuthName, cp, len); 966059Samurai cp += len; 976059Samurai ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 986059Samurai} 996059Samurai 1006059Samuraivoid 10128679SbrianRecvChapTalk(struct fsmheader * chp, struct mbuf * bp) 1026059Samurai{ 1036059Samurai int valsize, len; 1046059Samurai int arglen, keylen, namelen; 1056059Samurai char *cp, *argp, *ap, *name, *digest; 1066059Samurai char *keyp; 10729549Sbrian MD5_CTX MD5context; /* context for MD5 */ 1086059Samurai char answer[100]; 1096059Samurai char cdigest[16]; 11029840Sbrian#ifdef HAVE_DES 11129840Sbrian int ix; 11229840Sbrian MD4_CTX MD4context; /* context for MD4 */ 11329840Sbrian#endif 1146059Samurai 1156059Samurai len = ntohs(chp->length); 11626516Sbrian LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 1176059Samurai arglen = len - sizeof(struct fsmheader); 11828679Sbrian cp = (char *) MBUF_CTOP(bp); 1196059Samurai valsize = *cp++ & 255; 1206059Samurai name = cp + valsize; 1216059Samurai namelen = arglen - valsize - 1; 1226059Samurai name[namelen] = 0; 12326516Sbrian LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name); 1246059Samurai 1256059Samurai /* 1266059Samurai * Get a secret key corresponds to the peer 1276059Samurai */ 1286059Samurai keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 1296059Samurai 1306059Samurai switch (chp->code) { 1316059Samurai case CHAP_CHALLENGE: 1326059Samurai if (keyp) { 1336059Samurai keylen = strlen(keyp); 1346059Samurai } else { 1356059Samurai keylen = strlen(VarAuthKey); 1366059Samurai keyp = VarAuthKey; 1376059Samurai } 1386059Samurai name = VarAuthName; 1396059Samurai namelen = strlen(VarAuthName); 14029840Sbrian 14129840Sbrian#ifdef HAVE_DES 14229840Sbrian if (VarMSChap) 14329840Sbrian argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); 14429840Sbrian else 14529840Sbrian#endif 14629840Sbrian argp = malloc(1 + valsize + namelen + 16); 14729840Sbrian 14825630Sbrian if (argp == NULL) { 14925630Sbrian ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); 15025630Sbrian return; 15125630Sbrian } 15229840Sbrian#ifdef HAVE_DES 15329840Sbrian if (VarMSChap) { 15429840Sbrian digest = argp; /* this is the response */ 15529840Sbrian *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 15629840Sbrian bzero(digest, 24); digest += 24; 15729840Sbrian 15829840Sbrian ap = answer; /* this is the challenge */ 15929840Sbrian bcopy(keyp, ap, keylen); 16029840Sbrian ap += 2 * keylen; 16129840Sbrian bcopy(cp, ap, valsize); 16229840Sbrian LogDumpBuff(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); 17129840Sbrian bcopy(name, digest + 25, namelen); 17229840Sbrian ap += 2 * keylen; 17329840Sbrian ChapMS(digest, answer + 2 * keylen, valsize); 17429840Sbrian LogDumpBuff(LogDEBUG, "answer", digest, 24); 17529840Sbrian ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + MS_CHAP_RESPONSE_LEN + 1); 17629549Sbrian } else { 17729840Sbrian#endif 17829840Sbrian digest = argp; 17929840Sbrian *digest++ = 16; /* value size */ 18029840Sbrian ap = answer; 18129840Sbrian *ap++ = chp->id; 18229840Sbrian bcopy(keyp, ap, keylen); 18329840Sbrian ap += keylen; 18429840Sbrian bcopy(cp, ap, valsize); 18529840Sbrian LogDumpBuff(LogDEBUG, "recv", ap, valsize); 18629840Sbrian ap += valsize; 18729549Sbrian MD5Init(&MD5context); 18829549Sbrian MD5Update(&MD5context, answer, ap - answer); 18929549Sbrian MD5Final(digest, &MD5context); 19029840Sbrian LogDumpBuff(LogDEBUG, "answer", digest, 16); 19129840Sbrian bcopy(name, digest + 16, namelen); 19229840Sbrian ap += namelen; 19329840Sbrian /* Send answer to the peer */ 19429840Sbrian ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 19529840Sbrian#ifdef HAVE_DES 19629549Sbrian } 19729840Sbrian#endif 19818885Sjkh free(argp); 1996059Samurai break; 2006059Samurai case CHAP_RESPONSE: 2016059Samurai if (keyp) { 20228679Sbrian 2036059Samurai /* 2046059Samurai * Compute correct digest value 2056059Samurai */ 2066059Samurai keylen = strlen(keyp); 2076059Samurai ap = answer; 2086059Samurai *ap++ = chp->id; 2096059Samurai bcopy(keyp, ap, keylen); 2106059Samurai ap += keylen; 21129840Sbrian MD5Init(&MD5context); 21229840Sbrian MD5Update(&MD5context, answer, ap - answer); 21329840Sbrian MD5Update(&MD5context, challenge_data + 1, challenge_len); 21429840Sbrian MD5Final(cdigest, &MD5context); 21526516Sbrian LogDumpBuff(LogDEBUG, "got", cp, 16); 21626516Sbrian LogDumpBuff(LogDEBUG, "expect", cdigest, 16); 21728679Sbrian 2186059Samurai /* 2196059Samurai * Compare with the response 2206059Samurai */ 2216059Samurai if (bcmp(cp, cdigest, 16) == 0) { 22229729Sbrian ChapOutput(CHAP_SUCCESS, chp->id, "Welcome!!", 10); 22329729Sbrian if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp)) 22429729Sbrian if (Utmp) 22529729Sbrian LogPrintf(LogERROR, "Oops, already logged in on %s\n", 22629729Sbrian VarBaseDevice); 22729729Sbrian else { 22829729Sbrian struct utmp ut; 22929729Sbrian memset(&ut, 0, sizeof(ut)); 23029729Sbrian time(&ut.ut_time); 23129729Sbrian strncpy(ut.ut_name, name, sizeof(ut.ut_name)-1); 23229729Sbrian strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); 23329729Sbrian if (logout(ut.ut_line)) 23429729Sbrian logwtmp(ut.ut_line, "", ""); 23529729Sbrian login(&ut); 23629729Sbrian Utmp = 1; 23729729Sbrian } 2386059Samurai NewPhase(PHASE_NETWORK); 2396059Samurai break; 2406059Samurai } 2416059Samurai } 24228679Sbrian 2436059Samurai /* 2446059Samurai * Peer is not registerd, or response digest is wrong. 2456059Samurai */ 2466059Samurai ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 24726098Sbrian reconnect(RECON_FALSE); 2486059Samurai LcpClose(); 2496059Samurai break; 2506059Samurai } 2516059Samurai} 2526059Samurai 2536059Samuraivoid 25428679SbrianRecvChapResult(struct fsmheader * chp, struct mbuf * bp) 2556059Samurai{ 2566059Samurai int len; 2576059Samurai struct lcpstate *lcp = &LcpInfo; 2586059Samurai 2596059Samurai len = ntohs(chp->length); 26026516Sbrian LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); 2616059Samurai if (chp->code == CHAP_SUCCESS) { 2626059Samurai if (lcp->auth_iwait == PROTO_CHAP) { 2636059Samurai lcp->auth_iwait = 0; 2646059Samurai if (lcp->auth_ineed == 0) 2656059Samurai NewPhase(PHASE_NETWORK); 2666059Samurai } 2676059Samurai } else { 26828679Sbrian 2696059Samurai /* 2706059Samurai * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 2716059Samurai */ 2726059Samurai ; 2736059Samurai } 2746059Samurai} 2756059Samurai 2766059Samuraivoid 27728679SbrianChapInput(struct mbuf * bp) 2786059Samurai{ 2796059Samurai int len = plength(bp); 2806059Samurai struct fsmheader *chp; 2816059Samurai 2826059Samurai if (len >= sizeof(struct fsmheader)) { 28328679Sbrian chp = (struct fsmheader *) MBUF_CTOP(bp); 2846059Samurai if (len >= ntohs(chp->length)) { 2856059Samurai if (chp->code < 1 || chp->code > 4) 2866059Samurai chp->code = 0; 28726516Sbrian LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); 2886059Samurai 2896059Samurai bp->offset += sizeof(struct fsmheader); 2906059Samurai bp->cnt -= sizeof(struct fsmheader); 2916059Samurai 2926059Samurai switch (chp->code) { 2936735Samurai case CHAP_RESPONSE: 2946735Samurai StopAuthTimer(&AuthChapInfo); 2956735Samurai /* Fall into.. */ 2966059Samurai case CHAP_CHALLENGE: 2976059Samurai RecvChapTalk(chp, bp); 2986059Samurai break; 2996059Samurai case CHAP_SUCCESS: 3006059Samurai case CHAP_FAILURE: 3016059Samurai RecvChapResult(chp, bp); 3026059Samurai break; 3036059Samurai } 3046059Samurai } 3056059Samurai } 3066059Samurai pfree(bp); 3076059Samurai} 308