chap.c revision 29729
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.21 1997/09/17 23:17:48 brian Exp $ 21 * 22 * TODO: 23 */ 24#include <sys/types.h> 25#include <time.h> 26#include <utmp.h> 27#include "fsm.h" 28#include "chap.h" 29#include "lcpproto.h" 30#include "lcp.h" 31#include "hdlc.h" 32#include "phase.h" 33#include "loadalias.h" 34#include "vars.h" 35#include "auth.h" 36#ifdef __OpenBSD__ 37#include "util.h" 38#else 39#include "libutil.h" 40#endif 41 42static char *chapcodes[] = { 43 "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 44}; 45 46struct authinfo AuthChapInfo = { 47 SendChapChallenge, 48}; 49 50extern char *AuthGetSecret(); 51extern int randinit; 52 53void 54ChapOutput(u_int code, u_int id, u_char * ptr, int count) 55{ 56 int plen; 57 struct fsmheader lh; 58 struct mbuf *bp; 59 60 plen = sizeof(struct fsmheader) + count; 61 lh.code = code; 62 lh.id = id; 63 lh.length = htons(plen); 64 bp = mballoc(plen, MB_FSM); 65 bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); 66 if (count) 67 bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); 68 LogDumpBp(LogDEBUG, "ChapOutput", bp); 69 LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); 70 HdlcOutput(PRI_LINK, PROTO_CHAP, bp); 71} 72 73 74static char challenge_data[80]; 75static int challenge_len; 76 77void 78SendChapChallenge(int chapid) 79{ 80 int len, i; 81 char *cp; 82 83 if (!randinit) { 84 randinit = 1; 85 srandomdev(); 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 97void 98RecvChapTalk(struct fsmheader * chp, struct mbuf * bp) 99{ 100 int valsize, len; 101 int arglen, keylen, namelen; 102 char *cp, *argp, *ap, *name, *digest; 103 char *keyp; 104 MD4_CTX MD4context; /* context for MD4 */ 105 MD5_CTX MD5context; /* context for MD5 */ 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 if (VarEncMD4) { 149 MD4Init(&MD4context); 150 MD4Update(&MD4context, answer, ap - answer); 151 MD4Final(digest, &MD4context); 152 } else { 153 MD5Init(&MD5context); 154 MD5Update(&MD5context, answer, ap - answer); 155 MD5Final(digest, &MD5context); 156 } 157 LogDumpBuff(LogDEBUG, "answer", digest, 16); 158 bcopy(name, digest + 16, namelen); 159 ap += namelen; 160 /* Send answer to the peer */ 161 ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); 162 free(argp); 163 break; 164 case CHAP_RESPONSE: 165 if (keyp) { 166 167 /* 168 * Compute correct digest value 169 */ 170 keylen = strlen(keyp); 171 ap = answer; 172 *ap++ = chp->id; 173 bcopy(keyp, ap, keylen); 174 ap += keylen; 175 if (VarEncMD4) { 176 MD4Init(&MD4context); 177 MD4Update(&MD4context, answer, ap - answer); 178 MD4Update(&MD4context, challenge_data + 1, challenge_len); 179 MD4Final(cdigest, &MD4context); 180 } else { 181 MD5Init(&MD5context); 182 MD5Update(&MD5context, answer, ap - answer); 183 MD5Update(&MD5context, challenge_data + 1, challenge_len); 184 MD5Final(cdigest, &MD5context); 185 } 186 LogDumpBuff(LogDEBUG, "got", cp, 16); 187 LogDumpBuff(LogDEBUG, "expect", cdigest, 16); 188 189 /* 190 * Compare with the response 191 */ 192 if (bcmp(cp, cdigest, 16) == 0) { 193 ChapOutput(CHAP_SUCCESS, chp->id, "Welcome!!", 10); 194 if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp)) 195 if (Utmp) 196 LogPrintf(LogERROR, "Oops, already logged in on %s\n", 197 VarBaseDevice); 198 else { 199 struct utmp ut; 200 memset(&ut, 0, sizeof(ut)); 201 time(&ut.ut_time); 202 strncpy(ut.ut_name, name, sizeof(ut.ut_name)-1); 203 strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); 204 if (logout(ut.ut_line)) 205 logwtmp(ut.ut_line, "", ""); 206 login(&ut); 207 Utmp = 1; 208 } 209 NewPhase(PHASE_NETWORK); 210 break; 211 } 212 } 213 214 /* 215 * Peer is not registerd, or response digest is wrong. 216 */ 217 ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); 218 reconnect(RECON_FALSE); 219 LcpClose(); 220 break; 221 } 222} 223 224void 225RecvChapResult(struct fsmheader * chp, struct mbuf * bp) 226{ 227 int len; 228 struct lcpstate *lcp = &LcpInfo; 229 230 len = ntohs(chp->length); 231 LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); 232 if (chp->code == CHAP_SUCCESS) { 233 if (lcp->auth_iwait == PROTO_CHAP) { 234 lcp->auth_iwait = 0; 235 if (lcp->auth_ineed == 0) 236 NewPhase(PHASE_NETWORK); 237 } 238 } else { 239 240 /* 241 * Maybe, we shoud close LCP. Of cause, peer may take close action, too. 242 */ 243 ; 244 } 245} 246 247void 248ChapInput(struct mbuf * bp) 249{ 250 int len = plength(bp); 251 struct fsmheader *chp; 252 253 if (len >= sizeof(struct fsmheader)) { 254 chp = (struct fsmheader *) MBUF_CTOP(bp); 255 if (len >= ntohs(chp->length)) { 256 if (chp->code < 1 || chp->code > 4) 257 chp->code = 0; 258 LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); 259 260 bp->offset += sizeof(struct fsmheader); 261 bp->cnt -= sizeof(struct fsmheader); 262 263 switch (chp->code) { 264 case CHAP_RESPONSE: 265 StopAuthTimer(&AuthChapInfo); 266 /* Fall into.. */ 267 case CHAP_CHALLENGE: 268 RecvChapTalk(chp, bp); 269 break; 270 case CHAP_SUCCESS: 271 case CHAP_FAILURE: 272 RecvChapResult(chp, bp); 273 break; 274 } 275 } 276 } 277 pfree(bp); 278} 279