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