Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

230 lines
5.4 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corp. All rights reserved.
//
// SYNOPSIS
//
// Defines the class EAPFSM.
//
///////////////////////////////////////////////////////////////////////////////
#include "ias.h"
#include "iasutil.h"
#include "eapfsm.h"
EAPType* EAPFSM::onBegin() throw ()
{
return types.front();
}
void EAPFSM::onDllEvent(
PPP_EAP_ACTION action,
const PPP_EAP_PACKET& sendPkt
) throw ()
{
switch (action)
{
case EAPACTION_NoAction:
{
lastSendCode = 0;
break;
}
case EAPACTION_Done:
case EAPACTION_SendAndDone:
{
state = STATE_DONE;
break;
}
case EAPACTION_Send:
case EAPACTION_SendWithTimeout:
case EAPACTION_SendWithTimeoutInteractive:
{
lastSendCode = sendPkt.Code;
lastSendId = sendPkt.Id;
break;
}
}
}
EAPFSM::Action EAPFSM::onReceiveEvent(
const PPP_EAP_PACKET& recvPkt,
EAPType*& newType
) throw ()
{
// Default is to discard.
Action action = DISCARD;
// And type doesn't change.
newType = 0;
switch (state)
{
case STATE_INITIAL:
{
// In the initial state we only accept Response/Identity.
if ((recvPkt.Code == EAPCODE_Response) && (recvPkt.Data[0] == 1))
{
action = MAKE_MESSAGE;
state = STATE_NEGOTIATING;
}
break;
}
case STATE_NEGOTIATING:
{
if (isRepeat(recvPkt))
{
action = REPLAY_LAST;
break;
}
if (!isExpected(recvPkt))
{
action = DISCARD;
break;
}
// In the negotiating state, NAK's are allowed.
if (recvPkt.Data[0] == 3)
{
// Did the client propose a type?
BYTE proposal =
(IASExtractWORD(recvPkt.Length) > 5) ? recvPkt.Data[1] : 0;
// Select a new type.
action = selectNewType(proposal, newType);
}
else if (recvPkt.Data[0] == eapType)
{
// Once the client agrees to our type; he's locked in.
action = MAKE_MESSAGE;
state = STATE_ACTIVE;
}
else
{
action = FAIL_NEGOTIATE;
state = STATE_DONE;
}
break;
}
case STATE_ACTIVE:
{
if (recvPkt.Code == EAPCODE_Request)
{
action = MAKE_MESSAGE;
}
else if (recvPkt.Data[0] == 3)
{
action = DISCARD;
}
else if (isRepeat(recvPkt))
{
action = REPLAY_LAST;
}
else if (isExpected(recvPkt))
{
action = MAKE_MESSAGE;
}
break;
}
case STATE_DONE:
{
// The session is over, so all we do is replay repeats.
if (isRepeat(recvPkt))
{
action = REPLAY_LAST;
}
}
}
// If the packet made it through our filters, then we count it as the
// last received.
if (action == MAKE_MESSAGE)
{
lastRecvCode = recvPkt.Code;
lastRecvId = recvPkt.Id;
lastRecvType = recvPkt.Data[0];
}
return action;
}
inline BOOL EAPFSM::isExpected(const PPP_EAP_PACKET& recvPkt) const throw ()
{
return (lastSendCode == EAPCODE_Request) &&
(recvPkt.Code == EAPCODE_Response) &&
(recvPkt.Id == lastSendId);
}
inline BOOL EAPFSM::isRepeat(const PPP_EAP_PACKET& recvPkt) const throw ()
{
return (recvPkt.Code == lastRecvCode) &&
(recvPkt.Id == lastRecvId) &&
(recvPkt.Data[0] == lastRecvType);
}
EAPFSM::Action EAPFSM::selectNewType(
BYTE proposal,
EAPType*& newType
) throw ()
{
// The peer NAK'd our previous offer, so he's not allowed to use it
// again.
types.erase(types.begin());
if (proposal != 0)
{
IASTracePrintf("EAP NAK; proposed type = %hd", proposal);
// Find the proposed type in the list of allowed types.
for (std::vector<EAPType*>::iterator i = types.begin();
i != types.end();
++i)
{
if ((*i)->dwEapTypeId == proposal)
{
IASTraceString("Accepting proposed type.");
// change the current type
newType = *i;
eapType = newType->dwEapTypeId;
// change the state to active: any NAK received now will fail
state = STATE_ACTIVE;
return MAKE_MESSAGE;
}
}
}
else
{
IASTraceString("EAP NAK; no type proposed");
}
// If the server list is empty, then nothing else can be negotiated.
if (types.empty())
{
IASTraceString("EAP negotiation failed; no types remaining.");
state = STATE_DONE;
return FAIL_NEGOTIATE;
}
// negotiate the next one from the server's list
newType = types.front();
eapType = newType->dwEapTypeId;
IASTracePrintf("EAP authenticator offering type %hd", eapType);
return MAKE_MESSAGE;
}