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.11 1997/03/10 08:04:13 ache Exp $ 21 * 22 * TODO: 23 */ 24 #include <sys/types.h> 25 #include <time.h> 26 #include "fsm.h" 27 #include "chap.h" 28 #include "lcpproto.h" 29 #include "lcp.h" 30 #include "hdlc.h" 31 #include "phase.h" 32 #include "vars.h" 33 #include "auth.h" 34 35 static char *chapcodes[] = { 36 "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 37 }; 38 39 struct authinfo AuthChapInfo = { 40 SendChapChallenge, 41 }; 42 43 extern char *AuthGetSecret(); 44 extern int randinit; 45 46 void 47 ChapOutput(code, id, ptr, count) 48 u_int code, id; 49 u_char *ptr; 50 int count; 51 { 52 int plen; 53 struct fsmheader lh; 54 struct mbuf *bp; 55 56 plen = sizeof(struct fsmheader) + count; 57 lh.code = code; 58 lh.id = id; 59 lh.length = htons(plen); 60 bp = mballoc(plen, MB_FSM); 61 bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 62 if (count) 63 bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 64 #ifdef DEBUG 65 DumpBp(bp); 66 #endif 67 LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]); 68 HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 69 } 70 71 72 static char challenge_data[80]; 73 static int challenge_len; 74 75 void 76 SendChapChallenge(chapid) 77 int chapid; 78 { 79 int len, i; 80 char *cp; 81 82 if (!randinit) { 83 srandom((unsigned long)(time(NULL) ^ getpid())); 84 randinit = 1; 85 } 86 87 cp = challenge_data; 88 *cp++ = challenge_len = random() % 32 + 16; 89 for (i = 0; i < challenge_len; i++) 90 *cp++ = random() & 0xff; 91 len = strlen(VarAuthName); 92 bcopy(VarAuthName, cp, len); 93 cp += len; 94 ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); 95 } 96 97 #ifdef DEBUG 98 void 99 DumpDigest(mes, cp, len) 100 char *mes; 101 char *cp; 102 int len; 103 { 104 int i; 105 106 logprintf("%s: ", mes); 107 for (i = 0; i < len; i++) { 108 logprintf(" %02x", *cp++ & 0xff); 109 } 110 logprintf("\n"); 111 } 112 #endif 113 114 void 115 RecvChapTalk(chp, bp) 116 struct fsmheader *chp; 117 struct mbuf *bp; 118 { 119 int valsize, len; 120 int arglen, keylen, namelen; 121 char *cp, *argp, *ap, *name, *digest; 122 char *keyp; 123 MD5_CTX context; /* context */ 124 char answer[100]; 125 char cdigest[16]; 126 127 len = ntohs(chp->length); 128 #ifdef DEBUG 129 logprintf("length: %d\n", len); 130 #endif 131 arglen = len - sizeof(struct fsmheader); 132 cp = (char *)MBUF_CTOP(bp); 133 valsize = *cp++ & 255; 134 name = cp + valsize; 135 namelen = arglen - valsize - 1; 136 name[namelen] = 0; 137 LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name); 138 139 /* 140 * Get a secret key corresponds to the peer 141 */ 142 keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); 143 144 switch (chp->code) { 145 case CHAP_CHALLENGE: 146 if (keyp) { 147 keylen = strlen(keyp); 148 } else { 149 keylen = strlen(VarAuthKey); 150 keyp = VarAuthKey; 151 } 152 name = VarAuthName; 153 namelen = strlen(VarAuthName); 154 argp = malloc(1 + valsize + namelen + 16); 155 digest = argp; 156 *digest++ = 16; /* value size */ 157 ap = answer; 158 *ap++ = chp->id; 159 bcopy(keyp, ap, keylen); 160 ap += keylen; 161 bcopy(cp, ap, valsize); 162 #ifdef DEBUG 163 DumpDigest("recv", ap, valsize); 164 #endif 165 ap += valsize; 166 MD5Init(&context); 167 MD5Update(&context, answer, ap - answer); 168 MD5Final(digest, &context); 169 #ifdef DEBUG 170 DumpDigest("answer", digest, 16); 171 #endif 172 bcopy(name, digest + 16, namelen); 173 ap += namelen; 174 /* Send answer to the peer */ 175 ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 176 free(argp); 177 break; 178 case CHAP_RESPONSE: 179 if (keyp) { 180 /* 181 * Compute correct digest value 182 */ 183 keylen = strlen(keyp); 184 ap = answer; 185 *ap++ = chp->id; 186 bcopy(keyp, ap, keylen); 187 ap += keylen; 188 MD5Init(&context); 189 MD5Update(&context, answer, ap - answer); 190 MD5Update(&context, challenge_data+1, challenge_len); 191 MD5Final(cdigest, &context); 192 #ifdef DEBUG 193 DumpDigest("got", cp, 16); 194 DumpDigest("expect", cdigest, 16); 195 #endif 196 /* 197 * Compare with the response 198 */ 199 if (bcmp(cp, cdigest, 16) == 0) { 200 ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10); 201 NewPhase(PHASE_NETWORK); 202 break; 203 } 204 } 205 /* 206 * Peer is not registerd, or response digest is wrong. 207 */ 208 ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 209 LcpClose(); 210 break; 211 } 212 } 213 214 void 215 RecvChapResult(chp, bp) 216 struct fsmheader *chp; 217 struct mbuf *bp; 218 { 219 int len; 220 struct lcpstate *lcp = &LcpInfo; 221 222 len = ntohs(chp->length); 223 #ifdef DEBUG 224 logprintf("length: %d\n", len); 225 #endif 226 if (chp->code == CHAP_SUCCESS) { 227 if (lcp->auth_iwait == PROTO_CHAP) { 228 lcp->auth_iwait = 0; 229 if (lcp->auth_ineed == 0) 230 NewPhase(PHASE_NETWORK); 231 } 232 } else { 233 /* 234 * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 235 */ 236 ; 237 } 238 } 239 240 void 241 ChapInput(struct mbuf *bp) 242 { 243 int len = plength(bp); 244 struct fsmheader *chp; 245 246 if (len >= sizeof(struct fsmheader)) { 247 chp = (struct fsmheader *)MBUF_CTOP(bp); 248 if (len >= ntohs(chp->length)) { 249 if (chp->code < 1 || chp->code > 4) 250 chp->code = 0; 251 LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]); 252 253 bp->offset += sizeof(struct fsmheader); 254 bp->cnt -= sizeof(struct fsmheader); 255 256 switch (chp->code) { 257 case CHAP_RESPONSE: 258 StopAuthTimer(&AuthChapInfo); 259 /* Fall into.. */ 260 case CHAP_CHALLENGE: 261 RecvChapTalk(chp, bp); 262 break; 263 case CHAP_SUCCESS: 264 case CHAP_FAILURE: 265 RecvChapResult(chp, bp); 266 break; 267 } 268 } 269 } 270 pfree(bp); 271 } 272