diff options
Diffstat (limited to 'libexec/pppd/chap.c')
-rw-r--r-- | libexec/pppd/chap.c | 986 |
1 files changed, 531 insertions, 455 deletions
diff --git a/libexec/pppd/chap.c b/libexec/pppd/chap.c index 6643db16c0dc..ebdc6537fb0c 100644 --- a/libexec/pppd/chap.c +++ b/libexec/pppd/chap.c @@ -18,6 +18,10 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +#ifndef lint +static char rcsid[] = "$Id: chap.c,v 1.3 1994/03/30 09:38:11 jkh Exp $"; +#endif + /* * TODO: */ @@ -27,33 +31,23 @@ #include <sys/time.h> #include <syslog.h> -#ifdef STREAMS -#include <sys/socket.h> -#include <net/if.h> -#include <sys/stream.h> -#endif - -#include <net/ppp.h> +#include "ppp.h" #include "pppd.h" -#include "fsm.h" -#include "lcp.h" #include "chap.h" -#include "upap.h" -#include "ipcp.h" #include "md5.h" -chap_state chap[NPPP]; /* CHAP state; one for each unit */ +chap_state chap[_NPPP]; /* CHAP state; one for each unit */ -static void ChapTimeout __ARGS((caddr_t)); +static void ChapChallengeTimeout __ARGS((caddr_t)); +static void ChapResponseTimeout __ARGS((caddr_t)); static void ChapReceiveChallenge __ARGS((chap_state *, u_char *, int, int)); static void ChapReceiveResponse __ARGS((chap_state *, u_char *, int, int)); static void ChapReceiveSuccess __ARGS((chap_state *, u_char *, int, int)); static void ChapReceiveFailure __ARGS((chap_state *, u_char *, int, int)); -static void ChapSendStatus __ARGS((chap_state *, int, int, - u_char *, int)); +static void ChapSendStatus __ARGS((chap_state *, int)); static void ChapSendChallenge __ARGS((chap_state *)); -static void ChapSendResponse __ARGS((chap_state *, int, u_char *, int)); -static void ChapGenChallenge __ARGS((int, u_char *)); +static void ChapSendResponse __ARGS((chap_state *)); +static void ChapGenChallenge __ARGS((chap_state *)); extern double drand48 __ARGS((void)); extern void srand48 __ARGS((long)); @@ -62,21 +56,18 @@ extern void srand48 __ARGS((long)); * ChapInit - Initialize a CHAP unit. */ void - ChapInit(unit) -int unit; +ChapInit(unit) + int unit; { - chap_state *cstate = &chap[unit]; - - cstate->unit = unit; - cstate->chal_str[0] = '\000'; - cstate->chal_len = 0; - cstate->clientstate = CHAPCS_CLOSED; - cstate->serverstate = CHAPSS_CLOSED; - cstate->flags = 0; - cstate->id = 0; - cstate->timeouttime = CHAP_DEFTIMEOUT; - cstate->retransmits = 0; - srand48((long) time(NULL)); /* joggle random number generator */ + chap_state *cstate = &chap[unit]; + + BZERO(cstate, sizeof(*cstate)); + cstate->unit = unit; + cstate->clientstate = CHAPCS_INITIAL; + cstate->serverstate = CHAPSS_INITIAL; + cstate->timeouttime = CHAP_DEFTIMEOUT; + cstate->max_transmits = CHAP_DEFTRANSMITS; + srand48((long) time(NULL)); /* joggle random number generator */ } @@ -85,35 +76,29 @@ int unit; * */ void - ChapAuthWithPeer(unit) -int unit; +ChapAuthWithPeer(unit, our_name, digest) + int unit; + char *our_name; + int digest; { - chap_state *cstate = &chap[unit]; - - cstate->flags &= ~CHAPF_AWPPENDING; /* Clear pending flag */ - - /* Protect against programming errors that compromise security */ - if (cstate->serverstate != CHAPSS_CLOSED || - cstate->flags & CHAPF_APPENDING) { - CHAPDEBUG((LOG_INFO, - "ChapAuthWithPeer: we were called already!")) - return; - } - - if (cstate->clientstate == CHAPCS_CHALLENGE_SENT || /* should we be here? */ - cstate->clientstate == CHAPCS_OPEN) - return; - - /* Lower layer up? */ - if (!(cstate->flags & CHAPF_LOWERUP)) { - cstate->flags |= CHAPF_AWPPENDING; /* Nah, Wait */ - return; - } - ChapSendChallenge(cstate); /* crank it up dude! */ - TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime); - /* set-up timeout */ - cstate->clientstate = CHAPCS_CHALLENGE_SENT; /* update state */ - cstate->retransmits = 0; + chap_state *cstate = &chap[unit]; + + cstate->resp_name = our_name; + cstate->resp_type = digest; + + if (cstate->clientstate == CHAPCS_INITIAL || + cstate->clientstate == CHAPCS_PENDING) { + /* lower layer isn't up - wait until later */ + cstate->clientstate = CHAPCS_PENDING; + 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. + */ + cstate->clientstate = CHAPCS_LISTEN; } @@ -121,44 +106,92 @@ int unit; * ChapAuthPeer - Authenticate our peer (start server). */ void - ChapAuthPeer(unit) -int unit; +ChapAuthPeer(unit, our_name, digest) + int unit; + char *our_name; + int digest; { - chap_state *cstate = &chap[unit]; + chap_state *cstate = &chap[unit]; - cstate->flags &= ~CHAPF_APPENDING; /* Clear pending flag */ - - /* Already authenticat{ed,ing}? */ - if (cstate->serverstate == CHAPSS_LISTEN || - cstate->serverstate == CHAPSS_OPEN) - return; - - /* Lower layer up? */ - if (!(cstate->flags & CHAPF_LOWERUP)) { - cstate->flags |= CHAPF_APPENDING; /* Wait for desired event */ - return; - } - cstate->serverstate = CHAPSS_LISTEN; + cstate->chal_name = our_name; + cstate->chal_type = digest; + + if (cstate->serverstate == CHAPSS_INITIAL || + cstate->serverstate == CHAPSS_PENDING) { + /* lower layer isn't up - wait until later */ + cstate->serverstate = CHAPSS_PENDING; + return; + } + + ChapGenChallenge(cstate); + ChapSendChallenge(cstate); /* crank it up dude! */ + cstate->serverstate = CHAPSS_INITIAL_CHAL; } /* - * ChapTimeout - Timeout expired. + * ChapChallengeTimeout - Timeout expired on sending challenge. */ static void - ChapTimeout(arg) -caddr_t arg; +ChapChallengeTimeout(arg) + caddr_t arg; { - chap_state *cstate = (chap_state *) 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->clientstate != CHAPCS_CHALLENGE_SENT) - return; - - ChapSendChallenge(cstate); /* Send challenge */ - TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime); - ++cstate->retransmits; + /* if we aren't sending challenges, don't worry. then again we */ + /* probably shouldn't be here either */ + if (cstate->serverstate != CHAPSS_INITIAL_CHAL && + cstate->serverstate != CHAPSS_RECHALLENGE) + return; + + if (cstate->chal_transmits >= cstate->max_transmits) { + /* give up on peer */ + syslog(LOG_ERR, "Peer failed to respond to CHAP challenge"); + cstate->serverstate = CHAPSS_BADAUTH; + auth_peer_fail(cstate->unit, CHAP); + return; + } + + ChapSendChallenge(cstate); /* Re-send challenge */ +} + + +/* + * ChapResponseTimeout - Timeout expired on sending response. + */ +static void +ChapResponseTimeout(arg) + caddr_t arg; +{ + chap_state *cstate = (chap_state *) arg; + + /* if we aren't sending a response, don't worry. */ + if (cstate->clientstate != CHAPCS_RESPONSE) + return; + + ChapSendResponse(cstate); /* re-send response */ +} + + +/* + * ChapRechallenge - Time to challenge the peer again. + */ +static void +ChapRechallenge(arg) + caddr_t arg; +{ + chap_state *cstate = (chap_state *) arg; + + /* if we aren't sending a response, don't worry. */ + if (cstate->serverstate != CHAPSS_OPEN) + return; + + ChapGenChallenge(cstate); + ChapSendChallenge(cstate); + cstate->serverstate = CHAPSS_RECHALLENGE; + + if (cstate->chal_interval != 0) + TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval); } @@ -168,16 +201,23 @@ caddr_t arg; * Start up if we have pending requests. */ void - ChapLowerUp(unit) -int unit; +ChapLowerUp(unit) + int unit; { - chap_state *cstate = &chap[unit]; + chap_state *cstate = &chap[unit]; - cstate->flags |= CHAPF_LOWERUP; - if (cstate->flags & CHAPF_AWPPENDING) /* were we attempting authwithpeer? */ - ChapAuthWithPeer(unit); /* Try it now */ - if (cstate->flags & CHAPF_APPENDING) /* or authpeer? */ - ChapAuthPeer(unit); + if (cstate->clientstate == CHAPCS_INITIAL) + cstate->clientstate = CHAPCS_CLOSED; + else if (cstate->clientstate == CHAPCS_PENDING) + cstate->clientstate = CHAPCS_LISTEN; + + if (cstate->serverstate == CHAPSS_INITIAL) + cstate->serverstate = CHAPSS_CLOSED; + else if (cstate->serverstate == CHAPSS_PENDING) { + ChapGenChallenge(cstate); + ChapSendChallenge(cstate); + cstate->serverstate = CHAPSS_INITIAL_CHAL; + } } @@ -187,20 +227,23 @@ int unit; * Cancel all timeouts. */ void - ChapLowerDown(unit) -int unit; +ChapLowerDown(unit) + int unit; { - chap_state *cstate = &chap[unit]; + chap_state *cstate = &chap[unit]; - cstate->flags &= ~CHAPF_LOWERUP; - - if (cstate->clientstate == CHAPCS_CHALLENGE_SENT) /* Timeout pending? */ - UNTIMEOUT(ChapTimeout, (caddr_t) cstate); /* Cancel timeout */ - - if (cstate->serverstate == CHAPSS_OPEN) /* have we successfully authed? */ - LOGOUT(unit); - cstate->clientstate = CHAPCS_CLOSED; - cstate->serverstate = CHAPSS_CLOSED; + /* Timeout(s) pending? Cancel if so. */ + if (cstate->serverstate == CHAPSS_INITIAL_CHAL || + cstate->serverstate == CHAPSS_RECHALLENGE) + UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate); + else if (cstate->serverstate == CHAPSS_OPEN + && cstate->chal_interval != 0) + UNTIMEOUT(ChapRechallenge, (caddr_t) cstate); + if (cstate->clientstate == CHAPCS_RESPONSE) + UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate); + + cstate->clientstate = CHAPCS_INITIAL; + cstate->serverstate = CHAPSS_INITIAL; } @@ -208,13 +251,18 @@ int unit; * ChapProtocolReject - Peer doesn't grok CHAP. */ void - ChapProtocolReject(unit) -int unit; +ChapProtocolReject(unit) + int unit; { - ChapLowerDown(unit); /* shutdown chap */ - - -/* Note: should we bail here if chap is required? */ + chap_state *cstate = &chap[unit]; + + if (cstate->serverstate != CHAPSS_INITIAL && + cstate->serverstate != CHAPSS_CLOSED) + auth_peer_fail(unit, CHAP); + if (cstate->clientstate != CHAPCS_INITIAL && + cstate->clientstate != CHAPCS_CLOSED) + auth_withpeer_fail(unit, CHAP); + ChapLowerDown(unit); /* shutdown chap */ } @@ -222,311 +270,335 @@ int unit; * ChapInput - Input CHAP packet. */ void - ChapInput(unit, inpacket, packet_len) -int unit; -u_char *inpacket; -int packet_len; +ChapInput(unit, inpacket, packet_len) + int unit; + u_char *inpacket; + int packet_len; { - chap_state *cstate = &chap[unit]; - u_char *inp; - u_char code, id; - int len; + chap_state *cstate = &chap[unit]; + u_char *inp; + u_char code, id; + int len; - /* - * Parse header (code, id and length). - * If packet too short, drop it. - */ - inp = inpacket; - if (packet_len < CHAP_HEADERLEN) { - CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.")) - return; - } - GETCHAR(code, inp); - GETCHAR(id, inp); - GETSHORT(len, inp); - if (len < CHAP_HEADERLEN) { - CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.")) - return; - } - if (len > packet_len) { - CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.")) - return; - } - len -= CHAP_HEADERLEN; + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (packet_len < CHAP_HEADERLEN) { + CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < CHAP_HEADERLEN) { + CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.")); + return; + } + if (len > packet_len) { + CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.")); + return; + } + len -= CHAP_HEADERLEN; - /* - * Action depends on code. - */ - switch (code) { - case CHAP_CHALLENGE: - ChapReceiveChallenge(cstate, inp, id, len); - break; + /* + * Action depends on code (as in fact it usually does :-). + */ + switch (code) { + case CHAP_CHALLENGE: + ChapReceiveChallenge(cstate, inp, id, len); + break; - case CHAP_RESPONSE: - ChapReceiveResponse(cstate, inp, id, len); - break; + case CHAP_RESPONSE: + ChapReceiveResponse(cstate, inp, id, len); + break; - case CHAP_FAILURE: - ChapReceiveFailure(cstate, inp, id, len); - break; - - case CHAP_SUCCESS: - ChapReceiveSuccess(cstate, inp, id, len); - break; - - default: /* Need code reject? */ - syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code); - break; - } -} - + case CHAP_FAILURE: + ChapReceiveFailure(cstate, inp, id, len); + break; -/* - * ChapReceiveChallenge - Receive Challenge. - */ -static void - ChapReceiveChallenge(cstate, inp, id, len) -chap_state *cstate; -u_char *inp; -int id; -int len; -{ - u_char rchallenge_len; - u_char *rchallenge; - u_char secret[MAX_SECRET_LEN]; - int secret_len; - u_char rhostname[256]; - u_char buf[256]; - MD5_CTX mdContext; - - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id)) - if (cstate->serverstate != CHAPSS_LISTEN) { - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received challenge but not in listen state")) - return; - } - - if (len < 2) { - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")) - return; - } - GETCHAR(rchallenge_len, inp); - len -= sizeof (u_char) + rchallenge_len ; - if (len < 0) { - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")) - return; - } - rchallenge = inp; - INCPTR(rchallenge_len, inp); - - BCOPY(inp, rhostname, len); - rhostname[len] = '\000'; - - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s", - rhostname)) - GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */ - - BCOPY(rchallenge, buf, rchallenge_len); /* copy challenge into buffer */ - BCOPY(secret, buf + rchallenge_len, secret_len); /* append secret */ - - /* generate MD based on negotiated type */ - - switch (lcp_hisoptions[cstate->unit].chap_mdtype) { - - case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ - MD5Init(&mdContext); - MD5Update(&mdContext, buf, rchallenge_len + secret_len); - MD5Final(&mdContext); - ChapSendResponse(cstate, id, &mdContext.digest[0], MD5_SIGNATURE_SIZE); - break; - - default: - CHAPDEBUG((LOG_INFO, "unknown digest type %d", - lcp_hisoptions[cstate->unit].chap_mdtype)) - } + case CHAP_SUCCESS: + ChapReceiveSuccess(cstate, inp, id, len); + break; + default: /* Need code reject? */ + syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code); + break; + } } /* - * ChapReceiveResponse - Receive and process response. + * ChapReceiveChallenge - Receive Challenge and send Response. */ static void - ChapReceiveResponse(cstate, inp, id, len) -chap_state *cstate; -u_char *inp; -int id; -int len; +ChapReceiveChallenge(cstate, inp, id, len) + chap_state *cstate; + u_char *inp; + int id; + int len; { - u_char *remmd, remmd_len; - u_char secret[MAX_SECRET_LEN]; - int secret_len; - u_char chal_len = cstate->chal_len; - u_char code; - u_char rhostname[256]; - u_char buf[256]; - MD5_CTX mdContext; - u_char msg[256], msglen; - - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id)) - -/* sanity check */ - if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) { - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received response but did not send a challenge")) - return; - } - - if (len < 2) { - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")) - return; - } - GETCHAR(remmd_len, inp); /* get length of MD */ - len -= sizeof (u_char) + remmd_len ; + int rchallenge_len; + u_char *rchallenge; + int secret_len; + char secret[MAXSECRETLEN]; + char rhostname[256]; + MD5_CTX mdContext; + + CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id)); + if (cstate->clientstate == CHAPCS_CLOSED || + cstate->clientstate == CHAPCS_PENDING) { + CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d", + cstate->clientstate)); + return; + } + + if (len < 2) { + CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")); + return; + } - if (len < 0) { - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")) - return; - } + GETCHAR(rchallenge_len, inp); + len -= sizeof (u_char) + rchallenge_len; /* now name field length */ + if (len < 0) { + CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")); + return; + } + rchallenge = inp; + INCPTR(rchallenge_len, inp); + + if (len >= sizeof(rhostname)) + len = sizeof(rhostname) - 1; + BCOPY(inp, rhostname, len); + rhostname[len] = '\000'; + + CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s", + rhostname)); + + /* get secret for authenticating ourselves with the specified host */ + if (!get_secret(cstate->unit, cstate->resp_name, rhostname, + secret, &secret_len, 0)) { + secret_len = 0; /* assume null secret if can't find one */ + syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s", + rhostname); + } - remmd = inp; /* get pointer to MD */ - INCPTR(remmd_len, inp); + /* cancel response send timeout if necessary */ + if (cstate->clientstate == CHAPCS_RESPONSE) + UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate); - BCOPY(inp, rhostname, len); - rhostname[len] = '\000'; + cstate->resp_id = id; + cstate->resp_transmits = 0; - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s", - rhostname)) + /* generate MD based on negotiated type */ + switch (cstate->resp_type) { - GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */ + case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ + MD5Init(&mdContext); + MD5Update(&mdContext, &cstate->resp_id, 1); + MD5Update(&mdContext, secret, secret_len); + MD5Update(&mdContext, rchallenge, rchallenge_len); + MD5Final(&mdContext); + BCOPY(mdContext.digest, cstate->response, MD5_SIGNATURE_SIZE); + cstate->resp_length = MD5_SIGNATURE_SIZE; + break; - BCOPY(cstate->chal_str, buf, chal_len); /* copy challenge */ - /* into buffer */ - BCOPY(secret, buf + chal_len, secret_len); /* append secret */ + default: + CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type)); + return; + } - /* generate MD based on negotiated type */ + ChapSendResponse(cstate); +} - switch (lcp_gotoptions[cstate->unit].chap_mdtype) { - case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ - MD5Init(&mdContext); - MD5Update(&mdContext, buf, chal_len + secret_len); - MD5Final(&mdContext); +/* + * ChapReceiveResponse - Receive and process response. + */ +static void +ChapReceiveResponse(cstate, inp, id, len) + chap_state *cstate; + u_char *inp; + int id; + int len; +{ + u_char *remmd, remmd_len; + int secret_len, old_state; + int code; + char rhostname[256]; + u_char buf[256]; + MD5_CTX mdContext; + u_char msg[256]; + char secret[MAXSECRETLEN]; + + CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id)); + + if (cstate->serverstate == CHAPSS_CLOSED || + cstate->serverstate == CHAPSS_PENDING) { + CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d", + cstate->serverstate)); + return; + } - /* compare local and remote MDs and send the appropriate status */ + if (id != cstate->chal_id) + return; /* doesn't match ID of last challenge */ + + /* + * If we have received a duplicate or bogus Response, + * we have to send the same answer (Success/Failure) + * as we did for the first Response we saw. + */ + if (cstate->serverstate == CHAPSS_OPEN) { + ChapSendStatus(cstate, CHAP_SUCCESS); + return; + } + if (cstate->serverstate == CHAPSS_BADAUTH) { + ChapSendStatus(cstate, CHAP_FAILURE); + return; + } - if (bcmp (&mdContext.digest[0], remmd, MD5_SIGNATURE_SIZE)) - code = CHAP_FAILURE; /* they ain't the same */ - else - code = CHAP_SUCCESS; /* they are the same! */ - break; + if (len < 2) { + CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")); + return; + } + GETCHAR(remmd_len, inp); /* get length of MD */ + remmd = inp; /* get pointer to MD */ + INCPTR(remmd_len, inp); + + len -= sizeof (u_char) + remmd_len; + if (len < 0) { + CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")); + return; + } - default: - CHAPDEBUG((LOG_INFO, "unknown digest type %d", - lcp_gotoptions[cstate->unit].chap_mdtype)) + UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate); + + if (len >= sizeof(rhostname)) + len = sizeof(rhostname) - 1; + BCOPY(inp, rhostname, len); + rhostname[len] = '\000'; + + CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s", + rhostname)); + + /* + * Get secret for authenticating them with us, + * do the hash ourselves, and compare the result. + */ + code = CHAP_FAILURE; + if (!get_secret(cstate->unit, rhostname, cstate->chal_name, + secret, &secret_len, 1)) { + syslog(LOG_WARNING, "No CHAP secret found for authenticating %s", + 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(&mdContext); + + /* compare local and remote MDs and send the appropriate status */ + if (bcmp (mdContext.digest, remmd, MD5_SIGNATURE_SIZE) == 0) + code = CHAP_SUCCESS; /* they are the same! */ + break; + + default: + CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type)); + } } - if (code == CHAP_SUCCESS) - sprintf((char *)msg, "Welcome to %s.", hostname); - else - sprintf((char *)msg, "I don't like you. Go 'way."); - msglen = strlen(msg); - ChapSendStatus(cstate, code, id, msg, msglen); - - /* only crank up IPCP when either we aren't doing PAP, or if we are, */ - /* that it is in open state */ + + ChapSendStatus(cstate, code); if (code == CHAP_SUCCESS) { - cstate->serverstate = CHAPSS_OPEN; - if (!lcp_hisoptions[cstate->unit].neg_upap || - (lcp_hisoptions[cstate->unit].neg_upap && - upap[cstate->unit].us_serverstate == UPAPSS_OPEN )) - ipcp_activeopen(cstate->unit); /* Start IPCP */ + old_state = cstate->serverstate; + cstate->serverstate = CHAPSS_OPEN; + if (old_state == CHAPSS_INITIAL_CHAL) { + auth_peer_success(cstate->unit, CHAP); + } + if (cstate->chal_interval != 0) + TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval); + + } else { + syslog(LOG_ERR, "CHAP peer authentication failed"); + cstate->serverstate = CHAPSS_BADAUTH; + auth_peer_fail(cstate->unit, CHAP); } } + /* * ChapReceiveSuccess - Receive Success */ -/* ARGSUSED */ static void - ChapReceiveSuccess(cstate, inp, id, len) -chap_state *cstate; -u_char *inp; -u_char id; -int len; +ChapReceiveSuccess(cstate, inp, id, len) + chap_state *cstate; + u_char *inp; + u_char id; + int len; { - u_char msglen; - u_char *msg; - - CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id)) - - if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) { - CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: received success, but did not send a challenge.")) - return; - } - - /* - * Parse message. - */ - if (len < sizeof (u_char)) { - CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet.")) - return; - } - GETCHAR(msglen, inp); - len -= sizeof (u_char); - if (len < msglen) { - CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet.")) - return; - } - msg = inp; - PRINTMSG(msg, msglen); - - cstate->clientstate = CHAPCS_OPEN; - /* only crank up IPCP when either we aren't doing PAP, or if we are, */ - /* that it is in open state */ + CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id)); + + if (cstate->clientstate == CHAPCS_OPEN) + /* presumably an answer to a duplicate response */ + return; + + if (cstate->clientstate != CHAPCS_RESPONSE) { + /* don't know what this is */ + CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", + cstate->clientstate)); + return; + } - if (!lcp_gotoptions[cstate->unit].neg_chap || - (lcp_gotoptions[cstate->unit].neg_chap && - upap[cstate->unit].us_serverstate == UPAPCS_OPEN )) - ipcp_activeopen(cstate->unit); /* Start IPCP */ + /* + * Print message. + */ + if (len > 0) + PRINTMSG(inp, len); + + cstate->clientstate = CHAPCS_OPEN; + + auth_withpeer_success(cstate->unit, CHAP); } /* * ChapReceiveFailure - Receive failure. */ -/* ARGSUSED */ static void - ChapReceiveFailure(cstate, inp, id, len) -chap_state *cstate; -u_char *inp; -u_char id; -int len; +ChapReceiveFailure(cstate, inp, id, len) + chap_state *cstate; + u_char *inp; + u_char id; + int len; { - u_char msglen; - u_char *msg; + u_char msglen; + u_char *msg; - CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id)) - if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) /* XXX */ - return; - - /* - * Parse message. - */ - if (len < sizeof (u_char)) { - CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet.")) - return; - } - GETCHAR(msglen, inp); - len -= sizeof (u_char); - if (len < msglen) { - CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet.")) - return; - } - msg = inp; - PRINTMSG(msg, msglen); - - cstate->flags &= ~CHAPF_UPVALID; /* Clear valid flag */ - cstate->clientstate = CHAPCS_CLOSED; /* Pretend for a moment */ - ChapAuthWithPeer(cstate->unit); /* Restart */ + CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id)); + + if (cstate->clientstate != CHAPCS_RESPONSE) { + /* don't know what this is */ + CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", + cstate->clientstate)); + return; + } + + /* + * Print message. + */ + if (len > 0) + PRINTMSG(inp, len); + + syslog(LOG_ERR, "CHAP authentication failed"); + auth_withpeer_fail(cstate->unit, CHAP); } @@ -534,43 +606,36 @@ int len; * ChapSendChallenge - Send an Authenticate challenge. */ static void - ChapSendChallenge(cstate) -chap_state *cstate; +ChapSendChallenge(cstate) + chap_state *cstate; { - u_char *outp; - u_char chal_len; - int outlen; - -/* pick a random challenge length between MIN_CHALLENGE_LENGTH and - MAX_CHALLENGE_LENGTH */ - cstate->chal_len = (unsigned) ((drand48() * - (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) + - MIN_CHALLENGE_LENGTH); - chal_len = cstate->chal_len; - - outlen = CHAP_HEADERLEN + 2 * sizeof (u_char) + chal_len + hostname_len; - outp = outpacket_buf; + u_char *outp; + int chal_len, name_len; + int outlen; - MAKEHEADER(outp, CHAP); /* paste in a CHAP header */ - - PUTCHAR(CHAP_CHALLENGE, outp); - PUTCHAR(++cstate->id, outp); - PUTSHORT(outlen, outp); + chal_len = cstate->chal_len; + name_len = strlen(cstate->chal_name); + outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; + outp = outpacket_buf; - PUTCHAR(chal_len, outp); /* put length of challenge */ + MAKEHEADER(outp, CHAP); /* paste in a CHAP header */ - ChapGenChallenge(chal_len, cstate->chal_str); /* generate a challenge string */ + PUTCHAR(CHAP_CHALLENGE, outp); + PUTCHAR(cstate->chal_id, outp); + PUTSHORT(outlen, outp); - BCOPY(cstate->chal_str, outp, chal_len); /* copy it the the output buffer */ - INCPTR(chal_len, outp); + PUTCHAR(chal_len, outp); /* put length of challenge */ + BCOPY(cstate->challenge, outp, chal_len); + INCPTR(chal_len, outp); - BCOPY(hostname, outp, hostname_len); /* append hostname */ - INCPTR(hostname_len, outp); + BCOPY(cstate->chal_name, outp, name_len); /* append hostname */ - output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); + output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); - CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->id)) - cstate->clientstate |= CHAPCS_CHALLENGE_SENT; + CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id)); + + TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime); + ++cstate->chal_transmits; } @@ -578,88 +643,99 @@ chap_state *cstate; * ChapSendStatus - Send a status response (ack or nak). */ static void - ChapSendStatus(cstate, code, id, msg, msglen) -chap_state *cstate; -u_char code, id; -u_char *msg; -int msglen; +ChapSendStatus(cstate, code) + chap_state *cstate; + int code; { - u_char *outp; - int outlen; - - outlen = CHAP_HEADERLEN + msglen; - outp = outpacket_buf; + u_char *outp; + int outlen, msglen; + char msg[256]; - MAKEHEADER(outp, CHAP); /* paste in a header */ + if (code == CHAP_SUCCESS) + sprintf(msg, "Welcome to %s.", hostname); + else + sprintf(msg, "I don't like you. Go 'way."); + msglen = strlen(msg); + + outlen = CHAP_HEADERLEN + msglen; + outp = outpacket_buf; + + MAKEHEADER(outp, CHAP); /* paste in a header */ - PUTCHAR(code, outp); - PUTCHAR(id, outp); - PUTSHORT(outlen, outp); - BCOPY(msg, outp, msglen); - output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); + PUTCHAR(code, outp); + PUTCHAR(cstate->chal_id, outp); + PUTSHORT(outlen, outp); + BCOPY(msg, outp, msglen); + output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); - CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, id)) + CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, + cstate->chal_id)); } /* * ChapGenChallenge is used to generate a pseudo-random challenge string of - * a pseudo-random length between min_len and max_len and return the - * challenge string, and the message digest of the secret appended to - * the challenge string. the message digest type is specified by mdtype. - * - * It returns with the string in the caller-supplied buffer str (which - * should be instantiated with a length of max_len + 1), and the - * length of the generated string into chal_len. - * + * 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 - ChapGenChallenge(chal_len, str) -u_char chal_len; -u_char * str; +ChapGenChallenge(cstate) + chap_state *cstate; { - u_char * ptr = str; - unsigned int i; - - /* generate a random string */ - - for (i = 0; i < chal_len; i++ ) - *ptr++ = (char) (drand48() * 0xff); - - *ptr = 0; /* null terminate it so we can printf it */ + int chal_len; + u_char *ptr = cstate->challenge; + unsigned int i; + + /* 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_len = chal_len; + cstate->chal_id = ++cstate->id; + cstate->chal_transmits = 0; + + /* generate a random string */ + for (i = 0; i < chal_len; i++ ) + *ptr++ = (char) (drand48() * 0xff); } + /* - * ChapSendResponse - send a response packet with the message - * digest specified by md and md_len + * ChapSendResponse - send a response packet with values as specified + * in *cstate. */ /* ARGSUSED */ static void - ChapSendResponse(cstate, id, md, md_len) -chap_state *cstate; -u_char id; -u_char *md; -int md_len; +ChapSendResponse(cstate) + chap_state *cstate; { u_char *outp; - int outlen; + int outlen, md_len, name_len; - outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + hostname_len; + md_len = cstate->resp_length; + name_len = strlen(cstate->resp_name); + outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; outp = outpacket_buf; - MAKEHEADER(outp, CHAP); - PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ - PUTCHAR(id, outp); /* copy id from challenge packet */ - PUTSHORT(outlen, outp); /* packet length */ + MAKEHEADER(outp, CHAP); - PUTCHAR(md_len, outp); /* length of MD */ + PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ + PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */ + PUTSHORT(outlen, outp); /* packet length */ - BCOPY(md, outp, md_len); /* copy MD to buffer */ + PUTCHAR(md_len, outp); /* length of MD */ + BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */ INCPTR(md_len, outp); - BCOPY(hostname, outp, hostname_len); /* append hostname */ - INCPTR(hostname_len, outp); + BCOPY(cstate->resp_name, outp, name_len); /* append our name */ + + /* send the packet */ + output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); - output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); /* bomb's away! */ + cstate->clientstate = CHAPCS_RESPONSE; + TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime); + ++cstate->resp_transmits; } #ifdef NO_DRAND48 |