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