chap.c revision 36285
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.28.2.27 1998/05/01 19:24:03 brian Exp $ 21 * 22 * TODO: 23 */ 24#include <sys/types.h> 25#include <netinet/in.h> 26#include <netinet/in_systm.h> 27#include <netinet/ip.h> 28#include <sys/un.h> 29 30#include <md5.h> 31#include <stdlib.h> 32#include <termios.h> 33 34#include "mbuf.h" 35#include "log.h" 36#include "defs.h" 37#include "timer.h" 38#include "fsm.h" 39#include "lcpproto.h" 40#include "lcp.h" 41#include "lqr.h" 42#include "hdlc.h" 43#include "auth.h" 44#include "chap.h" 45#include "async.h" 46#include "throughput.h" 47#include "descriptor.h" 48#include "iplist.h" 49#include "slcompress.h" 50#include "ipcp.h" 51#include "filter.h" 52#include "ccp.h" 53#include "link.h" 54#include "physical.h" 55#include "mp.h" 56#include "bundle.h" 57#include "chat.h" 58#include "datalink.h" 59 60static const char *chapcodes[] = { 61 "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 62}; 63 64static void 65ChapOutput(struct physical *physical, u_int code, u_int id, 66 const u_char * ptr, int count) 67{ 68 int plen; 69 struct fsmheader lh; 70 struct mbuf *bp; 71 72 plen = sizeof(struct fsmheader) + count; 73 lh.code = code; 74 lh.id = id; 75 lh.length = htons(plen); 76 bp = mbuf_Alloc(plen, MB_FSM); 77 memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 78 if (count) 79 memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 80 log_DumpBp(LogDEBUG, "ChapOutput", bp); 81 log_Printf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 82 hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); 83} 84 85void 86chap_SendChallenge(struct authinfo *auth, int chapid, struct physical *physical) 87{ 88 struct chap *chap = auth2chap(auth); 89 int len, i; 90 char *cp; 91 92 randinit(); 93 cp = chap->challenge_data; 94 *cp++ = chap->challenge_len = random() % 32 + 16; 95 for (i = 0; i < chap->challenge_len; i++) 96 *cp++ = random() & 0xff; 97 len = strlen(physical->dl->bundle->cfg.auth.name); 98 memcpy(cp, physical->dl->bundle->cfg.auth.name, len); 99 cp += len; 100 ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, 101 cp - chap->challenge_data); 102} 103 104static void 105RecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 106 struct physical *physical) 107{ 108 int valsize, len; 109 int arglen, keylen, namelen; 110 char *cp, *argp, *ap, *name, *digest; 111 char *keyp; 112 MD5_CTX MD5context; /* context for MD5 */ 113 char answer[100]; 114 char cdigest[16]; 115#ifdef HAVE_DES 116 int ix; 117 MD4_CTX MD4context; /* context for MD4 */ 118#endif 119 120 len = ntohs(chp->length); 121 log_Printf(LogDEBUG, "RecvChapTalk: length: %d\n", len); 122 arglen = len - sizeof(struct fsmheader); 123 cp = (char *) MBUF_CTOP(bp); 124 valsize = *cp++ & 255; 125 name = cp + valsize; 126 namelen = arglen - valsize - 1; 127 name[namelen] = 0; 128 log_Printf(LogLCP, " Valsize = %d, Name = \"%s\"\n", valsize, name); 129 130 switch (chp->code) { 131 case CHAP_CHALLENGE: 132 keyp = bundle->cfg.auth.key; 133 keylen = strlen(bundle->cfg.auth.key); 134 name = bundle->cfg.auth.name; 135 namelen = strlen(bundle->cfg.auth.name); 136 137#ifdef HAVE_DES 138 if (physical->dl->chap.using_MSChap) 139 argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); 140 else 141#endif 142 argp = malloc(1 + valsize + namelen + 16); 143 144 if (argp == NULL) { 145 ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14); 146 return; 147 } 148#ifdef HAVE_DES 149 if (physical->dl->chap.using_MSChap) { 150 digest = argp; /* this is the response */ 151 *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 152 memset(digest, '\0', 24); 153 digest += 24; 154 155 ap = answer; /* this is the challenge */ 156 memcpy(ap, keyp, keylen); 157 ap += 2 * keylen; 158 memcpy(ap, cp, valsize); 159 log_DumpBuff(LogDEBUG, "recv", ap, valsize); 160 ap += valsize; 161 for (ix = keylen; ix > 0 ; ix--) { 162 answer[2*ix-2] = answer[ix-1]; 163 answer[2*ix-1] = 0; 164 } 165 MD4Init(&MD4context); 166 MD4Update(&MD4context, answer, 2 * keylen); 167 MD4Final(digest, &MD4context); 168 memcpy(digest + 25, name, namelen); 169 ap += 2 * keylen; 170 chap_MS(digest, answer + 2 * keylen, valsize); 171 log_DumpBuff(LogDEBUG, "answer", digest, 24); 172 ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, 173 namelen + MS_CHAP_RESPONSE_LEN + 1); 174 } else { 175#endif 176 digest = argp; 177 *digest++ = 16; /* value size */ 178 ap = answer; 179 *ap++ = chp->id; 180 memcpy(ap, keyp, keylen); 181 ap += keylen; 182 memcpy(ap, cp, valsize); 183 log_DumpBuff(LogDEBUG, "recv", ap, valsize); 184 ap += valsize; 185 MD5Init(&MD5context); 186 MD5Update(&MD5context, answer, ap - answer); 187 MD5Final(digest, &MD5context); 188 log_DumpBuff(LogDEBUG, "answer", digest, 16); 189 memcpy(digest + 16, name, namelen); 190 ap += namelen; 191 /* Send answer to the peer */ 192 ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17); 193#ifdef HAVE_DES 194 } 195#endif 196 free(argp); 197 break; 198 case CHAP_RESPONSE: 199 /* 200 * Get a secret key corresponds to the peer 201 */ 202 keyp = auth_GetSecret(bundle, name, namelen, physical); 203 if (keyp) { 204 /* 205 * Compute correct digest value 206 */ 207 keylen = strlen(keyp); 208 ap = answer; 209 *ap++ = chp->id; 210 memcpy(ap, keyp, keylen); 211 ap += keylen; 212 MD5Init(&MD5context); 213 MD5Update(&MD5context, answer, ap - answer); 214 MD5Update(&MD5context, physical->dl->chap.challenge_data + 1, 215 physical->dl->chap.challenge_len); 216 MD5Final(cdigest, &MD5context); 217 log_DumpBuff(LogDEBUG, "got", cp, 16); 218 log_DumpBuff(LogDEBUG, "expect", cdigest, 16); 219 220 /* 221 * Compare with the response 222 */ 223 if (memcmp(cp, cdigest, 16) == 0) { 224 datalink_GotAuthname(physical->dl, name, namelen); 225 ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10); 226 if (Enabled(bundle, OPT_UTMP)) 227 physical_Login(physical, name); 228 229 if (physical->link.lcp.auth_iwait == 0) 230 /* 231 * Either I didn't need to authenticate, or I've already been 232 * told that I got the answer right. 233 */ 234 datalink_AuthOk(physical->dl); 235 236 break; 237 } 238 } 239 240 /* 241 * Peer is not registerd, or response digest is wrong. 242 */ 243 ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9); 244 datalink_AuthNotOk(physical->dl); 245 break; 246 } 247} 248 249static void 250RecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, 251 struct physical *physical) 252{ 253 int len; 254 255 len = ntohs(chp->length); 256 log_Printf(LogDEBUG, "RecvChapResult: length: %d\n", len); 257 if (chp->code == CHAP_SUCCESS) { 258 if (physical->link.lcp.auth_iwait == PROTO_CHAP) { 259 physical->link.lcp.auth_iwait = 0; 260 if (physical->link.lcp.auth_ineed == 0) 261 /* 262 * We've succeeded in our ``login'' 263 * If we're not expecting the peer to authenticate (or he already 264 * has), proceed to network phase. 265 */ 266 datalink_AuthOk(physical->dl); 267 } 268 } else { 269 /* CHAP failed - it's not going to get any better */ 270 log_Printf(LogPHASE, "Received CHAP_FAILURE\n"); 271 datalink_AuthNotOk(physical->dl); 272 } 273} 274 275void 276chap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) 277{ 278 int len = mbuf_Length(bp); 279 struct fsmheader *chp; 280 281 if (len >= sizeof(struct fsmheader)) { 282 chp = (struct fsmheader *) MBUF_CTOP(bp); 283 if (len >= ntohs(chp->length)) { 284 if (chp->code < 1 || chp->code > 4) 285 chp->code = 0; 286 log_Printf(LogLCP, "chap_Input: %s\n", chapcodes[chp->code]); 287 288 bp->offset += sizeof(struct fsmheader); 289 bp->cnt -= sizeof(struct fsmheader); 290 291 switch (chp->code) { 292 case CHAP_RESPONSE: 293 auth_StopTimer(&physical->dl->chap.auth); 294 /* Fall into.. */ 295 case CHAP_CHALLENGE: 296 RecvChapTalk(bundle, chp, bp, physical); 297 break; 298 case CHAP_SUCCESS: 299 case CHAP_FAILURE: 300 RecvChapResult(bundle, chp, bp, physical); 301 break; 302 } 303 } 304 } 305 mbuf_Free(bp); 306} 307