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