chap.c revision 28679
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.19 1997/06/14 00:21:23 ache 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 MD5_CTX context; /* context */ 99 char answer[100]; 100 char cdigest[16]; 101 102 len = ntohs(chp->length); 103 LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 104 arglen = len - sizeof(struct fsmheader); 105 cp = (char *) MBUF_CTOP(bp); 106 valsize = *cp++ & 255; 107 name = cp + valsize; 108 namelen = arglen - valsize - 1; 109 name[namelen] = 0; 110 LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name); 111 112 /* 113 * Get a secret key corresponds to the peer 114 */ 115 keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 116 117 switch (chp->code) { 118 case CHAP_CHALLENGE: 119 if (keyp) { 120 keylen = strlen(keyp); 121 } else { 122 keylen = strlen(VarAuthKey); 123 keyp = VarAuthKey; 124 } 125 name = VarAuthName; 126 namelen = strlen(VarAuthName); 127 argp = malloc(1 + valsize + namelen + 16); 128 if (argp == NULL) { 129 ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); 130 return; 131 } 132 digest = argp; 133 *digest++ = 16; /* value size */ 134 ap = answer; 135 *ap++ = chp->id; 136 bcopy(keyp, ap, keylen); 137 ap += keylen; 138 bcopy(cp, ap, valsize); 139 LogDumpBuff(LogDEBUG, "recv", ap, valsize); 140 ap += valsize; 141 MD5Init(&context); 142 MD5Update(&context, answer, ap - answer); 143 MD5Final(digest, &context); 144 LogDumpBuff(LogDEBUG, "answer", digest, 16); 145 bcopy(name, digest + 16, namelen); 146 ap += namelen; 147 /* Send answer to the peer */ 148 ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 149 free(argp); 150 break; 151 case CHAP_RESPONSE: 152 if (keyp) { 153 154 /* 155 * Compute correct digest value 156 */ 157 keylen = strlen(keyp); 158 ap = answer; 159 *ap++ = chp->id; 160 bcopy(keyp, ap, keylen); 161 ap += keylen; 162 MD5Init(&context); 163 MD5Update(&context, answer, ap - answer); 164 MD5Update(&context, challenge_data + 1, challenge_len); 165 MD5Final(cdigest, &context); 166 LogDumpBuff(LogDEBUG, "got", cp, 16); 167 LogDumpBuff(LogDEBUG, "expect", cdigest, 16); 168 169 /* 170 * Compare with the response 171 */ 172 if (bcmp(cp, cdigest, 16) == 0) { 173 ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 174 NewPhase(PHASE_NETWORK); 175 break; 176 } 177 } 178 179 /* 180 * Peer is not registerd, or response digest is wrong. 181 */ 182 ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 183 reconnect(RECON_FALSE); 184 LcpClose(); 185 break; 186 } 187} 188 189void 190RecvChapResult(struct fsmheader * chp, struct mbuf * bp) 191{ 192 int len; 193 struct lcpstate *lcp = &LcpInfo; 194 195 len = ntohs(chp->length); 196 LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); 197 if (chp->code == CHAP_SUCCESS) { 198 if (lcp->auth_iwait == PROTO_CHAP) { 199 lcp->auth_iwait = 0; 200 if (lcp->auth_ineed == 0) 201 NewPhase(PHASE_NETWORK); 202 } 203 } else { 204 205 /* 206 * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 207 */ 208 ; 209 } 210} 211 212void 213ChapInput(struct mbuf * bp) 214{ 215 int len = plength(bp); 216 struct fsmheader *chp; 217 218 if (len >= sizeof(struct fsmheader)) { 219 chp = (struct fsmheader *) MBUF_CTOP(bp); 220 if (len >= ntohs(chp->length)) { 221 if (chp->code < 1 || chp->code > 4) 222 chp->code = 0; 223 LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); 224 225 bp->offset += sizeof(struct fsmheader); 226 bp->cnt -= sizeof(struct fsmheader); 227 228 switch (chp->code) { 229 case CHAP_RESPONSE: 230 StopAuthTimer(&AuthChapInfo); 231 /* Fall into.. */ 232 case CHAP_CHALLENGE: 233 RecvChapTalk(chp, bp); 234 break; 235 case CHAP_SUCCESS: 236 case CHAP_FAILURE: 237 RecvChapResult(chp, bp); 238 break; 239 } 240 } 241 } 242 pfree(bp); 243} 244