927145be97
o Use syslog o Remove references to stdout/stderr (incl perror()) o Introduce VarTerm - the interactive terminal or zero o Allow "set timeout" to affect current session o Change "set debug" to "set log" o Allow "set log [+|-]flag" o Make MSEXT and PASSWDAUTH stuff the default o Move all #ifdef DEBUG stuff into the code - this shouldn't be too much overhead. It's now controlled with "set log +debug" o Add "set log command, debug, tun, warn, error, alert" o Remove cdefs.h, and assume an ansi compiler. o Improve all diagnostic output o Don't trap SIGSEGV o SIGHUP now terminates again (log files are controlled by syslog) o Call CloseModem() when changing devices o Fix parsing of third arg of "delete" I think this fixes the "magic is same" problems that some people have been experiencing. The man page is being rewritten. It'll follow soon.
250 lines
6.1 KiB
C
250 lines
6.1 KiB
C
/*
|
|
* PPP CHAP Module
|
|
*
|
|
* Written by Toshiharu OHNO (tony-o@iij.ad.jp)
|
|
*
|
|
* Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that the above copyright notice and this paragraph are
|
|
* duplicated in all such forms and that any documentation,
|
|
* advertising materials, and other materials related to such
|
|
* distribution and use acknowledge that the software was developed
|
|
* by the Internet Initiative Japan, Inc. The name of the
|
|
* IIJ may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* $Id: chap.c,v 1.17 1997/05/26 00:43:56 brian Exp $
|
|
*
|
|
* TODO:
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include "fsm.h"
|
|
#include "chap.h"
|
|
#include "lcpproto.h"
|
|
#include "lcp.h"
|
|
#include "hdlc.h"
|
|
#include "phase.h"
|
|
#include "loadalias.h"
|
|
#include "vars.h"
|
|
#include "auth.h"
|
|
|
|
static char *chapcodes[] = {
|
|
"???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
|
|
};
|
|
|
|
struct authinfo AuthChapInfo = {
|
|
SendChapChallenge,
|
|
};
|
|
|
|
extern char *AuthGetSecret();
|
|
extern int randinit;
|
|
|
|
void
|
|
ChapOutput(code, id, ptr, count)
|
|
u_int code, id;
|
|
u_char *ptr;
|
|
int count;
|
|
{
|
|
int plen;
|
|
struct fsmheader lh;
|
|
struct mbuf *bp;
|
|
|
|
plen = sizeof(struct fsmheader) + count;
|
|
lh.code = code;
|
|
lh.id = id;
|
|
lh.length = htons(plen);
|
|
bp = mballoc(plen, MB_FSM);
|
|
bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
|
|
if (count)
|
|
bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
|
|
LogDumpBp(LogDEBUG, "ChapOutput", bp);
|
|
LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]);
|
|
HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
|
|
}
|
|
|
|
|
|
static char challenge_data[80];
|
|
static int challenge_len;
|
|
|
|
void
|
|
SendChapChallenge(chapid)
|
|
int chapid;
|
|
{
|
|
int len, i;
|
|
char *cp;
|
|
|
|
if (!randinit) {
|
|
randinit = 1;
|
|
if (srandomdev() < 0)
|
|
srandom((unsigned long)(time(NULL) ^ getpid()));
|
|
}
|
|
|
|
cp = challenge_data;
|
|
*cp++ = challenge_len = random() % 32 + 16;
|
|
for (i = 0; i < challenge_len; i++)
|
|
*cp++ = random() & 0xff;
|
|
len = strlen(VarAuthName);
|
|
bcopy(VarAuthName, cp, len);
|
|
cp += len;
|
|
ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
|
|
}
|
|
|
|
void
|
|
RecvChapTalk(chp, bp)
|
|
struct fsmheader *chp;
|
|
struct mbuf *bp;
|
|
{
|
|
int valsize, len;
|
|
int arglen, keylen, namelen;
|
|
char *cp, *argp, *ap, *name, *digest;
|
|
char *keyp;
|
|
MD5_CTX context; /* context */
|
|
char answer[100];
|
|
char cdigest[16];
|
|
|
|
len = ntohs(chp->length);
|
|
LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len);
|
|
arglen = len - sizeof(struct fsmheader);
|
|
cp = (char *)MBUF_CTOP(bp);
|
|
valsize = *cp++ & 255;
|
|
name = cp + valsize;
|
|
namelen = arglen - valsize - 1;
|
|
name[namelen] = 0;
|
|
LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name);
|
|
|
|
/*
|
|
* Get a secret key corresponds to the peer
|
|
*/
|
|
keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
|
|
|
|
switch (chp->code) {
|
|
case CHAP_CHALLENGE:
|
|
if (keyp) {
|
|
keylen = strlen(keyp);
|
|
} else {
|
|
keylen = strlen(VarAuthKey);
|
|
keyp = VarAuthKey;
|
|
}
|
|
name = VarAuthName;
|
|
namelen = strlen(VarAuthName);
|
|
argp = malloc(1 + valsize + namelen + 16);
|
|
if (argp == NULL) {
|
|
ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
|
|
return;
|
|
}
|
|
digest = argp;
|
|
*digest++ = 16; /* value size */
|
|
ap = answer;
|
|
*ap++ = chp->id;
|
|
bcopy(keyp, ap, keylen);
|
|
ap += keylen;
|
|
bcopy(cp, ap, valsize);
|
|
LogDumpBuff(LogDEBUG, "recv", ap, valsize);
|
|
ap += valsize;
|
|
MD5Init(&context);
|
|
MD5Update(&context, answer, ap - answer);
|
|
MD5Final(digest, &context);
|
|
LogDumpBuff(LogDEBUG, "answer", digest, 16);
|
|
bcopy(name, digest + 16, namelen);
|
|
ap += namelen;
|
|
/* Send answer to the peer */
|
|
ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
|
|
free(argp);
|
|
break;
|
|
case CHAP_RESPONSE:
|
|
if (keyp) {
|
|
/*
|
|
* Compute correct digest value
|
|
*/
|
|
keylen = strlen(keyp);
|
|
ap = answer;
|
|
*ap++ = chp->id;
|
|
bcopy(keyp, ap, keylen);
|
|
ap += keylen;
|
|
MD5Init(&context);
|
|
MD5Update(&context, answer, ap - answer);
|
|
MD5Update(&context, challenge_data+1, challenge_len);
|
|
MD5Final(cdigest, &context);
|
|
LogDumpBuff(LogDEBUG, "got", cp, 16);
|
|
LogDumpBuff(LogDEBUG, "expect", cdigest, 16);
|
|
/*
|
|
* Compare with the response
|
|
*/
|
|
if (bcmp(cp, cdigest, 16) == 0) {
|
|
ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
|
|
NewPhase(PHASE_NETWORK);
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Peer is not registerd, or response digest is wrong.
|
|
*/
|
|
ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
|
|
reconnect(RECON_FALSE);
|
|
LcpClose();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
RecvChapResult(chp, bp)
|
|
struct fsmheader *chp;
|
|
struct mbuf *bp;
|
|
{
|
|
int len;
|
|
struct lcpstate *lcp = &LcpInfo;
|
|
|
|
len = ntohs(chp->length);
|
|
LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len);
|
|
if (chp->code == CHAP_SUCCESS) {
|
|
if (lcp->auth_iwait == PROTO_CHAP) {
|
|
lcp->auth_iwait = 0;
|
|
if (lcp->auth_ineed == 0)
|
|
NewPhase(PHASE_NETWORK);
|
|
}
|
|
} else {
|
|
/*
|
|
* Maybe, we shoud close LCP. Of cause, peer may take close action, too.
|
|
*/
|
|
;
|
|
}
|
|
}
|
|
|
|
void
|
|
ChapInput(struct mbuf *bp)
|
|
{
|
|
int len = plength(bp);
|
|
struct fsmheader *chp;
|
|
|
|
if (len >= sizeof(struct fsmheader)) {
|
|
chp = (struct fsmheader *)MBUF_CTOP(bp);
|
|
if (len >= ntohs(chp->length)) {
|
|
if (chp->code < 1 || chp->code > 4)
|
|
chp->code = 0;
|
|
LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]);
|
|
|
|
bp->offset += sizeof(struct fsmheader);
|
|
bp->cnt -= sizeof(struct fsmheader);
|
|
|
|
switch (chp->code) {
|
|
case CHAP_RESPONSE:
|
|
StopAuthTimer(&AuthChapInfo);
|
|
/* Fall into.. */
|
|
case CHAP_CHALLENGE:
|
|
RecvChapTalk(chp, bp);
|
|
break;
|
|
case CHAP_SUCCESS:
|
|
case CHAP_FAILURE:
|
|
RecvChapResult(chp, bp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pfree(bp);
|
|
}
|