* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#ifndef lint
-static char rcsid[] = "$Id: chap.c,v 1.21 1999/03/19 01:20:19 paulus Exp $";
-#endif
+#define RCSID "$Id: chap.c,v 1.26 2002/01/22 16:02:58 dfs Exp $"
/*
* TODO:
#include "chap_ms.h"
#endif
+/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */
+int (*chap_check_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the CHAP password for authenticating us */
+int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
+/* Hook for a plugin to validate CHAP challenge */
+int (*chap_auth_hook) __P((char *user,
+ u_char *remmd,
+ int remmd_len,
+ chap_state *cstate)) = NULL;
+
+static const char rcsid[] = RCSID;
+
/*
* Command-line options.
*/
static option_t chap_option_list[] = {
{ "chap-restart", o_int, &chap[0].timeouttime,
- "Set timeout for CHAP" },
+ "Set timeout for CHAP", OPT_PRIO },
{ "chap-max-challenge", o_int, &chap[0].max_transmits,
- "Set max #xmits for challenge" },
+ "Set max #xmits for challenge", OPT_PRIO },
{ "chap-interval", o_int, &chap[0].chal_interval,
- "Set interval for rechallenge" },
+ "Set interval for rechallenge", OPT_PRIO },
#ifdef MSLANMAN
{ "ms-lanman", o_bool, &ms_lanman,
"Use LanMan passwd when using MS-CHAP", 1 },
/*
* We get here as a result of LCP coming up.
- * So even if CHAP was open before, we will
+ * So even if CHAP was open before, we will
* have to re-authenticate ourselves.
*/
cstate->clientstate = CHAPCS_LISTEN;
int digest;
{
chap_state *cstate = &chap[unit];
-
+
cstate->chal_name = our_name;
cstate->chal_type = digest;
void *arg;
{
chap_state *cstate = (chap_state *) arg;
-
+
/* if we aren't sending challenges, don't worry. then again we */
/* probably shouldn't be here either */
if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
int unit;
{
chap_state *cstate = &chap[unit];
-
+
if (cstate->clientstate == CHAPCS_INITIAL)
cstate->clientstate = CHAPCS_CLOSED;
else if (cstate->clientstate == CHAPCS_PENDING)
int unit;
{
chap_state *cstate = &chap[unit];
-
+
/* Timeout(s) pending? Cancel if so. */
if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
cstate->serverstate == CHAPSS_RECHALLENGE)
u_char *inp;
u_char code, id;
int len;
-
+
/*
* Parse header (code, id and length).
* If packet too short, drop it.
return;
}
len -= CHAP_HEADERLEN;
-
+
/*
* Action depends on code (as in fact it usually does :-).
*/
case CHAP_CHALLENGE:
ChapReceiveChallenge(cstate, inp, id, len);
break;
-
+
case CHAP_RESPONSE:
ChapReceiveResponse(cstate, inp, id, len);
break;
-
+
case CHAP_FAILURE:
ChapReceiveFailure(cstate, inp, id, len);
break;
char rhostname[256];
MD5_CTX mdContext;
u_char hash[MD5_SIGNATURE_SIZE];
-
+
if (cstate->clientstate == CHAPCS_CLOSED ||
cstate->clientstate == CHAPCS_PENDING) {
CHAPDEBUG(("ChapReceiveChallenge: in state %d", cstate->clientstate));
cstate->resp_transmits = 0;
/* generate MD based on negotiated type */
- switch (cstate->resp_type) {
+ switch (cstate->resp_type) {
case CHAP_DIGEST_MD5:
MD5Init(&mdContext);
* do the hash ourselves, and compare the result.
*/
code = CHAP_FAILURE;
- if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
- cstate->chal_name, secret, &secret_len, 1)) {
- warn("No CHAP secret found for authenticating %q", rhostname);
- } else {
- /* generate MD based on negotiated type */
- switch (cstate->chal_type) {
-
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
- if (remmd_len != MD5_SIGNATURE_SIZE)
- break; /* it's not even the right length */
- MD5Init(&mdContext);
- MD5Update(&mdContext, &cstate->chal_id, 1);
- MD5Update(&mdContext, secret, secret_len);
- MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
- MD5Final(hash, &mdContext);
-
- /* compare local and remote MDs and send the appropriate status */
- if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
- code = CHAP_SUCCESS; /* they are the same! */
- break;
-
- default:
- CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
+ /* If a plugin will verify the response, let the plugin do it. */
+ if (chap_auth_hook) {
+ code = (*chap_auth_hook) ( (explicit_remote ? remote_name : rhostname),
+ remmd, (int) remmd_len,
+ cstate );
+ } else {
+ if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
+ cstate->chal_name, secret, &secret_len, 1)) {
+ warn("No CHAP secret found for authenticating %q", rhostname);
+ } else {
+
+ /* generate MD based on negotiated type */
+ switch (cstate->chal_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ if (remmd_len != MD5_SIGNATURE_SIZE)
+ break; /* it's not even the right length */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->chal_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+ MD5Final(hash, &mdContext);
+
+ /* compare local and remote MDs and send the appropriate status */
+ if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
+ code = CHAP_SUCCESS; /* they are the same! */
+ break;
+
+ default:
+ CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
+ }
}
- }
- BZERO(secret, sizeof(secret));
+ BZERO(secret, sizeof(secret));
+ }
ChapSendStatus(cstate, code);
if (code == CHAP_SUCCESS) {
BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
-
+
TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
++cstate->chal_transmits;
}
outp = outpacket_buf;
MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
-
+
PUTCHAR(code, outp);
PUTCHAR(cstate->chal_id, outp);
PUTSHORT(outlen, outp);
{
int chal_len;
u_char *ptr = cstate->challenge;
- unsigned int i;
+ int i;
- /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
- MAX_CHALLENGE_LENGTH */
+ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+ MAX_CHALLENGE_LENGTH */
chal_len = (unsigned) ((drand48() *
(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
MIN_CHALLENGE_LENGTH);
cstate->chal_transmits = 0;
/* generate a random string */
- for (i = 0; i < chal_len; i++ )
+ for (i = 0; i < chal_len; i++)
*ptr++ = (char) (drand48() * 0xff);
}