diff options
author | brian <brian@cvs.openbsd.org> | 1997-11-23 20:27:41 +0000 |
---|---|---|
committer | brian <brian@cvs.openbsd.org> | 1997-11-23 20:27:41 +0000 |
commit | 2cb79b0580b6b5629530c4d142a73a9a654f282f (patch) | |
tree | 8b062ff5e99e22ec2c95145149e22b58b7fc0e22 /usr.sbin/ppp/chap.c | |
parent | 518c0071f44dfb9716d70e0d8781585db7a3bd7d (diff) |
Import version 1.5 of ppp.
<sales>
This is a user-level ppp implementation that uses the
tun driver. It was originally created by a Japanese
ISP. It's now piled with features. Check the man pages
for details.
</sales>
The sources are identical to the ones in FreeBSD, except
for the Makefile.
IP aliasing (NAT) is disabled, and can be enabled by simply
doing a ``make install'' of libalias, then rebuilding
ppp. I'll create libalias as a port soon.
Diffstat (limited to 'usr.sbin/ppp/chap.c')
-rw-r--r-- | usr.sbin/ppp/chap.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/chap.c new file mode 100644 index 00000000000..539d629e3ff --- /dev/null +++ b/usr.sbin/ppp/chap.c @@ -0,0 +1,311 @@ +/* + * 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.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ +#include <sys/param.h> +#include <netinet/in.h> + +#include <ctype.h> +#ifdef HAVE_DES +#include <md4.h> +#endif +#include <md5.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#ifdef __OpenBSD__ +#include <util.h> +#else +#include <libutil.h> +#endif +#include <utmp.h> + +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "chap.h" +#include "chap_ms.h" +#include "lcpproto.h" +#include "lcp.h" +#include "hdlc.h" +#include "phase.h" +#include "loadalias.h" +#include "vars.h" +#include "auth.h" + +static const char *chapcodes[] = { + "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" +}; + +static void +ChapOutput(u_int code, u_int id, const 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); + memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); + if (count) + memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, 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; + +static void +SendChapChallenge(int chapid) +{ + int len, i; + char *cp; + + randinit(); + cp = challenge_data; + *cp++ = challenge_len = random() % 32 + 16; + for (i = 0; i < challenge_len; i++) + *cp++ = random() & 0xff; + len = strlen(VarAuthName); + memcpy(cp, VarAuthName, len); + cp += len; + ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); +} + +struct authinfo AuthChapInfo = { + SendChapChallenge, +}; + +static void +RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) +{ + int valsize, len; + int arglen, keylen, namelen; + char *cp, *argp, *ap, *name, *digest; + char *keyp; + MD5_CTX MD5context; /* context for MD5 */ + char answer[100]; + char cdigest[16]; +#ifdef HAVE_DES + int ix; + MD4_CTX MD4context; /* context for MD4 */ +#endif + + 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); + + switch (chp->code) { + case CHAP_CHALLENGE: + keyp = VarAuthKey; + keylen = strlen(VarAuthKey); + name = VarAuthName; + namelen = strlen(VarAuthName); + +#ifdef HAVE_DES + if (VarMSChap) + argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); + else +#endif + argp = malloc(1 + valsize + namelen + 16); + + if (argp == NULL) { + ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); + return; + } +#ifdef HAVE_DES + if (VarMSChap) { + digest = argp; /* this is the response */ + *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ + memset(digest, '\0', 24); + digest += 24; + + ap = answer; /* this is the challenge */ + memcpy(ap, keyp, keylen); + ap += 2 * keylen; + memcpy(ap, cp, valsize); + LogDumpBuff(LogDEBUG, "recv", ap, valsize); + ap += valsize; + for (ix = keylen; ix > 0 ; ix--) { + answer[2*ix-2] = answer[ix-1]; + answer[2*ix-1] = 0; + } + MD4Init(&MD4context); + MD4Update(&MD4context, answer, 2 * keylen); + MD4Final(digest, &MD4context); + memcpy(digest + 25, name, namelen); + ap += 2 * keylen; + ChapMS(digest, answer + 2 * keylen, valsize); + LogDumpBuff(LogDEBUG, "answer", digest, 24); + ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + MS_CHAP_RESPONSE_LEN + 1); + } else { +#endif + digest = argp; + *digest++ = 16; /* value size */ + ap = answer; + *ap++ = chp->id; + memcpy(ap, keyp, keylen); + ap += keylen; + memcpy(ap, cp, valsize); + LogDumpBuff(LogDEBUG, "recv", ap, valsize); + ap += valsize; + MD5Init(&MD5context); + MD5Update(&MD5context, answer, ap - answer); + MD5Final(digest, &MD5context); + LogDumpBuff(LogDEBUG, "answer", digest, 16); + memcpy(digest + 16, name, namelen); + ap += namelen; + /* Send answer to the peer */ + ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); +#ifdef HAVE_DES + } +#endif + free(argp); + break; + case CHAP_RESPONSE: + /* + * Get a secret key corresponds to the peer + */ + keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); + if (keyp) { + /* + * Compute correct digest value + */ + keylen = strlen(keyp); + ap = answer; + *ap++ = chp->id; + memcpy(ap, keyp, keylen); + ap += keylen; + MD5Init(&MD5context); + MD5Update(&MD5context, answer, ap - answer); + MD5Update(&MD5context, challenge_data + 1, challenge_len); + MD5Final(cdigest, &MD5context); + LogDumpBuff(LogDEBUG, "got", cp, 16); + LogDumpBuff(LogDEBUG, "expect", cdigest, 16); + + /* + * Compare with the response + */ + if (memcmp(cp, cdigest, 16) == 0) { + ChapOutput(CHAP_SUCCESS, chp->id, "Welcome!!", 10); + if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp)) + if (Utmp) + LogPrintf(LogERROR, "Oops, already logged in on %s\n", + VarBaseDevice); + else { + struct utmp ut; + memset(&ut, 0, sizeof(ut)); + time(&ut.ut_time); + strncpy(ut.ut_name, name, sizeof(ut.ut_name)-1); + strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); + if (logout(ut.ut_line)) + logwtmp(ut.ut_line, "", ""); + login(&ut); + Utmp = 1; + } + 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; + } +} + +static void +RecvChapResult(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); +} |