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