chap.c revision 29549
1/* 2 * PPP CHAP Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: chap.c,v 1.20 1997/08/25 00:29:06 brian Exp $ 21 * 22 * TODO: 23 */ 24#include <sys/types.h> 25#include <time.h> 26#include "fsm.h" 27#include "chap.h" 28#include "lcpproto.h" 29#include "lcp.h" 30#include "hdlc.h" 31#include "phase.h" 32#include "loadalias.h" 33#include "vars.h" 34#include "auth.h" 35 36static char *chapcodes[] = { 37 "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 38}; 39 40struct authinfo AuthChapInfo = { 41 SendChapChallenge, 42}; 43 44extern char *AuthGetSecret(); 45extern int randinit; 46 47void 48ChapOutput(u_int code, u_int id, u_char * ptr, int count) 49{ 50 int plen; 51 struct fsmheader lh; 52 struct mbuf *bp; 53 54 plen = sizeof(struct fsmheader) + count; 55 lh.code = code; 56 lh.id = id; 57 lh.length = htons(plen); 58 bp = mballoc(plen, MB_FSM); 59 bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 60 if (count) 61 bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 62 LogDumpBp(LogDEBUG, "ChapOutput", bp); 63 LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 64 HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 65} 66 67 68static char challenge_data[80]; 69static int challenge_len; 70 71void 72SendChapChallenge(int chapid) 73{ 74 int len, i; 75 char *cp; 76 77 if (!randinit) { 78 randinit = 1; 79 srandomdev(); 80 } 81 cp = challenge_data; 82 *cp++ = challenge_len = random() % 32 + 16; 83 for (i = 0; i < challenge_len; i++) 84 *cp++ = random() & 0xff; 85 len = strlen(VarAuthName); 86 bcopy(VarAuthName, cp, len); 87 cp += len; 88 ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 89} 90 91void 92RecvChapTalk(struct fsmheader * chp, struct mbuf * bp) 93{ 94 int valsize, len; 95 int arglen, keylen, namelen; 96 char *cp, *argp, *ap, *name, *digest; 97 char *keyp; 98 MD4_CTX MD4context; /* context for MD4 */ 99 MD5_CTX MD5context; /* context for MD5 */ 100 char answer[100]; 101 char cdigest[16]; 102 103 len = ntohs(chp->length); 104 LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 105 arglen = len - sizeof(struct fsmheader); 106 cp = (char *) MBUF_CTOP(bp); 107 valsize = *cp++ & 255; 108 name = cp + valsize; 109 namelen = arglen - valsize - 1; 110 name[namelen] = 0; 111 LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name); 112 113 /* 114 * Get a secret key corresponds to the peer 115 */ 116 keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 117 118 switch (chp->code) { 119 case CHAP_CHALLENGE: 120 if (keyp) { 121 keylen = strlen(keyp); 122 } else { 123 keylen = strlen(VarAuthKey); 124 keyp = VarAuthKey; 125 } 126 name = VarAuthName; 127 namelen = strlen(VarAuthName); 128 argp = malloc(1 + valsize + namelen + 16); 129 if (argp == NULL) { 130 ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); 131 return; 132 } 133 digest = argp; 134 *digest++ = 16; /* value size */ 135 ap = answer; 136 *ap++ = chp->id; 137 bcopy(keyp, ap, keylen); 138 ap += keylen; 139 bcopy(cp, ap, valsize); 140 LogDumpBuff(LogDEBUG, "recv", ap, valsize); 141 ap += valsize; 142 if (VarEncMD4) { 143 MD4Init(&MD4context); 144 MD4Update(&MD4context, answer, ap - answer); 145 MD4Final(digest, &MD4context); 146 } else { 147 MD5Init(&MD5context); 148 MD5Update(&MD5context, answer, ap - answer); 149 MD5Final(digest, &MD5context); 150 } 151 LogDumpBuff(LogDEBUG, "answer", digest, 16); 152 bcopy(name, digest + 16, namelen); 153 ap += namelen; 154 /* Send answer to the peer */ 155 ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 156 free(argp); 157 break; 158 case CHAP_RESPONSE: 159 if (keyp) { 160 161 /* 162 * Compute correct digest value 163 */ 164 keylen = strlen(keyp); 165 ap = answer; 166 *ap++ = chp->id; 167 bcopy(keyp, ap, keylen); 168 ap += keylen; 169 if (VarEncMD4) { 170 MD4Init(&MD4context); 171 MD4Update(&MD4context, answer, ap - answer); 172 MD4Update(&MD4context, challenge_data + 1, challenge_len); 173 MD4Final(cdigest, &MD4context); 174 } else { 175 MD5Init(&MD5context); 176 MD5Update(&MD5context, answer, ap - answer); 177 MD5Update(&MD5context, challenge_data + 1, challenge_len); 178 MD5Final(cdigest, &MD5context); 179 } 180 LogDumpBuff(LogDEBUG, "got", cp, 16); 181 LogDumpBuff(LogDEBUG, "expect", cdigest, 16); 182 183 /* 184 * Compare with the response 185 */ 186 if (bcmp(cp, cdigest, 16) == 0) { 187 ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 188 NewPhase(PHASE_NETWORK); 189 break; 190 } 191 } 192 193 /* 194 * Peer is not registerd, or response digest is wrong. 195 */ 196 ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 197 reconnect(RECON_FALSE); 198 LcpClose(); 199 break; 200 } 201} 202 203void 204RecvChapResult(struct fsmheader * chp, struct mbuf * bp) 205{ 206 int len; 207 struct lcpstate *lcp = &LcpInfo; 208 209 len = ntohs(chp->length); 210 LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); 211 if (chp->code == CHAP_SUCCESS) { 212 if (lcp->auth_iwait == PROTO_CHAP) { 213 lcp->auth_iwait = 0; 214 if (lcp->auth_ineed == 0) 215 NewPhase(PHASE_NETWORK); 216 } 217 } else { 218 219 /* 220 * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 221 */ 222 ; 223 } 224} 225 226void 227ChapInput(struct mbuf * bp) 228{ 229 int len = plength(bp); 230 struct fsmheader *chp; 231 232 if (len >= sizeof(struct fsmheader)) { 233 chp = (struct fsmheader *) MBUF_CTOP(bp); 234 if (len >= ntohs(chp->length)) { 235 if (chp->code < 1 || chp->code > 4) 236 chp->code = 0; 237 LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); 238 239 bp->offset += sizeof(struct fsmheader); 240 bp->cnt -= sizeof(struct fsmheader); 241 242 switch (chp->code) { 243 case CHAP_RESPONSE: 244 StopAuthTimer(&AuthChapInfo); 245 /* Fall into.. */ 246 case CHAP_CHALLENGE: 247 RecvChapTalk(chp, bp); 248 break; 249 case CHAP_SUCCESS: 250 case CHAP_FAILURE: 251 RecvChapResult(chp, bp); 252 break; 253 } 254 } 255 } 256 pfree(bp); 257} 258