chap.c revision 26142
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.16 1997/05/24 17:32:32 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(code, id, ptr, count) 49u_int code, id; 50u_char *ptr; 51int count; 52{ 53 int plen; 54 struct fsmheader lh; 55 struct mbuf *bp; 56 57 plen = sizeof(struct fsmheader) + count; 58 lh.code = code; 59 lh.id = id; 60 lh.length = htons(plen); 61 bp = mballoc(plen, MB_FSM); 62 bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 63 if (count) 64 bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 65#ifdef DEBUG 66 DumpBp(bp); 67#endif 68 LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]); 69 HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 70} 71 72 73static char challenge_data[80]; 74static int challenge_len; 75 76void 77SendChapChallenge(chapid) 78int chapid; 79{ 80 int len, i; 81 char *cp; 82 83 if (!randinit) { 84 randinit = 1; 85 if (srandomdev() < 0) 86 srandom((unsigned long)(time(NULL) ^ getpid())); 87 } 88 89 cp = challenge_data; 90 *cp++ = challenge_len = random() % 32 + 16; 91 for (i = 0; i < challenge_len; i++) 92 *cp++ = random() & 0xff; 93 len = strlen(VarAuthName); 94 bcopy(VarAuthName, cp, len); 95 cp += len; 96 ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 97} 98 99#ifdef DEBUG 100void 101DumpDigest(mes, cp, len) 102char *mes; 103char *cp; 104int len; 105{ 106 int i; 107 108 logprintf("%s: ", mes); 109 for (i = 0; i < len; i++) { 110 logprintf(" %02x", *cp++ & 0xff); 111 } 112 logprintf("\n"); 113} 114#endif 115 116void 117RecvChapTalk(chp, bp) 118struct fsmheader *chp; 119struct mbuf *bp; 120{ 121 int valsize, len; 122 int arglen, keylen, namelen; 123 char *cp, *argp, *ap, *name, *digest; 124 char *keyp; 125 MD5_CTX context; /* context */ 126 char answer[100]; 127 char cdigest[16]; 128 129 len = ntohs(chp->length); 130#ifdef DEBUG 131 logprintf("length: %d\n", len); 132#endif 133 arglen = len - sizeof(struct fsmheader); 134 cp = (char *)MBUF_CTOP(bp); 135 valsize = *cp++ & 255; 136 name = cp + valsize; 137 namelen = arglen - valsize - 1; 138 name[namelen] = 0; 139 LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name); 140 141 /* 142 * Get a secret key corresponds to the peer 143 */ 144 keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 145 146 switch (chp->code) { 147 case CHAP_CHALLENGE: 148 if (keyp) { 149 keylen = strlen(keyp); 150 } else { 151 keylen = strlen(VarAuthKey); 152 keyp = VarAuthKey; 153 } 154 name = VarAuthName; 155 namelen = strlen(VarAuthName); 156 argp = malloc(1 + valsize + namelen + 16); 157 if (argp == NULL) { 158 ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); 159 return; 160 } 161 digest = argp; 162 *digest++ = 16; /* value size */ 163 ap = answer; 164 *ap++ = chp->id; 165 bcopy(keyp, ap, keylen); 166 ap += keylen; 167 bcopy(cp, ap, valsize); 168#ifdef DEBUG 169 DumpDigest("recv", ap, valsize); 170#endif 171 ap += valsize; 172 MD5Init(&context); 173 MD5Update(&context, answer, ap - answer); 174 MD5Final(digest, &context); 175#ifdef DEBUG 176 DumpDigest("answer", digest, 16); 177#endif 178 bcopy(name, digest + 16, namelen); 179 ap += namelen; 180 /* Send answer to the peer */ 181 ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 182 free(argp); 183 break; 184 case CHAP_RESPONSE: 185 if (keyp) { 186 /* 187 * Compute correct digest value 188 */ 189 keylen = strlen(keyp); 190 ap = answer; 191 *ap++ = chp->id; 192 bcopy(keyp, ap, keylen); 193 ap += keylen; 194 MD5Init(&context); 195 MD5Update(&context, answer, ap - answer); 196 MD5Update(&context, challenge_data+1, challenge_len); 197 MD5Final(cdigest, &context); 198#ifdef DEBUG 199 DumpDigest("got", cp, 16); 200 DumpDigest("expect", cdigest, 16); 201#endif 202 /* 203 * Compare with the response 204 */ 205 if (bcmp(cp, cdigest, 16) == 0) { 206 ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 207 NewPhase(PHASE_NETWORK); 208 break; 209 } 210 } 211 /* 212 * Peer is not registerd, or response digest is wrong. 213 */ 214 ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 215 reconnect(RECON_FALSE); 216 LcpClose(); 217 break; 218 } 219} 220 221void 222RecvChapResult(chp, bp) 223struct fsmheader *chp; 224struct mbuf *bp; 225{ 226 int len; 227 struct lcpstate *lcp = &LcpInfo; 228 229 len = ntohs(chp->length); 230#ifdef DEBUG 231 logprintf("length: %d\n", len); 232#endif 233 if (chp->code == CHAP_SUCCESS) { 234 if (lcp->auth_iwait == PROTO_CHAP) { 235 lcp->auth_iwait = 0; 236 if (lcp->auth_ineed == 0) 237 NewPhase(PHASE_NETWORK); 238 } 239 } else { 240 /* 241 * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 242 */ 243 ; 244 } 245} 246 247void 248ChapInput(struct mbuf *bp) 249{ 250 int len = plength(bp); 251 struct fsmheader *chp; 252 253 if (len >= sizeof(struct fsmheader)) { 254 chp = (struct fsmheader *)MBUF_CTOP(bp); 255 if (len >= ntohs(chp->length)) { 256 if (chp->code < 1 || chp->code > 4) 257 chp->code = 0; 258 LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]); 259 260 bp->offset += sizeof(struct fsmheader); 261 bp->cnt -= sizeof(struct fsmheader); 262 263 switch (chp->code) { 264 case CHAP_RESPONSE: 265 StopAuthTimer(&AuthChapInfo); 266 /* Fall into.. */ 267 case CHAP_CHALLENGE: 268 RecvChapTalk(chp, bp); 269 break; 270 case CHAP_SUCCESS: 271 case CHAP_FAILURE: 272 RecvChapResult(chp, bp); 273 break; 274 } 275 } 276 } 277 pfree(bp); 278} 279