chap.c revision 6735
1229198Sed/* 2229198Sed * PPP CHAP Module 3229198Sed * 4229198Sed * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5229198Sed * 6229198Sed * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7229198Sed * 8229198Sed * Redistribution and use in source and binary forms are permitted 9229198Sed * provided that the above copyright notice and this paragraph are 10229198Sed * duplicated in all such forms and that any documentation, 11229198Sed * advertising materials, and other materials related to such 12229198Sed * distribution and use acknowledge that the software was developed 13229198Sed * by the Internet Initiative Japan, Inc. The name of the 14229198Sed * IIJ may not be used to endorse or promote products derived 15229198Sed * from this software without specific prior written permission. 16229198Sed * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17229198Sed * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18229198Sed * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19229198Sed * 20229198Sed * $Id:$ 21229198Sed * 22229198Sed * TODO: 23229198Sed */ 24229198Sed#include "fsm.h" 25229198Sed#include "chap.h" 26229198Sed#include "lcpproto.h" 27229198Sed#include "lcp.h" 28229198Sed#include "hdlc.h" 29229198Sed#include "phase.h" 30229198Sed#include "vars.h" 31229198Sed#include "auth.h" 32229198Sed 33229198Sedstatic char *chapcodes[] = { 34229198Sed "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE" 35229198Sed}; 36229198Sed 37229198Sedstruct authinfo AuthChapInfo = { 38229198Sed SendChapChallenge, 39229198Sed}; 40229198Sed 41229198Sedextern char *AuthGetSecret(); 42229198Sed 43229198Sedvoid 44229198SedChapOutput(code, id, ptr, count) 45229198Sedu_int code, id; 46229198Sedu_char *ptr; 47229198Sedint count; 48229198Sed{ 49229198Sed int plen; 50229198Sed struct fsmheader lh; 51229198Sed struct mbuf *bp; 52229198Sed 53229198Sed plen = sizeof(struct fsmheader) + count; 54229198Sed lh.code = code; 55229198Sed lh.id = id; 56229198Sed lh.length = htons(plen); 57229198Sed bp = mballoc(plen, MB_FSM); 58229198Sed bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 59229198Sed if (count) 60229198Sed bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 61229198Sed#ifdef DEBUG 62229198Sed DumpBp(bp); 63229198Sed#endif 64229198Sed LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]); 65229198Sed HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp); 66229198Sed} 67229198Sed 68229198Sed 69229198Sedstatic char challenge_data[80]; 70229198Sedstatic int challenge_len; 71229198Sed 72229198Sedvoid 73229198SedSendChapChallenge(chapid) 74229198Sedint chapid; 75229198Sed{ 76229198Sed int keylen, len, i; 77229198Sed char *cp; 78229198Sed 79229198Sed srandom(time(NULL)); 80229198Sed 81229198Sed cp = challenge_data; 82229198Sed *cp++ = challenge_len = random() % 32 + 16; 83229198Sed for (i = 0; i < challenge_len; i++) 84229198Sed *cp++ = random() & 0xff; 85229198Sed len = strlen(VarAuthName); 86229198Sed bcopy(VarAuthName, cp, len); 87229198Sed cp += len; 88229198Sed ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 89229198Sed} 90229198Sed 91229198Sed#ifdef DEBUG 92229198Sedvoid 93229198SedDumpDigest(mes, cp, len) 94229198Sedchar *mes; 95229198Sedchar *cp; 96229198Sedint len; 97229198Sed{ 98229198Sed int i; 99229198Sed 100229198Sed logprintf("%s: ", mes); 101229198Sed for (i = 0; i < len; i++) { 102229198Sed logprintf(" %02x", *cp++ & 0xff); 103229198Sed } 104229198Sed logprintf("\n"); 105229198Sed} 106229198Sed#endif 107229198Sed 108229198Sedvoid 109229198SedRecvChapTalk(chp, bp) 110229198Sedstruct fsmheader *chp; 111229198Sedstruct mbuf *bp; 112229198Sed{ 113229198Sed int valsize, len; 114229198Sed int arglen, keylen, namelen; 115229198Sed char *cp, *argp, *ap, *name, *digest; 116 char *keyp; 117 MD5_CTX context; /* context */ 118 char answer[100]; 119 char cdigest[16]; 120 121 len = ntohs(chp->length); 122#ifdef DEBUG 123 logprintf("length: %d\n", len); 124#endif 125 arglen = len - sizeof(struct fsmheader); 126 cp = (char *)MBUF_CTOP(bp); 127 valsize = *cp++ & 255; 128 name = cp + valsize; 129 namelen = arglen - valsize - 1; 130 name[namelen] = 0; 131 LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name); 132 133 /* 134 * Get a secret key corresponds to the peer 135 */ 136 keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 137 138 switch (chp->code) { 139 case CHAP_CHALLENGE: 140 if (keyp) { 141 keylen = strlen(keyp); 142 } else { 143 keylen = strlen(VarAuthKey); 144 keyp = VarAuthKey; 145 } 146 name = VarAuthName; 147 namelen = strlen(VarAuthName); 148 argp = malloc(1 + valsize + namelen); 149 digest = argp; 150 *digest++ = 16; /* value size */ 151 ap = answer; 152 *ap++ = chp->id; 153 bcopy(keyp, ap, keylen); 154 ap += keylen; 155 bcopy(cp, ap, valsize); 156#ifdef DEBUG 157 DumpDigest("recv", ap, valsize); 158#endif 159 ap += valsize; 160 MD5Init(&context); 161 MD5Update(&context, answer, ap - answer); 162 MD5Final(digest, &context); 163#ifdef DEBUG 164 DumpDigest("answer", digest, 16); 165#endif 166 bcopy(name, digest + 16, namelen); 167 ap += namelen; 168 /* Send answer to the peer */ 169 ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 170 break; 171 case CHAP_RESPONSE: 172 if (keyp) { 173 /* 174 * Compute correct digest value 175 */ 176 keylen = strlen(keyp); 177 ap = answer; 178 *ap++ = chp->id; 179 bcopy(keyp, ap, keylen); 180 ap += keylen; 181 MD5Init(&context); 182 MD5Update(&context, answer, ap - answer); 183 MD5Update(&context, challenge_data+1, challenge_len); 184 MD5Final(cdigest, &context); 185#ifdef DEBUG 186 DumpDigest("got", cp, 16); 187 DumpDigest("expect", cdigest, 16); 188#endif 189 /* 190 * Compare with the response 191 */ 192 if (bcmp(cp, cdigest, 16) == 0) { 193 ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 194 NewPhase(PHASE_NETWORK); 195 break; 196 } 197 } 198 /* 199 * Peer is not registerd, or response digest is wrong. 200 */ 201 ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 202 LcpClose(); 203 break; 204 } 205} 206 207void 208RecvChapResult(chp, bp) 209struct fsmheader *chp; 210struct mbuf *bp; 211{ 212 int len; 213 struct lcpstate *lcp = &LcpInfo; 214 215 len = ntohs(chp->length); 216#ifdef DEBUG 217 logprintf("length: %d\n", len); 218#endif 219 if (chp->code == CHAP_SUCCESS) { 220 if (lcp->auth_iwait == PROTO_CHAP) { 221 lcp->auth_iwait = 0; 222 if (lcp->auth_ineed == 0) 223 NewPhase(PHASE_NETWORK); 224 } 225 } else { 226 /* 227 * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 228 */ 229 ; 230 } 231} 232 233void 234ChapInput(struct mbuf *bp) 235{ 236 int len = plength(bp); 237 struct fsmheader *chp; 238 239 if (len >= sizeof(struct fsmheader)) { 240 chp = (struct fsmheader *)MBUF_CTOP(bp); 241 if (len >= ntohs(chp->length)) { 242 if (chp->code < 1 || chp->code > 4) 243 chp->code = 0; 244 LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]); 245 246 bp->offset += sizeof(struct fsmheader); 247 bp->cnt -= sizeof(struct fsmheader); 248 249 switch (chp->code) { 250 case CHAP_RESPONSE: 251 StopAuthTimer(&AuthChapInfo); 252 /* Fall into.. */ 253 case CHAP_CHALLENGE: 254 RecvChapTalk(chp, bp); 255 break; 256 case CHAP_SUCCESS: 257 case CHAP_FAILURE: 258 RecvChapResult(chp, bp); 259 break; 260 } 261 } 262 } 263 pfree(bp); 264} 265