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