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