chap.c revision 31051
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 * 2031051Sbrian * $Id: chap.c,v 1.24 1997/10/26 01:02:16 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2430715Sbrian#include <sys/param.h> 2530715Sbrian#include <netinet/in.h> 2630715Sbrian 2730715Sbrian#include <ctype.h> 2830715Sbrian#ifdef HAVE_DES 2930715Sbrian#include <md4.h> 3030715Sbrian#endif 3130715Sbrian#include <md5.h> 3230715Sbrian#include <stdio.h> 3330715Sbrian#include <stdlib.h> 3430715Sbrian#include <string.h> 3513379Sphk#include <time.h> 3630715Sbrian#include <unistd.h> 3730715Sbrian#ifdef __OpenBSD__ 3830715Sbrian#include <util.h> 3930715Sbrian#else 4030715Sbrian#include <libutil.h> 4130715Sbrian#endif 4229729Sbrian#include <utmp.h> 4329840Sbrian 4430715Sbrian#include "mbuf.h" 4530715Sbrian#include "log.h" 4630715Sbrian#include "defs.h" 4730715Sbrian#include "timer.h" 486059Samurai#include "fsm.h" 496059Samurai#include "chap.h" 5029840Sbrian#include "chap_ms.h" 516059Samurai#include "lcpproto.h" 526059Samurai#include "lcp.h" 536059Samurai#include "hdlc.h" 546059Samurai#include "phase.h" 5526142Sbrian#include "loadalias.h" 5630715Sbrian#include "command.h" 576059Samurai#include "vars.h" 586735Samurai#include "auth.h" 596059Samurai 606059Samuraistatic char *chapcodes[] = { 6119866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 626059Samurai}; 636059Samurai 6430715Sbrianstatic void 6528679SbrianChapOutput(u_int code, u_int id, u_char * ptr, int count) 666059Samurai{ 676059Samurai int plen; 686059Samurai struct fsmheader lh; 696059Samurai struct mbuf *bp; 706059Samurai 7128679Sbrian plen = sizeof(struct fsmheader) + count; 726059Samurai lh.code = code; 736059Samurai lh.id = id; 746059Samurai lh.length = htons(plen); 756059Samurai bp = mballoc(plen, MB_FSM); 7630715Sbrian memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 776059Samurai if (count) 7830715Sbrian memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 7926516Sbrian LogDumpBp(LogDEBUG, "ChapOutput", bp); 8026516Sbrian LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 8113733Sdfr HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 826059Samurai} 836059Samurai 846059Samurai 856059Samuraistatic char challenge_data[80]; 8628679Sbrianstatic int challenge_len; 876059Samurai 8830715Sbrianstatic void 8928679SbrianSendChapChallenge(int chapid) 906059Samurai{ 9113379Sphk int len, i; 926059Samurai char *cp; 936059Samurai 9430715Sbrian randinit(); 956059Samurai cp = challenge_data; 966059Samurai *cp++ = challenge_len = random() % 32 + 16; 976059Samurai for (i = 0; i < challenge_len; i++) 986059Samurai *cp++ = random() & 0xff; 996059Samurai len = strlen(VarAuthName); 10030715Sbrian memcpy(cp, VarAuthName, len); 1016059Samurai cp += len; 1026059Samurai ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 1036059Samurai} 1046059Samurai 10530715Sbrianstruct authinfo AuthChapInfo = { 10630715Sbrian SendChapChallenge, 10730715Sbrian}; 10830715Sbrian 10930715Sbrianstatic void 11030715SbrianRecvChapTalk(struct fsmheader *chp, struct mbuf *bp) 1116059Samurai{ 1126059Samurai int valsize, len; 1136059Samurai int arglen, keylen, namelen; 1146059Samurai char *cp, *argp, *ap, *name, *digest; 1156059Samurai char *keyp; 11629549Sbrian MD5_CTX MD5context; /* context for MD5 */ 1176059Samurai char answer[100]; 1186059Samurai char cdigest[16]; 11929840Sbrian#ifdef HAVE_DES 12029840Sbrian int ix; 12129840Sbrian MD4_CTX MD4context; /* context for MD4 */ 12229840Sbrian#endif 1236059Samurai 1246059Samurai len = ntohs(chp->length); 12526516Sbrian LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 1266059Samurai arglen = len - sizeof(struct fsmheader); 12728679Sbrian cp = (char *) MBUF_CTOP(bp); 1286059Samurai valsize = *cp++ & 255; 1296059Samurai name = cp + valsize; 1306059Samurai namelen = arglen - valsize - 1; 1316059Samurai name[namelen] = 0; 13226516Sbrian LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name); 1336059Samurai 1346059Samurai switch (chp->code) { 1356059Samurai case CHAP_CHALLENGE: 13631051Sbrian keyp = VarAuthKey; 13731051Sbrian keylen = strlen(VarAuthKey); 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 */ 15630715Sbrian memset(digest, '\0', 24); 15730715Sbrian digest += 24; 15829840Sbrian 15929840Sbrian ap = answer; /* this is the challenge */ 16030715Sbrian memcpy(ap, keyp, keylen); 16129840Sbrian ap += 2 * keylen; 16230715Sbrian memcpy(ap, cp, valsize); 16329840Sbrian LogDumpBuff(LogDEBUG, "recv", ap, valsize); 16429840Sbrian ap += valsize; 16529840Sbrian for (ix = keylen; ix > 0 ; ix--) { 16629840Sbrian answer[2*ix-2] = answer[ix-1]; 16729840Sbrian answer[2*ix-1] = 0; 16829840Sbrian } 16929549Sbrian MD4Init(&MD4context); 17029840Sbrian MD4Update(&MD4context, answer, 2 * keylen); 17129549Sbrian MD4Final(digest, &MD4context); 17230715Sbrian memcpy(digest + 25, name, namelen); 17329840Sbrian ap += 2 * keylen; 17429840Sbrian ChapMS(digest, answer + 2 * keylen, valsize); 17529840Sbrian LogDumpBuff(LogDEBUG, "answer", digest, 24); 17629840Sbrian ChapOutput(CHAP_RESPONSE, chp->id, argp, 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); 18629840Sbrian LogDumpBuff(LogDEBUG, "recv", ap, valsize); 18729840Sbrian ap += valsize; 18829549Sbrian MD5Init(&MD5context); 18929549Sbrian MD5Update(&MD5context, answer, ap - answer); 19029549Sbrian MD5Final(digest, &MD5context); 19129840Sbrian LogDumpBuff(LogDEBUG, "answer", digest, 16); 19230715Sbrian memcpy(digest + 16, name, namelen); 19329840Sbrian ap += namelen; 19429840Sbrian /* Send answer to the peer */ 19529840Sbrian ChapOutput(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 */ 20531051Sbrian keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 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); 21729840Sbrian MD5Update(&MD5context, challenge_data + 1, challenge_len); 21829840Sbrian MD5Final(cdigest, &MD5context); 21926516Sbrian LogDumpBuff(LogDEBUG, "got", cp, 16); 22026516Sbrian LogDumpBuff(LogDEBUG, "expect", cdigest, 16); 22128679Sbrian 2226059Samurai /* 2236059Samurai * Compare with the response 2246059Samurai */ 22530715Sbrian if (memcmp(cp, cdigest, 16) == 0) { 22629729Sbrian ChapOutput(CHAP_SUCCESS, chp->id, "Welcome!!", 10); 22729729Sbrian if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp)) 22829729Sbrian if (Utmp) 22929729Sbrian LogPrintf(LogERROR, "Oops, already logged in on %s\n", 23029729Sbrian VarBaseDevice); 23129729Sbrian else { 23229729Sbrian struct utmp ut; 23329729Sbrian memset(&ut, 0, sizeof(ut)); 23429729Sbrian time(&ut.ut_time); 23529729Sbrian strncpy(ut.ut_name, name, sizeof(ut.ut_name)-1); 23629729Sbrian strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); 23729729Sbrian if (logout(ut.ut_line)) 23829729Sbrian logwtmp(ut.ut_line, "", ""); 23929729Sbrian login(&ut); 24029729Sbrian Utmp = 1; 24129729Sbrian } 2426059Samurai NewPhase(PHASE_NETWORK); 2436059Samurai break; 2446059Samurai } 2456059Samurai } 24628679Sbrian 2476059Samurai /* 2486059Samurai * Peer is not registerd, or response digest is wrong. 2496059Samurai */ 2506059Samurai ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 25126098Sbrian reconnect(RECON_FALSE); 2526059Samurai LcpClose(); 2536059Samurai break; 2546059Samurai } 2556059Samurai} 2566059Samurai 25730715Sbrianstatic void 25830715SbrianRecvChapResult(struct fsmheader *chp, struct mbuf *bp) 2596059Samurai{ 2606059Samurai int len; 2616059Samurai struct lcpstate *lcp = &LcpInfo; 2626059Samurai 2636059Samurai len = ntohs(chp->length); 26426516Sbrian LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); 2656059Samurai if (chp->code == CHAP_SUCCESS) { 2666059Samurai if (lcp->auth_iwait == PROTO_CHAP) { 2676059Samurai lcp->auth_iwait = 0; 2686059Samurai if (lcp->auth_ineed == 0) 2696059Samurai NewPhase(PHASE_NETWORK); 2706059Samurai } 2716059Samurai } else { 27228679Sbrian 2736059Samurai /* 2746059Samurai * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 2756059Samurai */ 2766059Samurai ; 2776059Samurai } 2786059Samurai} 2796059Samurai 2806059Samuraivoid 28130715SbrianChapInput(struct mbuf *bp) 2826059Samurai{ 2836059Samurai int len = plength(bp); 2846059Samurai struct fsmheader *chp; 2856059Samurai 2866059Samurai if (len >= sizeof(struct fsmheader)) { 28728679Sbrian chp = (struct fsmheader *) MBUF_CTOP(bp); 2886059Samurai if (len >= ntohs(chp->length)) { 2896059Samurai if (chp->code < 1 || chp->code > 4) 2906059Samurai chp->code = 0; 29126516Sbrian LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); 2926059Samurai 2936059Samurai bp->offset += sizeof(struct fsmheader); 2946059Samurai bp->cnt -= sizeof(struct fsmheader); 2956059Samurai 2966059Samurai switch (chp->code) { 2976735Samurai case CHAP_RESPONSE: 2986735Samurai StopAuthTimer(&AuthChapInfo); 2996735Samurai /* Fall into.. */ 3006059Samurai case CHAP_CHALLENGE: 3016059Samurai RecvChapTalk(chp, bp); 3026059Samurai break; 3036059Samurai case CHAP_SUCCESS: 3046059Samurai case CHAP_FAILURE: 3056059Samurai RecvChapResult(chp, bp); 3066059Samurai break; 3076059Samurai } 3086059Samurai } 3096059Samurai } 3106059Samurai pfree(bp); 3116059Samurai} 312