/*
* chap.c - Challenge Handshake Authentication Protocol.
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1993 The Australian National University.
* All rights reserved.
*
* 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 Australian National University. The name of the University
* 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.
*
* Copyright (c) 1991 Gregory M. Christy.
* All rights reserved.
*
* 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 Gregory M. Christy. The name of the author 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.
*/
/*
* TODO:
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "pppd.h"
#include "chap.h"
#include "md5.h"
#include "chap_ms.h"
#endif
#endif
/*
* Command-line options.
*/
"Set CHAP Challenge retry interval" },
"Max number of Challenges sent without a valid response" },
"Set interval for rechallenge" },
"Use obsolete LAN Manager password when using MS-CHAP", 1 },
#endif
{ NULL }
};
/*
* Protocol entry points.
*/
static void ChapLowerUp __P((int));
static void ChapLowerDown __P((int));
static void ChapProtocolReject __P((int));
void (*) __P((void *, const char *, ...)), void *));
PPP_CHAP, /* PPP protocol number */
ChapInit, /* Initialization procedure */
ChapInput, /* Process a received packet */
ChapProtocolReject, /* Process a received protocol-reject */
ChapLowerUp, /* Lower layer has come up */
ChapLowerDown, /* Lower layer has gone down */
NULL, /* Open the protocol */
NULL, /* Close the protocol */
ChapPrintPkt, /* Print a packet in readable form */
NULL, /* Process a received data packet */
1, /* 0 iff protocol is disabled */
"CHAP", /* Text name of protocol */
NULL, /* Text name of corresponding data protocol */
chap_option_list, /* List of command-line options */
NULL, /* Check requested options, assign defaults */
NULL, /* Configure interface for demand-dial */
NULL /* Say whether to bring up link for this pkt */
};
/* Not static'd for plug-ins */
static void ChapChallengeTimeout __P((void *));
static void ChapResponseTimeout __P((void *));
static void ChapRechallenge __P((void *));
static const char *
{
return (buf);
}
return cstate[clientstate];
}
static const char *
{
return (buf);
}
return sstate[serverstate];
}
/*
* ChapInit - Initialize a CHAP unit.
*/
static void
int unit;
{
/* XXX save get_first_hwaddr() here. */
/* random number generator is initialized in magic_init */
}
/*
* ChapAuthWithPeer - Authenticate us with our peer (start client).
*
*/
void
int unit;
char *our_name;
int digest;
{
/* lower layer isn't up - wait until later */
return;
}
/*
* We get here as a result of LCP coming up.
* So even if CHAP was open before, we will
* have to re-authenticate ourselves.
*/
}
/*
* ChapAuthPeer - Authenticate our peer (start server).
*/
void
int unit;
char *our_name;
int digest;
{
/* lower layer isn't up - wait until later */
return;
}
}
/*
* ChapChallengeTimeout - Timeout expired on sending challenge.
*/
static void
void *arg;
{
/* if we aren't sending challenges, don't worry. then again we */
/* probably shouldn't be here either */
return;
/* give up on peer */
error("Peer failed to respond to CHAP challenge");
return;
}
}
/*
* ChapResponseTimeout - Timeout expired on sending response.
*/
static void
void *arg;
{
/* if we aren't sending a response, don't worry. */
return;
}
/*
* ChapRechallenge - Time to challenge the peer again.
*/
static void
void *arg;
{
/* if we aren't sending a response, don't worry. */
return;
}
/*
* ChapLowerUp - The lower layer is up.
*
* Start up if we have pending requests.
*/
static void
int unit;
{
}
}
/*
* ChapLowerDown - The lower layer is down.
*
* Cancel all timeouts.
*/
static void
int unit;
{
/* Timeout(s) pending? Cancel if so. */
&& cstate->chal_interval != 0)
}
/*
* ChapProtocolReject - Peer doesn't grok CHAP.
*/
static void
int unit;
{
}
/*
* ChapInput - Input CHAP packet.
*/
static void
int unit;
int packet_len;
{
int len;
/*
* Parse header (code, id and length).
* If packet too short, drop it.
*/
if (packet_len < CHAP_HEADERLEN) {
return;
}
error("CHAP: packet has illegal length %d (%d..%d)",
return;
}
len -= CHAP_HEADERLEN;
/*
* Action depends on code (as in fact it usually does :-).
*/
switch (code) {
case CHAP_CHALLENGE:
break;
case CHAP_RESPONSE:
break;
case CHAP_FAILURE:
break;
case CHAP_SUCCESS:
break;
default:
/* CHAP does not define a code reject. */
break;
}
}
/*
* ChapReceiveChallenge - Receive Challenge and send Response.
*/
static void
int id;
int len;
{
int rchallenge_len;
int secret_len;
int fake_response = 0;
if (debug)
dbglog("CHAP Challenge unexpectedly received in state %s",
return;
}
if (len < 2) {
return;
}
if (len < 0) {
error("CHAP: Challenge truncated");
return;
}
rchallenge = inp;
if (len > 0) {
}
#ifdef CHECK_CHALLENGE_LENGTH
if (rchallenge_len < CHECK_CHALLENGE_LENGTH) {
warn("CHAP: Challenge from %s unreasonably short (%d octets)",
fake_response = 1;
}
#endif
/* XXX compare against saved get_first_hwaddr() here. */
/* Microsoft NT doesn't send a name in the CHAP Challenge message */
if (explicit_remote ||
if (debug)
dbglog("CHAP: Peer gave no name; using '%q' as remote name",
}
info("CHAP: peer challenge name changed from '%q' to '%q'",
} else {
fake_response = 1;
warn("CHAP: peer challenge name changed again to '%q'",
}
}
/* get secret for authenticating ourselves with the specified host */
secret, &secret_len, 0)) {
secret_len = 0; /* assume null secret if can't find one */
warn("No CHAP secret found for authenticating us (%q) to %q",
}
/* cancel response send timeout if necessary */
cstate->resp_transmits = 0;
/* generate MD based on negotiated type */
case CHAP_DIGEST_MD5:
if (fake_response) {
} else {
}
break;
#ifdef CHAPMS
case CHAP_MICROSOFT:
break;
#endif
#ifdef CHAPMSV2
case CHAP_MICROSOFT_V2:
break;
#endif
default:
return;
}
}
/*
* ChapReceiveResponse - Receive and process response.
*/
static void
int id;
int len;
{
int code;
if (debug)
dbglog("CHAP Response unexpectedly received in state %s",
return;
}
if (debug)
return; /* doesn't match ID of last challenge */
}
/*
* If we have received a duplicate or bogus Response,
* as we did for the first Response we saw.
*/
if (debug)
dbglog("CHAP ignoring response and resending success message");
return;
}
if (debug)
dbglog("CHAP ignoring response and resending failure message");
return;
}
if (len < 2) {
return;
}
if (len < 0) {
error("CHAP: Response truncated");
return;
}
/*
* Get secret for authenticating them with us,
* do the hash ourselves, and compare the result.
*/
code = CHAP_FAILURE;
warn("Peer changed his name from '%q' to '%q' on rechallenge",
&secret_len, 1)) {
warn("No CHAP secret found for authenticating %q to us (%q)",
} else {
/* generate MD based on negotiated 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 */
/* compare local and remote MDs and send the appropriate status */
break;
#ifdef CHAPMS
case CHAP_MICROSOFT:
code = CHAP_SUCCESS;
break;
#endif
#ifdef CHAPMSV2
case CHAP_MICROSOFT_V2:
secret, secret_len))
code = CHAP_SUCCESS;
break;
#endif
default:
}
}
if (code == CHAP_SUCCESS) {
if (old_state == CHAPSS_INITIAL_CHAL) {
}
if (cstate->chal_interval != 0)
if (old_state == CHAPSS_INITIAL_CHAL)
else if (debug)
} else {
error("CHAP peer %sauthentication failed for remote host %q",
}
}
/*
* ChapReceiveSuccess - Receive Success
*/
/*ARGSUSED*/
static void
int len;
{
/* presumably an answer to a duplicate response */
if (debug)
dbglog("CHAP duplicate Success message ignored");
return;
}
/* don't know what this is */
if (debug)
dbglog("CHAP Success unexpectedly received in state %s",
return;
}
/*
* Print message.
*/
if (len > 0)
}
/*
* ChapReceiveFailure - Receive failure.
*/
/*ARGSUSED*/
static void
int len;
{
/* don't know what this is */
if (debug)
dbglog("CHAP Failure unexpectedly received in state %s",
return;
}
/*
* Print message.
*/
if (len > 0)
error("CHAP authentication failed");
}
/*
* ChapSendChallenge - Send an Authenticate challenge.
*/
static void
{
int outlen;
++cstate->chal_transmits;
}
/*
* ChapSendStatus - Send a status response (ack or nak).
*/
static void
int code;
{
} else {
if (code == CHAP_SUCCESS)
else
}
}
/*
* ChapGenChallenge is used to generate a pseudo-random challenge string of
* a pseudo-random length between min_len and max_len. The challenge
* string and its length are stored in *cstate, and various other fields of
* *cstate are initialized.
*/
static void
{
int chal_len;
int i;
/* pick a random challenge length between MIN_CHALLENGE_LENGTH and
MAX_CHALLENGE_LENGTH */
cstate->chal_transmits = 0;
/* XXX tack on saved get_first_hwaddr() here. */
/* generate a random string */
for (i = 0; i < chal_len; i++)
}
/*
* ChapSendResponse - send a response packet with values as specified
* in *cstate.
*/
/* ARGSUSED */
static void
{
/* send the packet */
++cstate->resp_transmits;
}
/*
* ChapPrintPkt - print the contents of a CHAP packet.
*/
static char *ChapCodenames[] = {
"Challenge", "Response", "Success", "Failure"
};
static int
u_char *p;
int plen;
void *arg;
{
u_char x;
if (plen < CHAP_HEADERLEN)
return 0;
return 0;
else
len -= CHAP_HEADERLEN;
switch (code) {
case CHAP_CHALLENGE:
case CHAP_RESPONSE:
if (len < 1)
break;
clen = p[0];
break;
++p;
GETCHAR(x, p);
}
break;
case CHAP_FAILURE:
case CHAP_SUCCESS:
break;
default:
GETCHAR(x, p);
}
}
return len + CHAP_HEADERLEN;
}