2772 lines
82 KiB
C
2772 lines
82 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1999, Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
elprotocol.c
|
||
|
|
||
|
Abstract:
|
||
|
This module implements functions related to EAPOL
|
||
|
protocol
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
sachins, Apr 30 2000, Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "pcheapol.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#define EAPOL_SERVICE
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
HRESULT
|
||
|
EAPOLMANAuthenticationStarted (
|
||
|
REFGUID InterfaceId
|
||
|
);
|
||
|
|
||
|
HRESULT
|
||
|
EAPOLMANAuthenticationSucceeded (
|
||
|
REFGUID InterfaceId
|
||
|
);
|
||
|
|
||
|
HRESULT
|
||
|
EAPOLMANAuthenticationFailed (
|
||
|
REFGUID InterfaceId,
|
||
|
DWORD dwType
|
||
|
);
|
||
|
|
||
|
HRESULT EAPOLMANNotification(
|
||
|
REFGUID InterfaceId,
|
||
|
LPWSTR szwNotificationMessage,
|
||
|
DWORD dwType
|
||
|
);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// ElProcessReceivedPacket
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called to process data received from the NDISUIO driver.
|
||
|
// The EAPOL packet is extracted and further processing is done.
|
||
|
//
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pvContext - Context buffer which is a pointer to EAPOL_BUFFER structure
|
||
|
//
|
||
|
// Return Values:
|
||
|
//
|
||
|
|
||
|
VOID
|
||
|
ElProcessReceivedPacket (
|
||
|
IN PVOID pvContext
|
||
|
)
|
||
|
{
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
EAPOL_BUFFER *pEapolBuffer = NULL;
|
||
|
DWORD dwLength = 0;
|
||
|
ETH_HEADER *pEthHdr = NULL;
|
||
|
EAPOL_PACKET *pEapolPkt = NULL;
|
||
|
EAPOL_PACKET_D8 *pEapolPktD8 = NULL;
|
||
|
BOOLEAN fRemoteEnd8021XD8 = FALSE;
|
||
|
PPP_EAP_PACKET *pEapPkt = NULL;
|
||
|
BYTE *pBuffer;
|
||
|
BOOLEAN ReqId = FALSE; // EAPOL state machine local variables
|
||
|
BOOLEAN ReqAuth = FALSE;
|
||
|
BOOLEAN EapSuccess = FALSE;
|
||
|
BOOLEAN EapFail = FALSE;
|
||
|
BOOLEAN RxKey = FALSE;
|
||
|
GUID DeviceGuid;
|
||
|
EAPOL_PACKET_D8_D7 DummyHeader;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
|
||
|
if (pvContext == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: Critical error, Context is NULL");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pEapolBuffer = (EAPOL_BUFFER *)pvContext;
|
||
|
pPCB = (EAPOL_PCB *)pEapolBuffer->pvContext;
|
||
|
dwLength = pEapolBuffer->dwBytesTransferred;
|
||
|
pBuffer = (BYTE *)pEapolBuffer->pBuffer;
|
||
|
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket entered, length = %ld", dwLength);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// The Port was verified to be active before the workitem
|
||
|
// was queued. But do a double-check
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Port %s not active",
|
||
|
pPCB->pszDeviceGUID);
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
FREE (pEapolBuffer);
|
||
|
break;
|
||
|
}
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
// Validate packet length
|
||
|
// Should be atleast ETH_HEADER and first 4 required bytes of
|
||
|
// EAPOL_PACKET
|
||
|
if (dwLength < (sizeof(ETH_HEADER) + 4))
|
||
|
{
|
||
|
TRACE2 (EAPOL, "ProcessReceivedPacket: Packet length %ld is less than minimum required %d. Ignoring packet",
|
||
|
dwLength, (sizeof(ETH_HEADER) + 4));
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Validate Destination MAC Address
|
||
|
// Compare with MAC address got during MEDIA_CONNECT
|
||
|
|
||
|
#if 0
|
||
|
pEthHdr = (ETH_HEADER *)pBuffer;
|
||
|
if ((memcmp ((BYTE *)pEthHdr->bSrcAddr,
|
||
|
(BYTE *)pPCB->bDestMacAddr,
|
||
|
SIZE_MAC_ADDR)) != 0)
|
||
|
{
|
||
|
TRACE2 (EAPOL, "ProcessReceivedPacket: Dest MAC address %s does not match PAE address %s. Ignoring packet",
|
||
|
pEthHdr->SrcAddr,
|
||
|
pPCB->bDestMacAddr);
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_ADDRESS;
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Verify if the packet contains a 802.1P tag. If so, skip the 4 bytes
|
||
|
// after the src+dest mac addresses
|
||
|
|
||
|
if ((WireToHostFormat16(pBuffer + sizeof(ETH_HEADER)) == EAPOL_8021P_TAG_TYPE))
|
||
|
{
|
||
|
pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER) + 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER));
|
||
|
}
|
||
|
|
||
|
// Validate Ethernet type in the incoming packet
|
||
|
// It should be the same as the one defined for the
|
||
|
// current port
|
||
|
|
||
|
if (memcmp ((BYTE *)pEapolPkt->EthernetType, (BYTE *)pPCB->bEtherType,
|
||
|
SIZE_ETHERNET_TYPE) != 0)
|
||
|
{
|
||
|
TRACE2 (EAPOL, "ProcessReceivedPacket: Packet PAE type %s does not match expected type %s. Ignoring packet",
|
||
|
pEapolPkt->EthernetType,
|
||
|
pPCB->bEtherType);
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// EAPOL packet type should be valid
|
||
|
if ((pEapolPkt->PacketType != EAP_Packet) &&
|
||
|
(pEapolPkt->PacketType != EAPOL_Start) &&
|
||
|
(pEapolPkt->PacketType != EAPOL_Logoff) &&
|
||
|
(pEapolPkt->PacketType != EAPOL_Key))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid EAPOL packet type %d. Ignoring packet",
|
||
|
pEapolPkt->PacketType);
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_PACKET;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Determine the value of local EAPOL state variables
|
||
|
if (pEapolPkt->PacketType == EAP_Packet)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: EAP_Packet");
|
||
|
// Validate length of packet for EAP
|
||
|
// Should be atleast (ETH_HEADER+EAPOL_PACKET)
|
||
|
if (dwLength < (sizeof (ETH_HEADER) + sizeof (EAPOL_PACKET)))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP packet %d. Ignoring packet",
|
||
|
dwLength);
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Determine if the packet is draft 8 or not
|
||
|
|
||
|
pEapolPktD8 = (EAPOL_PACKET_D8 *)pEapolPkt;
|
||
|
|
||
|
pEapPkt = (PPP_EAP_PACKET *)pEapolPktD8->PacketBody;
|
||
|
|
||
|
|
||
|
switch (WireToHostFormat16(pEapolPktD8->AuthResultCode))
|
||
|
{
|
||
|
case AUTH_Continuing:
|
||
|
if (pEapPkt->Code == EAPCODE_Request)
|
||
|
{
|
||
|
fRemoteEnd8021XD8 = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AUTH_Authorized:
|
||
|
if (pEapPkt->Code == EAPCODE_Success)
|
||
|
|
||
|
{
|
||
|
fRemoteEnd8021XD8 = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AUTH_Unauthorized:
|
||
|
if ((pEapPkt->Code == EAPCODE_Failure) ||
|
||
|
(pEapPkt->Code == EAPCODE_Success))
|
||
|
{
|
||
|
fRemoteEnd8021XD8 = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (fRemoteEnd8021XD8 && (WireToHostFormat16(pEapolPktD8->PacketBodyLength) != 0))
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: Packet received DRAFT 8 format");
|
||
|
pPCB->fRemoteEnd8021XD8 = TRUE;
|
||
|
|
||
|
memcpy (DummyHeader.AuthResultCode, pEapolPktD8->AuthResultCode,
|
||
|
2);
|
||
|
memcpy (DummyHeader.EthernetType, pEapolPktD8->EthernetType,
|
||
|
2);
|
||
|
DummyHeader.ProtocolVersion = pEapolPktD8->ProtocolVersion;
|
||
|
DummyHeader.PacketType = pEapolPktD8->PacketType;
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPktD8, (BYTE *)&DummyHeader, 6);
|
||
|
|
||
|
pEapolPkt = (EAPOL_PACKET *)((BYTE *)pEapolPktD8 + 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB->fRemoteEnd8021XD8 = FALSE;
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: Packet received PRE-DRAFT 8 format");
|
||
|
}
|
||
|
|
||
|
pEapPkt = (PPP_EAP_PACKET *)pEapolPkt->PacketBody;
|
||
|
|
||
|
if (pEapPkt->Code == EAPCODE_Request)
|
||
|
{
|
||
|
// Validate length of packet for EAP-Request packet
|
||
|
// Should be atleast (ETH_HEADER+EAPOL_PACKET-1+PPP_EAP_PACKET)
|
||
|
if (dwLength < (sizeof (ETH_HEADER) + sizeof(EAPOL_PACKET)-1
|
||
|
+ sizeof (PPP_EAP_PACKET)))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP Request packet %d. Ignoring packet",
|
||
|
dwLength);
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
|
||
|
break;
|
||
|
}
|
||
|
if (pEapPkt->Data[0] == EAPTYPE_Identity)
|
||
|
{
|
||
|
pPCB->fIsRemoteEndEAPOLAware = TRUE;
|
||
|
ReqId = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ReqAuth = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else if (pEapPkt->Code == EAPCODE_Success)
|
||
|
{
|
||
|
EapSuccess = TRUE;
|
||
|
}
|
||
|
else if (pEapPkt->Code == EAPCODE_Failure)
|
||
|
{
|
||
|
EapFail = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Invalid type
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid EAP packet type %d. Ignoring packet",
|
||
|
pEapPkt->Code);
|
||
|
FREE (pEapolBuffer);
|
||
|
dwRetCode = ERROR_INVALID_PACKET;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: != EAP_Packet");
|
||
|
if (pEapolPkt->PacketType == EAPOL_Key)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: == EAPOL_Key");
|
||
|
RxKey = TRUE;
|
||
|
|
||
|
// Determine if the packet is draft 8 or not
|
||
|
|
||
|
pEapolPktD8 = (EAPOL_PACKET_D8 *)pEapolPkt;
|
||
|
|
||
|
// In pre-draft 8, PacketBodyLength cannot be '0'
|
||
|
// If it is zero, it is draft 8 packet format
|
||
|
|
||
|
if (WireToHostFormat16(pEapolPktD8->AuthResultCode)
|
||
|
== AUTH_Continuing)
|
||
|
{
|
||
|
pPCB->fRemoteEnd8021XD8 = TRUE;
|
||
|
|
||
|
memcpy (DummyHeader.AuthResultCode,
|
||
|
pEapolPktD8->AuthResultCode,
|
||
|
2);
|
||
|
|
||
|
memcpy (DummyHeader.EthernetType,
|
||
|
pEapolPktD8->EthernetType,
|
||
|
2);
|
||
|
|
||
|
DummyHeader.ProtocolVersion = pEapolPktD8->ProtocolVersion;
|
||
|
DummyHeader.PacketType = pEapolPktD8->PacketType;
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPktD8, (BYTE *)&DummyHeader, 6);
|
||
|
|
||
|
pEapolPkt = (EAPOL_PACKET *)((BYTE *)pEapolPktD8 + 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB->fRemoteEnd8021XD8 = FALSE;
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOL_Key Packet received PRE-DRAFT 8 format");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NOTE:
|
||
|
// Should we check values of EAP type
|
||
|
//
|
||
|
|
||
|
// Checking value of PCB fields now
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
switch (pPCB->State)
|
||
|
{
|
||
|
// ReqId, ReqAuth, EapSuccess, EapFail, RxKey are inherently
|
||
|
// mutually exclusive
|
||
|
// No checks will be made to verify this
|
||
|
// Also, assumption is being made that in any state, maximum
|
||
|
// one timer may be active on the port.
|
||
|
|
||
|
case EAPOLSTATE_LOGOFF:
|
||
|
// Only a User Logon event can get the port out of
|
||
|
// LOGOFF state
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: LOGOFF state, Ignoing packet");
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_DISCONNECTED:
|
||
|
// Only a Media Connect event can get the port out of
|
||
|
// DISCONNECTED state
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: DISCONNECTED state, Ignoing packet");
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_CONNECTING:
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_CONNECTING");
|
||
|
if (ReqId | EapSuccess | EapFail)
|
||
|
{
|
||
|
// Deactivate current timer
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (EapSuccess)
|
||
|
{
|
||
|
if ((dwRetCode = ElProcessEapSuccess (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (EapFail)
|
||
|
{
|
||
|
if ((dwRetCode = ElProcessEapFail (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (ReqId)
|
||
|
{
|
||
|
if ((dwRetCode = FSMAcquired (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_ACQUIRED:
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_ACQUIRED");
|
||
|
if (ReqId | ReqAuth | EapSuccess | EapFail)
|
||
|
{
|
||
|
// Deactivate current timer
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (EapSuccess)
|
||
|
{
|
||
|
if ((dwRetCode = ElProcessEapSuccess (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (EapFail)
|
||
|
{
|
||
|
if ((dwRetCode = ElProcessEapFail (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (ReqId)
|
||
|
{
|
||
|
if ((dwRetCode = FSMAcquired (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (ReqAuth)
|
||
|
{
|
||
|
if ((dwRetCode = FSMAuthenticating (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_AUTHENTICATING:
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_AUTHENTICATING");
|
||
|
// Common timer deletion
|
||
|
if (ReqAuth | ReqId | EapSuccess | EapFail)
|
||
|
{
|
||
|
// Deactivate current timer
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (ReqId)
|
||
|
{
|
||
|
if ((dwRetCode = FSMAcquired (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ((dwRetCode = FSMAuthenticating (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Continue further processing
|
||
|
|
||
|
if (EapSuccess | EapFail)
|
||
|
{
|
||
|
// Auth timer will have restarted in FSMAuthenticating
|
||
|
// Deactivate the timer
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// If the packet received was a EAP-Success, go into
|
||
|
// AUTHENTICATED state
|
||
|
if (EapSuccess)
|
||
|
{
|
||
|
if ((dwRetCode = ElProcessEapSuccess (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
// If the packet received was a EAP-Failure, go into
|
||
|
// HELD state
|
||
|
if (EapFail)
|
||
|
{
|
||
|
if ((dwRetCode = ElProcessEapFail (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_HELD:
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: HELD state, Ignoring packet");
|
||
|
if (ReqId)
|
||
|
{
|
||
|
// Deactivate current timer
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if ((dwRetCode = FSMAcquired (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_AUTHENTICATED:
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: STATE_AUTHENTICATED");
|
||
|
if (ReqId)
|
||
|
{
|
||
|
if ((dwRetCode = FSMAcquired (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
if (RxKey)
|
||
|
{
|
||
|
if ((dwRetCode = FSMRxKey (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket: Critical Error. Invalid state, Ignoring packet");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Only packet passing through switch statement will be freed here
|
||
|
FREE (pEapolBuffer);
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
|
||
|
// Post a new read request, ignoring errors
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Port %s not active, not reposting read request",
|
||
|
pPCB->pszDeviceGUID);
|
||
|
// Port is not active, release Context buffer
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Reposting buffer on port %s",
|
||
|
pPCB->pszDeviceGUID);
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
// ElReadFromPort creates a new context buffer, adds a ref count,
|
||
|
// and posts the read request
|
||
|
if ((dwRetCode = ElReadFromPort (
|
||
|
pPCB,
|
||
|
NULL,
|
||
|
0
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: Critical error: ElReadFromPort error %d",
|
||
|
dwRetCode);
|
||
|
// LOG
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Dereference ref count held for the read that was just processed
|
||
|
EAPOL_DEREFERENCE_PORT(pPCB);
|
||
|
TRACE2 (EAPOL, "ProcessReceivedPacket: pPCB= %p, RefCnt = %ld",
|
||
|
pPCB, pPCB->dwRefCount);
|
||
|
|
||
|
TRACE0 (EAPOL, "ProcessReceivedPacket exit");
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMDisconnected
|
||
|
//
|
||
|
// Description:
|
||
|
// Function called when media disconnect occurs
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to PCB for the port on which media disconnect occurs
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMDisconnected (
|
||
|
IN EAPOL_PCB *pPCB
|
||
|
)
|
||
|
{
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMDisconnected entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state DISCONNECTED for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
pPCB->State = EAPOLSTATE_DISCONNECTED;
|
||
|
|
||
|
// Free Identity buffer
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
|
||
|
// Free Password buffer
|
||
|
|
||
|
if (pPCB->pszPassword != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszPassword);
|
||
|
pPCB->pszPassword = NULL;
|
||
|
}
|
||
|
|
||
|
// Free user-specific data in the PCB
|
||
|
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
|
||
|
// Free connection data, though it is common to all users
|
||
|
|
||
|
if (pPCB->pCustomAuthConnData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthConnData);
|
||
|
pPCB->pCustomAuthConnData = NULL;
|
||
|
}
|
||
|
|
||
|
// Free SSID
|
||
|
|
||
|
if (pPCB->pszSSID != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszSSID);
|
||
|
pPCB->pszSSID = NULL;
|
||
|
}
|
||
|
|
||
|
pPCB->fGotUserIdentity = FALSE;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMDisconnected completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMLogoff
|
||
|
//
|
||
|
// Description:
|
||
|
// Function called to send out EAPOL_Logoff packet. Usually triggered by
|
||
|
// user logging off.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to PCB for the port on which logoff packet is to be
|
||
|
// sent out
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMLogoff (
|
||
|
IN EAPOL_PCB *pPCB
|
||
|
)
|
||
|
{
|
||
|
EAPOL_PACKET *pEapolPkt = NULL;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMLogoff entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Allocate new buffer
|
||
|
pEapolPkt = (EAPOL_PACKET *) MALLOC (sizeof (EAPOL_PACKET));
|
||
|
if (pEapolPkt == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMLogoff: Error in allocating memory for EAPOL packet");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Fill in fields
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPkt->EthernetType,
|
||
|
(BYTE *)pPCB->bEtherType,
|
||
|
SIZE_ETHERNET_TYPE);
|
||
|
pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
|
||
|
pEapolPkt->PacketType = EAPOL_Logoff;
|
||
|
HostToWireFormat16 ((WORD)0, (BYTE *)pEapolPkt->PacketBodyLength);
|
||
|
|
||
|
// Send packet out on the port
|
||
|
dwRetCode = ElWriteToPort (pPCB,
|
||
|
(CHAR *)pEapolPkt,
|
||
|
sizeof (EAPOL_PACKET));
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMLogoff: Error in writing Logoff pkt to port %ld",
|
||
|
dwRetCode);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Mark that EAPOL_Logoff was sent out on the port
|
||
|
pPCB->dwLogoffSent = 1;
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state LOGOFF for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
pPCB->State = EAPOLSTATE_LOGOFF;
|
||
|
|
||
|
// Free Identity buffer
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
|
||
|
// Free Password buffer
|
||
|
|
||
|
if (pPCB->pszPassword != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszPassword);
|
||
|
pPCB->pszPassword = NULL;
|
||
|
}
|
||
|
|
||
|
// Free user-specific data in the PCB
|
||
|
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
|
||
|
// Free connection data, though it is common to all users
|
||
|
|
||
|
if (pPCB->pCustomAuthConnData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthConnData);
|
||
|
pPCB->pCustomAuthConnData = NULL;
|
||
|
}
|
||
|
|
||
|
// Free SSID
|
||
|
|
||
|
if (pPCB->pszSSID != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszSSID);
|
||
|
pPCB->pszSSID = NULL;
|
||
|
}
|
||
|
|
||
|
pPCB->fGotUserIdentity = FALSE;
|
||
|
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMLogoff completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMConnecting
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Funtion called to send out EAPOL_Start packet. If MaxStart EAPOL_Start
|
||
|
// packets have been sent out, State Machine moves to Authenticated state
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to the PCB for the port on which Start packet is
|
||
|
// to be sent out
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMConnecting (
|
||
|
IN EAPOL_PCB *pPCB
|
||
|
)
|
||
|
{
|
||
|
EAPOL_PACKET *pEapolPkt = NULL;
|
||
|
DWORD dwStartInterval = 0;
|
||
|
GUID DeviceGuid;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMConnecting entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationStarted (&DeviceGuid);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (pPCB->State == EAPOLSTATE_CONNECTING)
|
||
|
{
|
||
|
// If PCB->State was Connecting earlier, increment ulStartCount
|
||
|
// else set ulStartCount to zero
|
||
|
|
||
|
// Did not receive Req/Id
|
||
|
if ((++(pPCB->ulStartCount)) > pPCB->EapolConfig.dwmaxStart)
|
||
|
{
|
||
|
// Deactivate start timer
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMConnecting: Sent out maxStart with no response, Setting AUTHENTICATED state");
|
||
|
|
||
|
// Sent out enough EAPOL_Starts
|
||
|
// Go into authenticated state
|
||
|
if ((dwRetCode = FSMAuthenticated (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMConnecting: Error in FSMAuthenticated %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
// Display change of status using sys tray balloon
|
||
|
// on interface icon
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationSucceeded (&DeviceGuid);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// No need to send out more EAPOL_Start packets
|
||
|
|
||
|
// Reset start packet count
|
||
|
pPCB->ulStartCount = 0;
|
||
|
pPCB->fIsRemoteEndEAPOLAware = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB->ulStartCount++;
|
||
|
}
|
||
|
|
||
|
// If user is not logged in, send out EAPOL_Start packets
|
||
|
// at intervals of 1 second each. This is used to detect if the
|
||
|
// interface is on a secure network or not.
|
||
|
// If user is logged in, use the configured value for the
|
||
|
// StartPeriod as the interval
|
||
|
//if (!pPCB->fUserLoggedIn)
|
||
|
|
||
|
if (!g_fUserLoggedOn)
|
||
|
{
|
||
|
dwStartInterval = EAPOL_INIT_START_PERIOD; // 1 second
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwStartInterval = pPCB->EapolConfig.dwstartPeriod;
|
||
|
}
|
||
|
|
||
|
// Restart timer with startPeriod
|
||
|
// Even if error occurs, timeout will happen
|
||
|
// Else, we won't be able to get out of connecting state
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
dwStartInterval,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMConnecting: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Send out EAPOL_Start
|
||
|
// Allocate new buffer
|
||
|
pEapolPkt = (EAPOL_PACKET *) MALLOC (sizeof(EAPOL_PACKET));
|
||
|
if (pEapolPkt == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMConnecting: Error in allocating memory for EAPOL packet");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// ISSUE:
|
||
|
// Does Authenticator side also ignore data beyond PacketType
|
||
|
// as the supplicant side does?
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPkt->EthernetType,
|
||
|
(BYTE *)pPCB->bEtherType,
|
||
|
SIZE_ETHERNET_TYPE);
|
||
|
pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
|
||
|
pEapolPkt->PacketType = EAPOL_Start;
|
||
|
HostToWireFormat16 ((WORD)0, (BYTE *)pEapolPkt->PacketBodyLength);
|
||
|
|
||
|
// Send packet out on the port
|
||
|
dwRetCode = ElWriteToPort (pPCB,
|
||
|
(CHAR *)pEapolPkt,
|
||
|
sizeof (EAPOL_PACKET));
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMConnecting: Error in writing Start Pkt to port %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state CONNECTING for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
pPCB->State = EAPOLSTATE_CONNECTING;
|
||
|
SET_EAPOL_START_TIMER(pPCB);
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMConnecting completed for port %s", pPCB->pszFriendlyName);
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMAcquired
|
||
|
//
|
||
|
// Description:
|
||
|
// Function called when the port receives a EAP-Request/Identity packet.
|
||
|
// EAP processing of the packet occurs and a EAP-Response/Identity may
|
||
|
// be sent out by EAP if required.
|
||
|
//
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to the PCB for the port on which data is being
|
||
|
// processed
|
||
|
// pEapolPkt - Pointer to EAPOL packet that was received
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMAcquired (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_PACKET *pEapolPkt
|
||
|
)
|
||
|
{
|
||
|
DWORD dwComputerNameLen = 0;
|
||
|
GUID DeviceGuid;
|
||
|
DWORD dwRetCode= NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMAcquired entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationStarted (&DeviceGuid);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
// Indicate to EAP=Dll to cleanup any leftovers from earlier
|
||
|
// authentication. This is to take care of cases where errors
|
||
|
// occured in the earlier authentication and cleanup wasn't done
|
||
|
if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAcquired: Error in ElEapEnd = %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Restart timer with authPeriod
|
||
|
// Even if there is error in ElEapWork, the authtimer timeout
|
||
|
// should happen
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwauthPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAcquired: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Since an EAP Req-ID was received, reset EAPOL_Start count
|
||
|
pPCB->ulStartCount = 0;
|
||
|
|
||
|
|
||
|
// If current received EAP Id is the same the previous EAP Id
|
||
|
// send the last EAPOL packet again
|
||
|
|
||
|
if (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Id ==
|
||
|
pPCB->dwPreviousId)
|
||
|
{
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMAcquired: Re-xmitting EAP_Packet to port");
|
||
|
|
||
|
dwRetCode = ElWriteToPort (pPCB,
|
||
|
(CHAR *)pPCB->pbPreviousEAPOLPkt,
|
||
|
pPCB->dwSizeOfPreviousEAPOLPkt);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAcquired: Error in writing re-xmitted EAP_Packet to port %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Process the EAP packet
|
||
|
// ElEapWork will send out response if required
|
||
|
if (( dwRetCode = ElEapWork (
|
||
|
pPCB,
|
||
|
(PPP_EAP_PACKET *)pEapolPkt->PacketBody
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAcquired: Error in ElEapWork %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state ACQUIRED for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
SET_EAPOL_AUTH_TIMER(pPCB);
|
||
|
pPCB->State = EAPOLSTATE_ACQUIRED;
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMAcquired completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMAuthenticating
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called when an non EAP-Request/Identity packet is received on the
|
||
|
// port. EAP processing of the data occurs.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to the PCB for the port on which data is being
|
||
|
// processed
|
||
|
// pEapolPkt - Pointer to EAPOL packet that was received
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMAuthenticating (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_PACKET *pEapolPkt
|
||
|
)
|
||
|
{
|
||
|
GUID DeviceGuid;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMAuthenticating entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationStarted (&DeviceGuid);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
// Restart timer with authPeriod
|
||
|
// Even if there is error in ElEapWork, the authtimer timeout
|
||
|
// should happen
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwauthPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAuthenticating: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// If current received EAP Id is the same the previous EAP Id
|
||
|
// send the last EAPOL packet again
|
||
|
// For EAPCODE_Success and EAPCODE_Failure, the value of id field
|
||
|
// will not be increment, Refer to EAP RFC
|
||
|
|
||
|
if ((((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Id
|
||
|
== pPCB->dwPreviousId) &&
|
||
|
(((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Code
|
||
|
!= EAPCODE_Success) &&
|
||
|
(((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Code
|
||
|
!= EAPCODE_Failure))
|
||
|
{
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMAcquired: Re-xmitting EAP_Packet to port");
|
||
|
|
||
|
dwRetCode = ElWriteToPort (pPCB,
|
||
|
(CHAR *)pPCB->pbPreviousEAPOLPkt,
|
||
|
pPCB->dwSizeOfPreviousEAPOLPkt);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAcquired: Error in writing re-xmitted EAP_Packet to port = %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Process the EAP packet
|
||
|
// ElEapWork will send out response if required
|
||
|
if (( dwRetCode = ElEapWork (
|
||
|
pPCB,
|
||
|
(PPP_EAP_PACKET *)pEapolPkt->PacketBody
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAuthenticating: Error in ElEapWork %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state AUTHENTICATING for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
SET_EAPOL_AUTH_TIMER(pPCB);
|
||
|
pPCB->State = EAPOLSTATE_AUTHENTICATING;
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMAuthenticating completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMHeld
|
||
|
//
|
||
|
// Description:
|
||
|
// Function called when a EAP-Failure packet is received in the
|
||
|
// Authenticating state. State machine is held for heldPeriod before
|
||
|
// re-authentication can occur.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to the PCB for the port on which data is being
|
||
|
// processed
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMHeld (
|
||
|
IN EAPOL_PCB *pPCB
|
||
|
)
|
||
|
{
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMHeld entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
#ifdef DRAFT7
|
||
|
if (g_dwMachineAuthEnabled)
|
||
|
{
|
||
|
#endif
|
||
|
|
||
|
pPCB->dwAuthFailCount++;
|
||
|
|
||
|
if (pPCB->dwAuthFailCount <= EAPOL_MAX_AUTH_FAIL_COUNT)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "Restarting Held timer with time value = %ld",
|
||
|
pPCB->EapolConfig.dwheldPeriod);
|
||
|
|
||
|
// Restart timer with heldPeriod
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwheldPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE1 (EAPOL, "Restarting Held timer with extended time value = %ld",
|
||
|
(pPCB->dwAuthFailCount * (pPCB->EapolConfig.dwheldPeriod)));
|
||
|
|
||
|
// Restart timer with heldPeriod times pPCB->dwAuthFailCount
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
((pPCB->dwAuthFailCount) * (pPCB->EapolConfig.dwheldPeriod)),
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
}
|
||
|
|
||
|
#ifdef DRAFT7
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
TRACE1 (EAPOL, "Restarting Held timer with time value = %ld",
|
||
|
pPCB->EapolConfig.dwheldPeriod);
|
||
|
|
||
|
// Restart timer with heldPeriod
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwheldPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
|
||
|
} // g_dwMachineAuthEnabled
|
||
|
#endif
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMHeld: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Free Identity buffer
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
|
||
|
// Free Password buffer
|
||
|
|
||
|
if (pPCB->pszPassword != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszPassword);
|
||
|
pPCB->pszPassword = NULL;
|
||
|
}
|
||
|
|
||
|
// Free user-specific data in the PCB
|
||
|
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
|
||
|
// Free connection data
|
||
|
|
||
|
if (pPCB->pCustomAuthConnData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthConnData);
|
||
|
pPCB->pCustomAuthConnData = NULL;
|
||
|
}
|
||
|
|
||
|
// Since there has been an error in credentials, start afresh
|
||
|
// the authentication. Credentials may have changed e.g. certs
|
||
|
// may be renewed, MD5 credentials corrected etc.
|
||
|
|
||
|
pPCB->fGotUserIdentity = FALSE;
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state HELD for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
pPCB->State = EAPOLSTATE_HELD;
|
||
|
SET_EAPOL_HELD_TIMER(pPCB);
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMHeld: Port %s set to HELD state",
|
||
|
pPCB->pszDeviceGUID);
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMHeld completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMAuthenticated
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called when a EAP-Success packet is received or MaxStart
|
||
|
// EAPOL_Startpackets have been sent out, but no EAP-Request/Identity
|
||
|
// packets were received. If EAP-Success packet is request, DHCP client
|
||
|
// is restarted to get a new IP address.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to the PCB for the port on which data is being
|
||
|
// processed
|
||
|
// pEapolPkt - Pointer to EAPOL packet that was received
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMAuthenticated (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_PACKET *pEapolPkt
|
||
|
)
|
||
|
{
|
||
|
DHCP_PNP_CHANGE DhcpPnpChange;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMAuthenticated entered for port %s",
|
||
|
pPCB->pszFriendlyName);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Shutdown earlier EAP session
|
||
|
ElEapEnd (pPCB);
|
||
|
|
||
|
// Call DHCP only if state machine went through authentication
|
||
|
// If FSM is getting AUTHENTICATED by default, don't call DHCP
|
||
|
|
||
|
// if (pPCB->ulStartCount < pPCB->EapolConfig.dwmaxStart)
|
||
|
{
|
||
|
// Call DHCP to do PnP
|
||
|
ZeroMemory(&DhcpPnpChange, sizeof(DHCP_PNP_CHANGE));
|
||
|
DhcpPnpChange.Version = DHCP_PNP_CHANGE_VERSION_0;
|
||
|
if ((dwRetCode = DhcpHandlePnPEvent(0,
|
||
|
DHCP_CALLER_TCPUI,
|
||
|
NULL,
|
||
|
//pPCB->pszDeviceGUID,
|
||
|
&DhcpPnpChange,
|
||
|
NULL)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMAuthenticated: DHCPHandlePnPEvent returned error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
TRACE0 (EAPOL, "FSMAuthenticated: DHCPHandlePnPEvent successful");
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "Setting state AUTHENTICATED for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
pPCB->State = EAPOLSTATE_AUTHENTICATED;
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMAuthenticated completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// FSMRxKey
|
||
|
//
|
||
|
// Description:
|
||
|
// Function called when an EAPOL-Key packet is received in the
|
||
|
// Authenticated state. The WEP key is decrypted and
|
||
|
// plumbed down to the NIC driver.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to the PCB for the port on which data is being
|
||
|
// processed
|
||
|
// pEapolPkt - Pointer to EAPOL packet that was received
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
FSMRxKey (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_PACKET *pEapolPkt
|
||
|
)
|
||
|
{
|
||
|
EAPOL_KEY_DESC *pKeyDesc = NULL;
|
||
|
EAPOL_KEY_DESC_D8 *pKeyDesc_D8 = NULL;
|
||
|
EAPOL_PACKET_D8 EapolPktD8;
|
||
|
EAPOL_PACKET_D8 *pEapolPktD8 = NULL;
|
||
|
ULONGLONG ullReplayCheck = 0;
|
||
|
BYTE bReplayCheck[8];
|
||
|
BYTE *pbMD5EapolPkt = NULL;
|
||
|
DWORD dwMD5EapolPktLen = 0;
|
||
|
MD5_CTX MD5Context;
|
||
|
DWORD dwEapPktLen = 0;
|
||
|
DWORD dwIndex = 0;
|
||
|
BYTE bHMACMD5HashBuffer[MD5DIGESTLEN];
|
||
|
RC4_KEYSTRUCT rc4key;
|
||
|
BYTE bKeyBuffer[48];
|
||
|
BYTE *pbKeyToBePlumbed = NULL;
|
||
|
DWORD dwKeyLength = 0;
|
||
|
NDIS_802_11_WEP *pNdisWEPKey = NULL;
|
||
|
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMRxKey entered for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (!pPCB->fRemoteEnd8021XD8)
|
||
|
{
|
||
|
// DRAFT 7
|
||
|
|
||
|
pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
|
||
|
|
||
|
dwKeyLength = WireToHostFormat16 (pKeyDesc->KeyLength);
|
||
|
|
||
|
TRACE4 (EAPOL, "Signature Type = %ld, \n Encrypt Type = %ld, \n KeyLength = %ld, \n KeyIndex = %ld",
|
||
|
pKeyDesc->SignatureType,
|
||
|
pKeyDesc->EncryptType,
|
||
|
dwKeyLength,
|
||
|
pKeyDesc->KeyIndex
|
||
|
);
|
||
|
|
||
|
// For Draft 8, do not check for non-existing fields
|
||
|
|
||
|
if (pKeyDesc->SignatureType != 1)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMRxKey: Invalid signature type = %ld",
|
||
|
pKeyDesc->SignatureType);
|
||
|
// log
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pKeyDesc->EncryptType != 1)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "FSMRxKey: Invalid encryption type = %ld",
|
||
|
pKeyDesc->EncryptType);
|
||
|
// log
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
memcpy ((BYTE *)bReplayCheck,
|
||
|
(BYTE *)pKeyDesc->ReplayCounter,
|
||
|
8*sizeof(BYTE));
|
||
|
|
||
|
ullReplayCheck = ((*((PBYTE)(bReplayCheck)+0) << 56) +
|
||
|
(*((PBYTE)(bReplayCheck)+1) << 48) +
|
||
|
(*((PBYTE)(bReplayCheck)+2) << 40) +
|
||
|
(*((PBYTE)(bReplayCheck)+3) << 32) +
|
||
|
(*((PBYTE)(bReplayCheck)+4) << 24) +
|
||
|
(*((PBYTE)(bReplayCheck)+5) << 16) +
|
||
|
(*((PBYTE)(bReplayCheck)+6) << 8) +
|
||
|
(*((PBYTE)(bReplayCheck)+7)));
|
||
|
|
||
|
//
|
||
|
// Check validity of Key message using the ReplayCounter field
|
||
|
// Verify if it is in sync with the last ReplayCounter value
|
||
|
// received
|
||
|
//
|
||
|
|
||
|
TRACE0 (EAPOL, "Incoming Replay counter ======= ");
|
||
|
EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
|
||
|
TRACE0 (EAPOL, "Last Replay counter ======= ");
|
||
|
EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
|
||
|
|
||
|
if (ullReplayCheck <= pPCB->ullLastReplayCounter)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Replay counter is not in sync, something is wrong");
|
||
|
// log
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// If valid ReplayCounter, save it in the PCB for future check
|
||
|
pPCB->ullLastReplayCounter = ullReplayCheck;
|
||
|
|
||
|
|
||
|
TRACE0 (EAPOL, "Replay counter in desc ======");
|
||
|
EAPOL_DUMPBA (pKeyDesc->ReplayCounter, 8);
|
||
|
|
||
|
//
|
||
|
// Verify if the MD5 hash generated on the EAPOL packet,
|
||
|
// with Signature nulled out, is the same as the signature
|
||
|
// Use the MPPERecv key as the secret
|
||
|
//
|
||
|
|
||
|
dwEapPktLen = WireToHostFormat16 (pEapolPkt->PacketBodyLength);
|
||
|
dwMD5EapolPktLen = sizeof (EAPOL_PACKET) - sizeof(pEapolPkt->EthernetType) - 1 + dwEapPktLen;
|
||
|
if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Error in MALLOC for pbMD5EapolPkt");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPkt+sizeof(pEapolPkt->EthernetType), dwMD5EapolPktLen);
|
||
|
|
||
|
//
|
||
|
// Null out the signature in the key descriptor copy, to calculate
|
||
|
// the hash on the supplicant side
|
||
|
//
|
||
|
|
||
|
ZeroMemory ((BYTE *)(pbMD5EapolPkt
|
||
|
- sizeof(pEapolPkt->EthernetType) +
|
||
|
sizeof(EAPOL_PACKET) - 1 + // pEapolPkt->Body
|
||
|
sizeof(EAPOL_KEY_DESC)- // End of EAPOL_KEY_DESC
|
||
|
MD5DIGESTLEN-1), // Signature field
|
||
|
MD5DIGESTLEN);
|
||
|
|
||
|
(VOID) ElGetHMACMD5Digest (
|
||
|
pbMD5EapolPkt,
|
||
|
dwMD5EapolPktLen,
|
||
|
pPCB->pbMPPERecvKey,
|
||
|
pPCB->dwMPPERecvKeyLength,
|
||
|
bHMACMD5HashBuffer
|
||
|
);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MD5 Hash body ==");
|
||
|
EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MD5 Hash secret ==");
|
||
|
EAPOL_DUMPBA (pPCB->pbMPPERecvKey, pPCB->dwMPPERecvKeyLength);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MD5 Hash generated by Supplicant");
|
||
|
EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Signature sent in EAPOL_KEY_DESC");
|
||
|
EAPOL_DUMPBA (pKeyDesc->KeySignature, MD5DIGESTLEN);
|
||
|
|
||
|
//
|
||
|
// Check if HMAC-MD5 hash in received packet is what is expected
|
||
|
//
|
||
|
if (memcmp (bHMACMD5HashBuffer, pKeyDesc->KeySignature, MD5DIGESTLEN) != 0)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Signature in Key Desc does not match, potential security attack");
|
||
|
// log
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Decrypt the multicast WEP key if it has been provided
|
||
|
//
|
||
|
|
||
|
// Check if there is Key Material (5/16 bytes) at the end of
|
||
|
// the Key Descriptor
|
||
|
|
||
|
if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
|
||
|
|
||
|
{
|
||
|
memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc->Key_IV, 16);
|
||
|
memcpy ((BYTE *)&bKeyBuffer[16], (BYTE *)pPCB->pbMPPESendKey, 32);
|
||
|
|
||
|
rc4_key (&rc4key, 48, bKeyBuffer);
|
||
|
rc4 (&rc4key, dwKeyLength, pKeyDesc->Key);
|
||
|
|
||
|
TRACE0 (EAPOL, " ========= The multicast key is ============= ");
|
||
|
EAPOL_DUMPBA (pKeyDesc->Key, dwKeyLength);
|
||
|
|
||
|
|
||
|
// Use the unencrypted key in the Key Desc as the encryption key
|
||
|
|
||
|
pbKeyToBePlumbed = pKeyDesc->Key;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Use the MPPESend key as the encryption key
|
||
|
|
||
|
pbKeyToBePlumbed = (BYTE *)pPCB->pbMPPESendKey;
|
||
|
}
|
||
|
|
||
|
if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwKeyLength ))
|
||
|
== NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MALLOC failed for pNdisWEPKey");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwKeyLength;
|
||
|
memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
|
||
|
dwKeyLength);
|
||
|
pNdisWEPKey->KeyLength = dwKeyLength;
|
||
|
|
||
|
|
||
|
// Create the long index out of the byte index got from AP
|
||
|
// If MSB in byte is set, set MSB in ulong format
|
||
|
|
||
|
if (pKeyDesc->KeyIndex & 0x80)
|
||
|
{
|
||
|
pNdisWEPKey->KeyIndex = 0x80000000;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNdisWEPKey->KeyIndex = 0x00000000;
|
||
|
}
|
||
|
|
||
|
pNdisWEPKey->KeyIndex |= (pKeyDesc->KeyIndex & 0x03);
|
||
|
|
||
|
TRACE1 (ANY, "FSMRxKey: Key Index is %x", pNdisWEPKey->KeyIndex);
|
||
|
|
||
|
|
||
|
// Use NDISUIO to plumb the key to the driver
|
||
|
|
||
|
if ((dwRetCode = ElNdisuioSetOIDValue (
|
||
|
pPCB->hPort,
|
||
|
OID_802_11_ADD_WEP,
|
||
|
(BYTE *)pNdisWEPKey,
|
||
|
pNdisWEPKey->Length)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (PORT, "FSMRxKey: ElNdisuioSetOIDValue failed with error %ld",
|
||
|
dwRetCode);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// DRAFT 8
|
||
|
|
||
|
// Point beyond Signature Type for structure alignment
|
||
|
pKeyDesc_D8 = (EAPOL_KEY_DESC_D8 *)(pEapolPkt->PacketBody);
|
||
|
|
||
|
dwKeyLength = WireToHostFormat16 (pKeyDesc_D8->KeyLength);
|
||
|
|
||
|
TRACE3 (EAPOL, "Descriptor type = %ld, \n KeyLength = %ld, \n KeyIndex = %ld",
|
||
|
pKeyDesc_D8->DescriptorType,
|
||
|
dwKeyLength,
|
||
|
pKeyDesc_D8->KeyIndex
|
||
|
);
|
||
|
|
||
|
memcpy ((BYTE *)bReplayCheck,
|
||
|
(BYTE *)pKeyDesc_D8->ReplayCounter,
|
||
|
8*sizeof(BYTE));
|
||
|
|
||
|
ullReplayCheck = ((*((PBYTE)(bReplayCheck)+0) << 56) +
|
||
|
(*((PBYTE)(bReplayCheck)+1) << 48) +
|
||
|
(*((PBYTE)(bReplayCheck)+2) << 40) +
|
||
|
(*((PBYTE)(bReplayCheck)+3) << 32) +
|
||
|
(*((PBYTE)(bReplayCheck)+4) << 24) +
|
||
|
(*((PBYTE)(bReplayCheck)+5) << 16) +
|
||
|
(*((PBYTE)(bReplayCheck)+6) << 8) +
|
||
|
(*((PBYTE)(bReplayCheck)+7)));
|
||
|
|
||
|
//
|
||
|
// Check validity of Key message using the ReplayCounter field
|
||
|
// Verify if it is in sync with the last ReplayCounter value
|
||
|
// received
|
||
|
//
|
||
|
|
||
|
TRACE0 (EAPOL, "Incoming Replay counter ======= ");
|
||
|
EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
|
||
|
TRACE0 (EAPOL, "Last Replay counter ======= ");
|
||
|
EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
|
||
|
|
||
|
if (ullReplayCheck < pPCB->ullLastReplayCounter)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Replay counter is not in sync, something is wrong");
|
||
|
// log
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// If valid ReplayCounter, save it in the PCB for future check
|
||
|
pPCB->ullLastReplayCounter = ullReplayCheck;
|
||
|
|
||
|
TRACE1 (EAPOL, "Replay counter ======= %lx", ullReplayCheck);
|
||
|
|
||
|
TRACE0 (EAPOL, "Replay counter in desc ======");
|
||
|
EAPOL_DUMPBA (pKeyDesc_D8->ReplayCounter, 8);
|
||
|
|
||
|
//
|
||
|
// Verify if the MD5 hash generated on the EAPOL packet,
|
||
|
// with Signature nulled out, is the same as the signature
|
||
|
// Use the MPPERecv key as the secret
|
||
|
//
|
||
|
|
||
|
{
|
||
|
ZeroMemory (&EapolPktD8, sizeof (EAPOL_PACKET_D8));
|
||
|
|
||
|
memcpy (EapolPktD8.EthernetType, pEapolPkt->EthernetType, 2);
|
||
|
EapolPktD8.ProtocolVersion = pEapolPkt->ProtocolVersion;
|
||
|
EapolPktD8.PacketType = pEapolPkt->PacketType;
|
||
|
memcpy (EapolPktD8.PacketBodyLength, pEapolPkt->PacketBodyLength,
|
||
|
2);
|
||
|
memcpy ((BYTE *)&(EapolPktD8.AuthResultCode), (BYTE *)pEapolPkt - 2, 2);
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPkt - 2, (BYTE *)&EapolPktD8,
|
||
|
sizeof(EAPOL_PACKET_D8)-1);
|
||
|
|
||
|
pEapolPktD8 = (EAPOL_PACKET_D8 *)((BYTE *)pEapolPkt - 2);
|
||
|
}
|
||
|
|
||
|
dwEapPktLen = WireToHostFormat16 (pEapolPktD8->PacketBodyLength);
|
||
|
dwMD5EapolPktLen = sizeof (EAPOL_PACKET_D8) - sizeof(pEapolPktD8->EthernetType) - 1 + dwEapPktLen;
|
||
|
if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Error in MALLOC for pbMD5EapolPkt");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPktD8+sizeof(pEapolPktD8->EthernetType), dwMD5EapolPktLen);
|
||
|
|
||
|
//
|
||
|
// Null out the signature in the key descriptor copy, to calculate
|
||
|
// the hash on the supplicant side
|
||
|
//
|
||
|
|
||
|
// Draft 8 has different KEY_DESC size
|
||
|
ZeroMemory ((BYTE *)(pbMD5EapolPkt
|
||
|
- sizeof(pEapolPktD8->EthernetType) +
|
||
|
sizeof(EAPOL_PACKET_D8) - 1 + // pEapolPktD8->Body
|
||
|
sizeof(EAPOL_KEY_DESC_D8) - // End of EAPOL_KEY_DESC
|
||
|
MD5DIGESTLEN-1), // Signature field
|
||
|
MD5DIGESTLEN);
|
||
|
|
||
|
(VOID) ElGetHMACMD5Digest (
|
||
|
pbMD5EapolPkt,
|
||
|
dwMD5EapolPktLen,
|
||
|
pPCB->pbMPPERecvKey,
|
||
|
pPCB->dwMPPERecvKeyLength,
|
||
|
bHMACMD5HashBuffer
|
||
|
);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MD5 Hash body ==");
|
||
|
EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MD5 Hash secret ==");
|
||
|
EAPOL_DUMPBA (pPCB->pbMPPERecvKey, pPCB->dwMPPERecvKeyLength);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MD5 Hash generated by Supplicant");
|
||
|
EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
|
||
|
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Signature sent in EAPOL_KEY_DESC");
|
||
|
EAPOL_DUMPBA (pKeyDesc_D8->KeySignature, MD5DIGESTLEN);
|
||
|
|
||
|
//
|
||
|
// Check if HMAC-MD5 hash in received packet is what is expected
|
||
|
//
|
||
|
if (memcmp (bHMACMD5HashBuffer, pKeyDesc_D8->KeySignature, MD5DIGESTLEN) != 0)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: Signature in Key Desc does not match, potential security attack");
|
||
|
// log
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Decrypt the multicast WEP key if it has been provided
|
||
|
//
|
||
|
|
||
|
// Check if there is Key Material (5/16 bytes) at the end of
|
||
|
// the Key Descriptor
|
||
|
|
||
|
if (WireToHostFormat16 (pEapolPktD8->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
|
||
|
|
||
|
{
|
||
|
memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc_D8->Key_IV, 16);
|
||
|
memcpy ((BYTE *)&bKeyBuffer[16], (BYTE *)pPCB->pbMPPESendKey, 32);
|
||
|
|
||
|
rc4_key (&rc4key, 48, bKeyBuffer);
|
||
|
rc4 (&rc4key, dwKeyLength, pKeyDesc_D8->Key);
|
||
|
|
||
|
TRACE0 (EAPOL, " ========= The multicast key is ============= ");
|
||
|
EAPOL_DUMPBA (pKeyDesc_D8->Key, dwKeyLength);
|
||
|
|
||
|
|
||
|
// Use the unencrypted key in the Key Desc as the encryption key
|
||
|
|
||
|
pbKeyToBePlumbed = pKeyDesc_D8->Key;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Use the MPPESend key as the encryption key
|
||
|
|
||
|
pbKeyToBePlumbed = (BYTE *)pPCB->pbMPPESendKey;
|
||
|
}
|
||
|
|
||
|
if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwKeyLength ))
|
||
|
== NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "FSMRxKey: MALLOC failed for pNdisWEPKey");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwKeyLength;
|
||
|
memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
|
||
|
dwKeyLength);
|
||
|
pNdisWEPKey->KeyLength = dwKeyLength;
|
||
|
|
||
|
|
||
|
// Create the long index out of the byte index got from AP
|
||
|
// If MSB in byte is set, set MSB in ulong format
|
||
|
|
||
|
if (pKeyDesc_D8->KeyIndex & 0x80)
|
||
|
{
|
||
|
pNdisWEPKey->KeyIndex = 0x80000000;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNdisWEPKey->KeyIndex = 0x00000000;
|
||
|
}
|
||
|
|
||
|
pNdisWEPKey->KeyIndex |= (pKeyDesc_D8->KeyIndex & 0x03);
|
||
|
|
||
|
TRACE1 (ANY, "FSMRxKey: Key Index is %x", pNdisWEPKey->KeyIndex);
|
||
|
|
||
|
|
||
|
// Use NDISUIO to plumb the key to the driver
|
||
|
|
||
|
if ((dwRetCode = ElNdisuioSetOIDValue (
|
||
|
pPCB->hPort,
|
||
|
OID_802_11_ADD_WEP,
|
||
|
(BYTE *)pNdisWEPKey,
|
||
|
pNdisWEPKey->Length)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (PORT, "FSMRxKey: ElNdisuioSetOIDValue failed with error %ld",
|
||
|
dwRetCode);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
} while (FALSE);
|
||
|
|
||
|
if (pbMD5EapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pbMD5EapolPkt);
|
||
|
pbMD5EapolPkt = NULL;
|
||
|
}
|
||
|
|
||
|
if (pNdisWEPKey != NULL)
|
||
|
{
|
||
|
FREE (pNdisWEPKey);
|
||
|
pNdisWEPKey = NULL;
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "FSMRxKey completed for port %s", pPCB->pszFriendlyName);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElTimeoutCallbackRoutine
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called when any timer work item queued on the global timer
|
||
|
// queue expires. Depending on the state in which the port is when the timer
|
||
|
// expires, the port moves to the next state.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pvContext - Pointer to context. In this case, it is pointer to a PCB
|
||
|
// fTimerOfWaitFired - Unused
|
||
|
//
|
||
|
// Return values:
|
||
|
//
|
||
|
|
||
|
VOID
|
||
|
ElTimeoutCallbackRoutine (
|
||
|
IN PVOID pvContext,
|
||
|
IN BOOLEAN fTimerOfWaitFired
|
||
|
)
|
||
|
{
|
||
|
EAPOL_PCB *pPCB;
|
||
|
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine entered");
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Context should not be NULL
|
||
|
if (pvContext == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: pvContext is NULL. Invalid timeout callback");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// PCB is guaranteed to exist until all timers are fired
|
||
|
|
||
|
// Verify if Port is still active
|
||
|
pPCB = (EAPOL_PCB *)pvContext;
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
// Port is not active
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
TRACE1 (PORT, "ElTimeoutCallbackRoutine: Port %s is inactive",
|
||
|
pPCB->pszDeviceGUID);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Check the timer has been changed
|
||
|
// If the current time is less than the programmed timeout on
|
||
|
// the PCB, either timer component has shot off timer earlier
|
||
|
// or the timer fired but someone changed it in the meanwhile
|
||
|
if (pPCB->ulTimeout > GetTickCount())
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: Timeout value has been changed or Timer fired earlier than required");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Check the current state of the state machine
|
||
|
// We can do additional checks such as flagging which timer was fired
|
||
|
// and in the timeout checking if the PCB state has remained the same
|
||
|
// Else bail out
|
||
|
|
||
|
switch (pPCB->State)
|
||
|
{
|
||
|
case EAPOLSTATE_CONNECTING:
|
||
|
if (!EAPOL_START_TIMER_SET(pPCB))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Connecting state", CHECK_EAPOL_TIMER(pPCB));
|
||
|
break;
|
||
|
}
|
||
|
FSMConnecting(pPCB);
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_ACQUIRED:
|
||
|
if (!EAPOL_AUTH_TIMER_SET(pPCB))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Acquired state", CHECK_EAPOL_TIMER(pPCB));
|
||
|
break;
|
||
|
}
|
||
|
FSMConnecting(pPCB);
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_AUTHENTICATING:
|
||
|
if (!EAPOL_AUTH_TIMER_SET(pPCB))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Authenticating state", CHECK_EAPOL_TIMER(pPCB));
|
||
|
break;
|
||
|
}
|
||
|
FSMConnecting(pPCB);
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_HELD:
|
||
|
if (!EAPOL_HELD_TIMER_SET(pPCB))
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Held state", CHECK_EAPOL_TIMER(pPCB));
|
||
|
break;
|
||
|
}
|
||
|
FSMConnecting(pPCB);
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_DISCONNECTED:
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Disconnected state");
|
||
|
break;
|
||
|
|
||
|
case EAPOLSTATE_LOGOFF:
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Logoff state");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: Critical Error. Invalid state after timer expires ");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE0 (EAPOL, "ElTimeoutCallbackRoutine completed");
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElEapWork
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called when an EAPOL packet of type EAP_Packet is received
|
||
|
// The EAP packet is passed to the EAP module for processing.
|
||
|
// Depending on the result of the processing, a EAP Response packet
|
||
|
// is sent or the incoming packet is ignored.
|
||
|
//
|
||
|
// Input arguments:
|
||
|
// pPCB - Pointer to PCB for the port on which data is being processed
|
||
|
// pRecvPkt - Pointer to EAP packet in the data received from the remote end
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// ISSUE: Rewrite with do {} while(FALSE)
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElEapWork (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN PPP_EAP_PACKET *pRecvPkt
|
||
|
)
|
||
|
{
|
||
|
DWORD dwLength = 0;
|
||
|
ELEAP_RESULT EapResult;
|
||
|
PPP_EAP_PACKET *pSendPkt;
|
||
|
EAPOL_PACKET *pEapolPkt;
|
||
|
GUID DeviceGuid;
|
||
|
WCHAR awszNotificationMsg[MAX_NOTIFICATION_MSG_SIZE];
|
||
|
DWORD dwReceivedId = 0;
|
||
|
DWORD dwDraft8HdrIncr = 0;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
//
|
||
|
// If the protocol has not been started yet, call ElEapBegin
|
||
|
//
|
||
|
|
||
|
if (!(pPCB->fEapInitialized))
|
||
|
{
|
||
|
if (ElEapBegin (pPCB) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElEapWork: Error in ElEapBegin = %ld", dwRetCode);
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ZeroMemory(&EapResult, sizeof(EapResult));
|
||
|
|
||
|
// Create buffer for EAPOL + EAP and pass pointer to EAP header
|
||
|
|
||
|
pEapolPkt = (EAPOL_PACKET *) MALLOC (MAX_EAPOL_BUFFER_SIZE);
|
||
|
|
||
|
TRACE1 (EAPOL, "ElEapWork: EapolPkt created at %p", pEapolPkt);
|
||
|
|
||
|
if (pEapolPkt == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElEapWork: Error allocating EAP buffer");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
// Point to EAP header
|
||
|
pSendPkt = (PPP_EAP_PACKET *)((PBYTE)pEapolPkt + sizeof (EAPOL_PACKET) - 1);
|
||
|
|
||
|
if (pRecvPkt != NULL)
|
||
|
{
|
||
|
dwReceivedId = pRecvPkt->Id;
|
||
|
}
|
||
|
|
||
|
if (pPCB->fRemoteEnd8021XD8)
|
||
|
{
|
||
|
// Account for 2 bytes of AuthResultCode
|
||
|
dwDraft8HdrIncr = 2;
|
||
|
}
|
||
|
|
||
|
dwRetCode = ElEapMakeMessage (pPCB,
|
||
|
pRecvPkt,
|
||
|
pSendPkt,
|
||
|
MAX_EAPOL_BUFFER_SIZE
|
||
|
- sizeof(EAPOL_PACKET) - 1 - dwDraft8HdrIncr,
|
||
|
&EapResult
|
||
|
);
|
||
|
|
||
|
// Notification message for the user
|
||
|
|
||
|
if (NULL != EapResult.pszReplyMessage)
|
||
|
{
|
||
|
// Free earlier notication with the PCB
|
||
|
if (pPCB->pszEapReplyMessage != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszEapReplyMessage);
|
||
|
pPCB->pszEapReplyMessage = NULL;
|
||
|
}
|
||
|
|
||
|
pPCB->pszEapReplyMessage = EapResult.pszReplyMessage;
|
||
|
|
||
|
// Notify user of message
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
ZeroMemory (awszNotificationMsg, MAX_NOTIFICATION_MSG_SIZE);
|
||
|
if (0 == MultiByteToWideChar (
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
pPCB->pszEapReplyMessage,
|
||
|
-1,
|
||
|
awszNotificationMsg,
|
||
|
MAX_NOTIFICATION_MSG_SIZE))
|
||
|
{
|
||
|
dwRetCode = GetLastError();
|
||
|
|
||
|
TRACE2 (EAPOL,"MultiByteToWideChar(%s) failed: %d",
|
||
|
pPCB->pszEapReplyMessage,
|
||
|
dwRetCode);
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
|
||
|
return dwRetCode;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Display notification message using sys tray balloon
|
||
|
// on interface icon
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANNotification (&DeviceGuid,
|
||
|
awszNotificationMsg,
|
||
|
0);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
TRACE1 (EAPOL, "ElEapWork: Notified user of EAP data = %s",
|
||
|
pPCB->pszEapReplyMessage);
|
||
|
}
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
switch (dwRetCode)
|
||
|
{
|
||
|
case ERROR_PPP_INVALID_PACKET:
|
||
|
|
||
|
TRACE0 (EAPOL, "ElEapWork: Silently discarding invalid auth packet");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
TRACE1 (EAPOL, "ElEapWork: ElEapMakeMessage returned error %ld",
|
||
|
dwRetCode);
|
||
|
|
||
|
// NotifyCallerOfFailure (pPCB, dwRetCode);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Free up memory reserved for packet
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check to see if we have to save any user data
|
||
|
//
|
||
|
|
||
|
if (EapResult.fSaveUserData)
|
||
|
{
|
||
|
if ((dwRetCode = ElSetEapUserInfo (
|
||
|
pPCB->hUserToken,
|
||
|
pPCB->pszDeviceGUID,
|
||
|
pPCB->dwEapTypeToBeUsed,
|
||
|
pPCB->pszSSID,
|
||
|
EapResult.pUserData,
|
||
|
EapResult.dwSizeOfUserData)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElEapWork: ElSetEapUserInfo failed with error = %d",
|
||
|
dwRetCode);
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
TRACE1 (EAPOL, "ElEapWork: Saved EAP data for user, dwRetCode = %d",
|
||
|
dwRetCode);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check to see if we have to save any connection data
|
||
|
//
|
||
|
|
||
|
if ((EapResult.fSaveConnectionData ) &&
|
||
|
( 0 != EapResult.SetCustomAuthData.dwSizeOfConnectionData ) )
|
||
|
{
|
||
|
|
||
|
if ((dwRetCode = ElSetCustomAuthData (
|
||
|
pPCB->pszDeviceGUID,
|
||
|
pPCB->dwEapTypeToBeUsed,
|
||
|
pPCB->pszSSID,
|
||
|
EapResult.SetCustomAuthData.pConnectionData,
|
||
|
EapResult.SetCustomAuthData.dwSizeOfConnectionData
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 ( EAPOL, "ElEapWork: ElSetCustomAuthData failed with error = %d",
|
||
|
dwRetCode);
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
TRACE0 ( EAPOL, "ElEapWork: Saved EAP data for connection" );
|
||
|
}
|
||
|
|
||
|
switch( EapResult.Action )
|
||
|
{
|
||
|
|
||
|
case ELEAP_Send:
|
||
|
case ELEAP_SendAndDone:
|
||
|
|
||
|
// Send out EAPOL packet
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPkt->EthernetType,
|
||
|
(BYTE *)pPCB->bEtherType,
|
||
|
SIZE_ETHERNET_TYPE);
|
||
|
pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
|
||
|
pEapolPkt->PacketType = EAP_Packet;
|
||
|
|
||
|
// The EAP packet length is in the packet returned back by
|
||
|
// the Dll MakeMessage
|
||
|
// In case of Notification and Identity Response, it is in
|
||
|
// EapResult.wSizeOfEapPkt
|
||
|
|
||
|
if (EapResult.wSizeOfEapPkt == 0)
|
||
|
{
|
||
|
EapResult.wSizeOfEapPkt =
|
||
|
WireToHostFormat16 (pSendPkt->Length);
|
||
|
}
|
||
|
HostToWireFormat16 ((WORD) EapResult.wSizeOfEapPkt,
|
||
|
(BYTE *)pEapolPkt->PacketBodyLength);
|
||
|
|
||
|
|
||
|
// Make a copy of the EAPOL packet in the PCB
|
||
|
// Will be used during retransmission
|
||
|
|
||
|
if (pPCB->pbPreviousEAPOLPkt != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pbPreviousEAPOLPkt);
|
||
|
}
|
||
|
pPCB->pbPreviousEAPOLPkt =
|
||
|
MALLOC (sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
|
||
|
|
||
|
if (pPCB->pbPreviousEAPOLPkt == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE0 (EAPOL, "ElEapWork: MALLOC failed for pbPreviousEAPOLPkt");
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
memcpy (pPCB->pbPreviousEAPOLPkt, pEapolPkt,
|
||
|
sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
|
||
|
|
||
|
pPCB->dwSizeOfPreviousEAPOLPkt =
|
||
|
sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1;
|
||
|
|
||
|
pPCB->dwPreviousId = dwReceivedId;
|
||
|
|
||
|
|
||
|
// Send packet out on the port
|
||
|
dwRetCode = ElWriteToPort (pPCB,
|
||
|
(CHAR *)pEapolPkt,
|
||
|
sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElEapWork: Error in writing EAP_Packet to port %ld",
|
||
|
dwRetCode);
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
|
||
|
// More processing to be done?
|
||
|
// Supplicant side should not ever receive ELEAP_SendAndDone
|
||
|
// result code
|
||
|
|
||
|
if (EapResult.Action != ELEAP_SendAndDone)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElEapWork: ELEAP_SendAndDone wrong result received");
|
||
|
ASSERT(0);
|
||
|
}
|
||
|
|
||
|
case ELEAP_Done:
|
||
|
|
||
|
// Retrieve MPPE keys from the attributes information
|
||
|
// returned by EAP-TLS
|
||
|
|
||
|
switch (EapResult.dwError)
|
||
|
{
|
||
|
case NO_ERROR:
|
||
|
|
||
|
TRACE0 (EAPOL, "ElEapWork: Authentication was successful");
|
||
|
|
||
|
//
|
||
|
// If authentication was successful
|
||
|
//
|
||
|
|
||
|
dwRetCode = ElExtractMPPESendRecvKeys (
|
||
|
pPCB,
|
||
|
EapResult.pUserAttributes,
|
||
|
(BYTE*)&(EapResult.abChallenge),
|
||
|
(BYTE*)&(EapResult.abResponse));
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
//NotifyCallerOfFailure (pPcb, dwRetCode);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
// ISSUE:
|
||
|
// Do we want to retain UserAttributes
|
||
|
// pPCB->pAuthProtocolAttributes = EapResult.pUserAttributes;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
default:
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
TRACE0 (EAPOL, "ElEapWork: Authentication FAILED");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Free memory allocated for the packet, since no response
|
||
|
// is going to be sent out
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case ELEAP_NoAction:
|
||
|
// Free memory allocated for the packet, since nothing
|
||
|
// is being done with it
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
pEapolPkt = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check to see if we have to bring up the InteractiveUI for EAP
|
||
|
// i.e. Server cert confirmation etc.
|
||
|
//
|
||
|
|
||
|
if (EapResult.fInvokeEapUI)
|
||
|
{
|
||
|
ElInvokeInteractiveUI (pPCB, &(EapResult.InvokeEapUIData));
|
||
|
}
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// ElExtractMPPESendRecvKeys
|
||
|
//
|
||
|
// Description:
|
||
|
// Function called if authentication was successful. The MPPE Send &
|
||
|
// Recv keys are extracted from the RAS_AUTH_ATTRIBUTE passed from
|
||
|
// the EAP DLL and stored in the PCB. The keys are used to decrypt
|
||
|
// the multicast WEP key and also are used for media-based encrypting.
|
||
|
//
|
||
|
// Return values
|
||
|
//
|
||
|
// NO_ERROR - Success
|
||
|
// Non-zero - Failure
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElExtractMPPESendRecvKeys (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN RAS_AUTH_ATTRIBUTE * pUserAttributes,
|
||
|
IN BYTE * pChallenge,
|
||
|
IN BYTE * pResponse
|
||
|
)
|
||
|
{
|
||
|
RAS_AUTH_ATTRIBUTE * pAttribute;
|
||
|
RAS_AUTH_ATTRIBUTE * pAttributeSendKey;
|
||
|
RAS_AUTH_ATTRIBUTE * pAttributeRecvKey;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
DWORD dwEncryptionPolicy = 0;
|
||
|
DWORD dwEncryptionTypes = 0;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Every time we get encryption keys, plumb them to the driver
|
||
|
//
|
||
|
|
||
|
do
|
||
|
{
|
||
|
pAttribute = ElAuthAttributeGetVendorSpecific (
|
||
|
311, 12, pUserAttributes);
|
||
|
|
||
|
|
||
|
pAttributeSendKey = ElAuthAttributeGetVendorSpecific ( 311, 16,
|
||
|
pUserAttributes);
|
||
|
pAttributeRecvKey = ElAuthAttributeGetVendorSpecific ( 311, 17,
|
||
|
pUserAttributes);
|
||
|
|
||
|
if ((pAttributeSendKey != NULL)
|
||
|
&& (pAttributeRecvKey != NULL))
|
||
|
{
|
||
|
//
|
||
|
// Set the MS-MPPE-Send-Key and MS-MPPE-Recv-Key with
|
||
|
// the ethernet driver
|
||
|
//
|
||
|
|
||
|
ULONG ulSendKeyLength = 0;
|
||
|
ULONG ulRecvKeyLength = 0;
|
||
|
|
||
|
// Based on PPP code
|
||
|
ulSendKeyLength = *(((BYTE*)(pAttributeSendKey->Value))+8);
|
||
|
ulRecvKeyLength = *(((BYTE*)(pAttributeRecvKey->Value))+8);
|
||
|
TRACE0 (EAPOL, "Send key = ");
|
||
|
EAPOL_DUMPBA (((BYTE*)(pAttributeSendKey->Value))+9,
|
||
|
ulSendKeyLength);
|
||
|
|
||
|
TRACE0 (EAPOL, "Recv key = ");
|
||
|
EAPOL_DUMPBA (((BYTE*)(pAttributeRecvKey->Value))+9,
|
||
|
ulRecvKeyLength);
|
||
|
|
||
|
pPCB->dwMPPESendKeyLength = ulSendKeyLength;
|
||
|
pPCB->dwMPPERecvKeyLength = ulRecvKeyLength;
|
||
|
|
||
|
//
|
||
|
// Copy MPPE Send and Receive Keys into the PCB for later usage
|
||
|
// These keys will be used to decrypt the global multicast key
|
||
|
// (if any).
|
||
|
//
|
||
|
|
||
|
if (pPCB->dwMPPESendKeyLength != 0)
|
||
|
{
|
||
|
if (pPCB->pbMPPESendKey != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pbMPPESendKey);
|
||
|
pPCB->pbMPPESendKey = NULL;
|
||
|
}
|
||
|
|
||
|
if ((pPCB->pbMPPESendKey = MALLOC (pPCB->dwMPPESendKeyLength))
|
||
|
== NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: Error in Malloc for SendKey");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
memcpy (pPCB->pbMPPESendKey,
|
||
|
((BYTE*)(pAttributeSendKey->Value))+9,
|
||
|
pPCB->dwMPPESendKeyLength);
|
||
|
}
|
||
|
|
||
|
if (pPCB->dwMPPERecvKeyLength != 0)
|
||
|
{
|
||
|
if (pPCB->pbMPPERecvKey != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pbMPPERecvKey);
|
||
|
pPCB->pbMPPERecvKey = NULL;
|
||
|
}
|
||
|
|
||
|
if ((pPCB->pbMPPERecvKey = MALLOC (pPCB->dwMPPERecvKeyLength))
|
||
|
== NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: Error in Malloc for RecvKey");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
memcpy (pPCB->pbMPPERecvKey,
|
||
|
((BYTE*)(pAttributeRecvKey->Value))+9,
|
||
|
pPCB->dwMPPERecvKeyLength);
|
||
|
}
|
||
|
|
||
|
TRACE0 (EAPOL,"MPPE-Send/Recv-Keys set");
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: pAttributeSendKey or pAttributeRecvKey == NULL");
|
||
|
}
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
if (pPCB->pbMPPESendKey != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pbMPPESendKey);
|
||
|
pPCB->pbMPPESendKey = NULL;
|
||
|
}
|
||
|
|
||
|
if (pPCB->pbMPPERecvKey != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pbMPPERecvKey);
|
||
|
pPCB->pbMPPERecvKey = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return( dwRetCode );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElProcessEapSuccess
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called when an EAP_Success is received in any state
|
||
|
//
|
||
|
// Input arguments:
|
||
|
// pPCB - Pointer to PCB for the port on which data is being processed
|
||
|
// pEapolPkt - Pointer to EAPOL packet that was received
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElProcessEapSuccess (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_PACKET *pEapolPkt
|
||
|
)
|
||
|
{
|
||
|
GUID DeviceGuid;
|
||
|
BOOLEAN fAuthenticateAndAuthorized = TRUE;
|
||
|
EAPOL_PACKET_D8_D7 *pDummyHeader;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE0 (EAPOL, "ElProcessEapSuccess: Got EAPCODE_Success");
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
// Indicate to EAP=Dll to cleanup completed session
|
||
|
if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ProcessReceivedPacket: EapSuccess: Error in ElEapEnd = %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->fRemoteEnd8021XD8)
|
||
|
{
|
||
|
fAuthenticateAndAuthorized = FALSE;
|
||
|
|
||
|
pDummyHeader = (EAPOL_PACKET_D8_D7 *)((BYTE *)pEapolPkt - 2);
|
||
|
|
||
|
switch (WireToHostFormat16(pDummyHeader->AuthResultCode))
|
||
|
{
|
||
|
case AUTH_Authorized:
|
||
|
fAuthenticateAndAuthorized = TRUE;
|
||
|
break;
|
||
|
case AUTH_Unauthorized:
|
||
|
fAuthenticateAndAuthorized = FALSE;
|
||
|
break;
|
||
|
default:
|
||
|
fAuthenticateAndAuthorized = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fAuthenticateAndAuthorized)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElProcessEapSuccess: Autho and Authen successful");
|
||
|
|
||
|
// Complete remaining processing i.e. DHCP
|
||
|
if ((dwRetCode = FSMAuthenticated (pPCB,
|
||
|
pEapolPkt)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
// Display change of status using sys tray balloon
|
||
|
// on interface icon
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationSucceeded (&DeviceGuid);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElProcessEapSuccess: Autho and Authen failed");
|
||
|
|
||
|
if ((dwRetCode = FSMHeld (pPCB)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
// Display change of status using sys tray balloon
|
||
|
// on interface icon
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationFailed (&DeviceGuid, 0);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElProcessEapFail
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called when an EAP_Fail is received in any state
|
||
|
//
|
||
|
// Input arguments:
|
||
|
// pPCB - Pointer to PCB for the port on which data is being processed
|
||
|
// pEapolPkt - Pointer to EAPOL packet that was received
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElProcessEapFail (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_PACKET *pEapolPkt
|
||
|
)
|
||
|
{
|
||
|
GUID DeviceGuid;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE0 (EAPOL, "ElProcessEapFail: Got EAPCODE_Failure");
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Indicate to EAP=Dll to cleanup completed session
|
||
|
if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElProcessEapFail: EapFail: Error in ElEapEnd = %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((dwRetCode = FSMHeld (pPCB)) != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
|
||
|
// Display change of status using sys tray balloon
|
||
|
// on interface icon
|
||
|
ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
|
||
|
(VOID)EAPOLMANAuthenticationFailed (&DeviceGuid, 0);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
#undef EAPOL_SERVICE
|