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