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