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