windows-nt/Source/XPSP1/NT/net/layer2svc/eapol/service/eleap.c
2020-09-26 16:20:57 +08:00

2020 lines
57 KiB
C

/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
eleap.c
Abstract:
Module that will do interfacing between the EAPOL engine and the EAP
implementations
Revision History:
sachins, May 04 2000, Created
--*/
#include "pcheapol.h"
#pragma hdrstop
#include <ntlsa.h>
#include <ntmsv1_0.h>
#include <ntsamp.h>
#include <crypt.h>
#include <raseapif.h>
//
// ElLoadEapDlls
//
// Description:
//
// Function called to load all the EAP dlls installed in the PPP
// configuration in the registry
//
// Arguments:
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElLoadEapDlls (
VOID
)
{
HKEY hKeyEap = (HKEY)NULL;
LPWSTR pEapDllPath = (LPWSTR)NULL;
LPWSTR pEapDllExpandedPath = (LPWSTR)NULL;
HKEY hKeyEapDll = (HKEY)NULL;
DWORD dwRetCode;
DWORD dwNumSubKeys;
DWORD dwMaxSubKeySize;
DWORD dwNumValues;
DWORD cbMaxValNameLen;
DWORD cbMaxValueDataSize;
DWORD dwRolesSupported = 0;
DWORD dwSizeOfRolesSupported = 0;
DWORD dwKeyIndex;
WCHAR wchSubKeyName[200];
HINSTANCE hInstance;
FARPROC pRasEapGetInfo;
PPP_EAP_INFO RasEapInfo = {0};
DWORD cbSubKeyName;
DWORD dwSecDescLen;
DWORD cbSize;
DWORD dwType;
DWORD dwEapTypeId;
//
// Open the EAP key
//
dwRetCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
RAS_EAP_REGISTRY_LOCATION,
0,
KEY_READ,
&hKeyEap);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: RegOpenKeyEx failed for HKLM\\RAS_EAP_REGISTRY_LOCATION with error = %ld",
dwRetCode);
return dwRetCode;
}
//
// Find out how many EAP DLLs there are
//
dwRetCode = RegQueryInfoKey (
hKeyEap,
NULL,
NULL,
NULL,
&dwNumSubKeys,
&dwMaxSubKeySize,
NULL,
&dwNumValues,
&cbMaxValNameLen,
&cbMaxValueDataSize,
NULL,
NULL);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: RegQueryInfoKey failed for HKLM\\RAS_EAP_REGISTRY_LOCATION with error = %ld",
dwRetCode);
RegCloseKey (hKeyEap);
return dwRetCode;
}
//
// Allocate space in the table to hold information for each one
//
g_pEapTable= (EAP_INFO*) MALLOC (sizeof(EAP_INFO)*dwNumSubKeys);
if (g_pEapTable == NULL)
{
RegCloseKey (hKeyEap);
return(GetLastError());
}
//
// Read the registry to find out the various EAPs to load.
//
for (dwKeyIndex = 0; dwKeyIndex < dwNumSubKeys; dwKeyIndex++)
{
cbSubKeyName = sizeof(wchSubKeyName)/sizeof(WCHAR);
dwRetCode = RegEnumKeyEx (
hKeyEap,
dwKeyIndex,
wchSubKeyName,
&cbSubKeyName,
NULL,
NULL,
NULL,
NULL);
if ((dwRetCode != NO_ERROR) &&
(dwRetCode != ERROR_NO_MORE_ITEMS))
{
TRACE1 (EAP,"ElLoadEapDlls: RegEnumKeyEx failed for HKLM\\RAS_EAP_REGISTRY_LOCATION with error = %ld",
dwRetCode);
break;
}
else
{
if (dwRetCode == ERROR_NO_MORE_ITEMS)
{
dwRetCode = NO_ERROR;
break;
}
}
do
{
dwRetCode = RegOpenKeyEx (
hKeyEap,
wchSubKeyName,
0,
KEY_QUERY_VALUE,
&hKeyEapDll);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: RegOpenKeyEx failed for HKLM\\RAS_EAP_REGISTRY_LOCATION\\dll with error = %ld",
dwRetCode);
break;
}
//
// Read in the role of the dll
//
dwRolesSupported = RAS_EAP_ROLE_AUTHENTICATEE;
dwSizeOfRolesSupported = sizeof(DWORD);
dwRetCode = RegQueryValueEx (
hKeyEapDll,
RAS_EAP_VALUENAME_ROLES_SUPPORTED,
NULL,
&dwType,
(LPBYTE)&dwRolesSupported,
&dwSizeOfRolesSupported);
if (dwRetCode != NO_ERROR)
{
// If no key, then it is an old dll, assume it will work
// for client
if (dwRetCode == ERROR_FILE_NOT_FOUND)
{
dwRetCode = NO_ERROR;
dwRolesSupported = RAS_EAP_ROLE_AUTHENTICATEE;
}
else
{
TRACE1 (EAP,"ElLoadEapDlls: RegQueryValueEx failed for hKeyEapDll\\RAS_EAP_VALUENAME_ROLES_SUPPORTED with error = %ld",
dwRetCode);
break;
}
}
if (!(dwRolesSupported & RAS_EAP_ROLE_AUTHENTICATEE))
{
TRACE1 (EAP, "ElLoadEapDlls: RolesSupported = (%0lx), not Authenticatee type, ignoring dll",
dwRolesSupported);
break;
}
dwEapTypeId = _wtol (wchSubKeyName);
//
// Find out the size of the path value.
//
dwRetCode = RegQueryInfoKey (
hKeyEapDll,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&cbMaxValNameLen,
&cbMaxValueDataSize,
NULL,
NULL
);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: RegQueryInfoKey failed for hKeyEapDll with error = %ld",
dwRetCode);
break;
}
//
// Allocate space for path and add one for NULL terminator
//
cbMaxValueDataSize += sizeof (WCHAR);
pEapDllPath = (LPWSTR) MALLOC (cbMaxValueDataSize);
if (pEapDllPath == (LPWSTR)NULL)
{
dwRetCode = GetLastError();
break;
}
//
// Read in the path
//
dwRetCode = RegQueryValueEx (
hKeyEapDll,
RAS_EAP_VALUENAME_PATH,
NULL,
&dwType,
(LPBYTE)pEapDllPath,
&cbMaxValueDataSize);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: RegQueryValueEx failed for hKeyEapDll\\RAS_EAP_VALUENAME_PATH with error = %ld",
dwRetCode);
break;
}
if ((dwType != REG_EXPAND_SZ) && (dwType != REG_SZ))
{
dwRetCode = ERROR_REGISTRY_CORRUPT;
TRACE1 (EAP,"ElLoadEapDlls: Registry corrupt for hKeyEapDll\\RAS_EAP_VALUENAME_PATH with error = %ld",
dwRetCode);
break;
}
//
// Replace the %SystemRoot% with the actual path.
//
cbSize = ExpandEnvironmentStrings (pEapDllPath, NULL, 0);
if (cbSize == 0)
{
dwRetCode = GetLastError();
break;
}
pEapDllExpandedPath = (LPWSTR) MALLOC (cbSize*sizeof(WCHAR));
if (pEapDllExpandedPath == (LPWSTR)NULL)
{
dwRetCode = GetLastError();
break;
}
cbSize = ExpandEnvironmentStrings (pEapDllPath,
pEapDllExpandedPath,
cbSize);
if ( cbSize == 0 )
{
dwRetCode = GetLastError();
break;
}
hInstance = LoadLibrary (pEapDllExpandedPath);
if (hInstance == (HINSTANCE)NULL)
{
dwRetCode = GetLastError();
TRACE2 (EAP,"ElLoadEapDlls: LoadLibrary for (%ws) failed with error = %ld",
pEapDllExpandedPath, dwRetCode);
break;
}
pRasEapGetInfo = GetProcAddress (hInstance, "RasEapGetInfo");
if (pRasEapGetInfo == (FARPROC)NULL)
{
dwRetCode = GetLastError();
TRACE1 (EAP,"ElLoadEapDlls: GetProcAddress failed with error = %ld",
dwRetCode);
break;
}
dwRetCode = (DWORD) (*pRasEapGetInfo) (dwEapTypeId,
&RasEapInfo);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: pRasEapGetInfo failed with error = %ld",
dwRetCode);
break;
}
if (RasEapInfo.RasEapInitialize != NULL)
{
dwRetCode = RasEapInfo.RasEapInitialize (
TRUE);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP,"ElLoadEapDlls: RasEapInitialize failed with error = %ld",
dwRetCode);
break;
}
}
g_pEapTable[g_dwNumEapProtocols].hInstance = hInstance;
memcpy ((PVOID)&(g_pEapTable[g_dwNumEapProtocols].RasEapInfo),
(PVOID)&RasEapInfo,
sizeof(PPP_EAP_INFO));
ZeroMemory ((PVOID)&RasEapInfo, sizeof(PPP_EAP_INFO));
g_pEapTable[g_dwNumEapProtocols].RasEapInfo.dwSizeInBytes =
sizeof(PPP_EAP_INFO);
g_dwNumEapProtocols++;
TRACE1 (EAP,"ElLoadEapDlls: Successfully loaded EAP DLL type id = %d",
dwEapTypeId );
} while (FALSE);
if (dwRetCode != NO_ERROR)
{
if (hInstance != NULL)
{
FreeLibrary (hInstance);
}
hInstance = NULL;
}
if (hKeyEapDll != NULL)
{
RegCloseKey (hKeyEapDll);
hKeyEapDll = (HKEY)NULL;
}
if (pEapDllExpandedPath != NULL)
{
FREE( pEapDllExpandedPath );
pEapDllExpandedPath = NULL;
}
if (pEapDllPath != NULL)
{
FREE (pEapDllPath);
pEapDllPath = (LPWSTR)NULL;
}
// Reset error code and continue loading next EAP Dll
dwRetCode = NO_ERROR;
}
if (hKeyEap != (HKEY)NULL)
{
RegCloseKey (hKeyEap);
}
if (hKeyEapDll != (HKEY)NULL)
{
RegCloseKey (hKeyEapDll);
}
if (pEapDllPath != (LPWSTR)NULL)
{
FREE (pEapDllPath);
}
if (pEapDllExpandedPath != NULL)
{
FREE (pEapDllExpandedPath);
}
return dwRetCode;
}
//
// ElEapInit
//
// Description:
// Function called to initialize/uninitialize EAP module.
// In the former case, fInitialize will be TRUE; in the latter case,
// it will be FALSE.
//
// Arguments:
// fInitialize - TRUE - initialize EAP
// FALSE - uninitialize EAP
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElEapInit (
IN BOOL fInitialize
)
{
DWORD dwRetCode = NO_ERROR;
if (fInitialize)
{
// Initialize EAP globals
g_dwNumEapProtocols = 0;
g_pEapTable = NULL;
g_dwEAPUIInvocationId = 1;
if ((dwRetCode = ElLoadEapDlls()) != NO_ERROR)
{
if (g_pEapTable != NULL)
{
FREE (g_pEapTable);
g_pEapTable = NULL;
}
g_dwNumEapProtocols = 0;
return dwRetCode;
}
}
else
{
if (g_pEapTable != NULL)
{
DWORD dwIndex;
//
// Unload loaded DLLs
//
for (dwIndex = 0; dwIndex < g_dwNumEapProtocols; dwIndex++)
{
if (g_pEapTable[dwIndex].hInstance != NULL)
{
if (g_pEapTable[dwIndex].RasEapInfo.RasEapInitialize !=
NULL)
{
dwRetCode = g_pEapTable[dwIndex].RasEapInfo.
RasEapInitialize (
FALSE);
if (dwRetCode != NO_ERROR)
{
TRACE2 (EAP,
"RasEapInitialize(%d) failed and returned %d",
g_pEapTable[dwIndex].RasEapInfo.dwEapTypeId,
dwRetCode);
}
}
FreeLibrary (g_pEapTable[dwIndex].hInstance);
g_pEapTable[dwIndex].hInstance = NULL;
}
}
FREE(g_pEapTable);
g_pEapTable = NULL;
}
g_dwNumEapProtocols = 0;
g_dwEAPUIInvocationId = 1;
}
return (NO_ERROR);
}
//
// EapBegin
//
// Description:
//
// Function called by the EAPOL engine to initialize an EAP session for
// a particular port.
//
// Arguments:
// pPCB - Pointer to PCB for port on which EAP is to be initialized
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElEapBegin (
IN EAPOL_PCB *pPCB
)
{
DWORD dwRetCode = NO_ERROR;
TRACE0 (EAP,"ElEapBegin entered");
if (pPCB->dwEapTypeToBeUsed != -1)
{
//
// First check if we support this EAP type
//
if (ElGetEapTypeIndex((BYTE)(pPCB->dwEapTypeToBeUsed)) == -1)
{
TRACE0 (EAP, "ElEapBegin: EAPType not supported");
return (ERROR_NOT_SUPPORTED);
}
}
pPCB->fEapInitialized = TRUE;
TRACE0 (EAP,"ElEapBegin done");
return (NO_ERROR);
}
//
// ElEapEnd
//
// Description:
//
// Function called to end the Eap session initiated by an ElEapBegin.
// Called when port goes down
//
// Arguments:
// pPCB - Pointer to the PCB for the port on which EAP session is to be
// shut-down.
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElEapEnd (
IN EAPOL_PCB *pPCB
)
{
DWORD dwRetCode = NO_ERROR;
TRACE0 (EAP,"ElEapEnd entered");
if ((pPCB == NULL) || (!(pPCB->fEapInitialized)))
{
return( NO_ERROR );
}
if ((dwRetCode = ElEapDllEnd (pPCB)) != NO_ERROR)
{
TRACE1 (EAP, "ElEapEnd: Error in ElEapDllEnd %ld", dwRetCode);
}
if (pPCB->EapUIData.pEapUIData != NULL)
{
FREE( pPCB->EapUIData.pEapUIData );
pPCB->EapUIData.pEapUIData = NULL;
}
pPCB->fEapInitialized = FALSE;
return (NO_ERROR);
}
//
// ElEapExtractMessage
//
// Description:
//
// If there is any message in the Request/Notification packet, then
// save the string in pResult->pszReplyMessage
//
// Arguments:
// pReceiveBuf - Pointer to EAP packet received
// pResult - Pointer to result structure
//
// Return values:
//
VOID
ElEapExtractMessage (
IN PPP_EAP_PACKET *pReceiveBuf,
OUT ELEAP_RESULT *pResult
)
{
DWORD dwNumBytes = 0;
CHAR* pszReplyMessage = NULL;
WORD cbPacket;
do
{
cbPacket = WireToHostFormat16 (pReceiveBuf->Length);
if (PPP_EAP_PACKET_HDR_LEN + 1 >= cbPacket)
{
TRACE2 (EAP, "ElEapExtractMessage: Packet length %ld less than minimum %ld",
cbPacket, PPP_EAP_PACKET_HDR_LEN+1);
break;
}
dwNumBytes = cbPacket - PPP_EAP_PACKET_HDR_LEN - 1;
//
// One more for the terminating NULL.
//
pszReplyMessage = (CHAR *) MALLOC (dwNumBytes+1);
if (pszReplyMessage == NULL)
{
TRACE0 (EAP, "ElEapExtractMessage: MALLOC failed. Cannot extract server's message." );
break;
}
CopyMemory (pszReplyMessage, pReceiveBuf->Data + 1, dwNumBytes);
pszReplyMessage[dwNumBytes] = '\0';
// FREE( pResult->pszReplyMessage );
pResult->pszReplyMessage = pszReplyMessage;
pszReplyMessage = NULL;
} while (FALSE);
return;
}
//
// ElParseIdentityString
//
// Description:
// Parse the identity string
//
// Arguments:
// pReceiveBuf - Pointer to EAP packet received
// pPCB - Pointer to PCB for port on which data is being processed
//
// Return values:
//
DWORD
ElParseIdentityString (
IN PPP_EAP_PACKET *pReceiveBuf,
IN OUT EAPOL_PCB *pPCB
)
{
DWORD dwNumBytes = 0;
WORD cbPacket = 0;
CHAR *pszLocalIdString = NULL;
WCHAR *pwszLocalIdString = NULL;
WCHAR *pwszDisplayString = NULL;
WCHAR *pwszDisplayStringEnd = NULL;
WCHAR *pwszTupleValueStart = NULL;
WCHAR *pwszTupleTypeStart = NULL;
WCHAR *pwszTupleTypeEnd = NULL;
WCHAR *pwszTupleValueEnd = NULL;
WCHAR *pwszNetworkId = NULL;
DWORD dwNetworkIdLen = 0;
WCHAR *pwszNASId = NULL;
WCHAR *pwszPortId = NULL;
WCHAR *pwczNetworkId = L"NetworkId";
WCHAR *pwczNASId = L"NASId";
WCHAR *pwczPortId = L"PortId";
LOCATION_802_1X location;
EAPOL_INTF_PARAMS EapolIntfParams;
DWORD dwRetCode = NO_ERROR;
do
{
cbPacket = WireToHostFormat16 (pReceiveBuf->Length);
if (PPP_EAP_PACKET_HDR_LEN + 1 >= cbPacket)
{
TRACE2 (EAP, "ElParseIdentityString: Packet length %ld less than minimum %ld",
cbPacket, PPP_EAP_PACKET_HDR_LEN+1);
break;
}
dwNumBytes = cbPacket - PPP_EAP_PACKET_HDR_LEN - 1;
pszLocalIdString = MALLOC (dwNumBytes + 2);
if (pszLocalIdString == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed for pszLocalIdString");
break;
}
pwszLocalIdString = MALLOC ((dwNumBytes + 2)*sizeof(WCHAR));
if (pwszLocalIdString == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed for pwszLocalIdString");
break;
}
memcpy (pszLocalIdString, pReceiveBuf->Data + 1, dwNumBytes);
pszLocalIdString[dwNumBytes] = '\0';
if (0 == MultiByteToWideChar (
CP_ACP,
0,
pszLocalIdString,
dwNumBytes+1,
pwszLocalIdString,
dwNumBytes + 2))
{
dwRetCode = GetLastError();
TRACE2 (EAP,"ElParseIdentityString: MultiByteToWideChar(%s) failed for pszLocalIdString with error (%ld)",
pszLocalIdString,
dwRetCode);
break;
}
pwszDisplayStringEnd = wcschr (pwszLocalIdString, L'\0');
if (pwszDisplayStringEnd == NULL)
{
dwRetCode = ERROR_INVALID_DATA;
TRACE0 (EAP, "ElParseIdentityString: Identity string does not contain mandatory NULL character");
break;
}
pwszDisplayString = MALLOC ((pwszDisplayStringEnd - pwszLocalIdString + 1) * sizeof(WCHAR));
if (pwszDisplayString == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed for pwszDisplayString");
break;
}
wcscpy (pwszDisplayString, pwszLocalIdString);
TRACE1 (EAP, "ElParseIdentityString: DisplayString = %ws",
pwszDisplayString);
TRACE1 (EAP, "ElParseIdentityString: LocalIdString = %ws",
pwszDisplayStringEnd+1);
TRACE1 (EAP, "ElParseIdentityString: LocalIdString Length = %ld",
dwNumBytes);
// If only Display String is received, bail out
if (pwszDisplayStringEnd == (pwszLocalIdString+dwNumBytes))
{
dwRetCode = NO_ERROR;
TRACE0 (EAP, "ElParseIdentityString: Identity string does not contain tuples");
break;
}
pwszTupleTypeStart = pwszDisplayStringEnd + 1;
while (TRUE)
{
pwszTupleTypeEnd = wcschr (pwszTupleTypeStart, L'=');
if (!(_wcsnicmp (pwszTupleTypeStart, pwczNetworkId, wcslen(pwczNetworkId))))
{
pwszTupleValueStart = pwszTupleTypeEnd + 1;
pwszTupleValueEnd = wcschr (pwszTupleValueStart, L',');
if (pwszTupleValueEnd == NULL)
{
// End-of-string
pwszTupleValueEnd = &pwszLocalIdString[dwNumBytes];
}
TRACE1 (ANY, "ElParseIdentityString: NetworkID Size = %ld",
pwszTupleValueEnd - pwszTupleValueStart + 1);
pwszNetworkId =
MALLOC ((pwszTupleValueEnd - pwszTupleValueStart + 1)*sizeof(WCHAR));
if (pwszNetworkId == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed for pwszNetworkId");
break;
}
memcpy ((VOID *)pwszNetworkId, (VOID *)pwszTupleValueStart, (pwszTupleValueEnd - pwszTupleValueStart)*sizeof(WCHAR));
pwszNetworkId[pwszTupleValueEnd - pwszTupleValueStart] = L'\0';
dwNetworkIdLen = (DWORD)(pwszTupleValueEnd - pwszTupleValueStart);
TRACE1 (EAP, "Got NetworkId = %ws", pwszNetworkId);
}
else
{
if (!(_wcsnicmp (pwszTupleTypeStart, pwczNASId, wcslen (pwczNASId))))
{
pwszTupleValueStart = pwszTupleTypeEnd + 1;
pwszTupleValueEnd = wcschr (pwszTupleValueStart, L',');
if (pwszTupleValueEnd == NULL)
{
// End-of-string
pwszTupleValueEnd = &pwszLocalIdString[dwNumBytes];
}
pwszNASId = MALLOC ((pwszTupleValueEnd - pwszTupleValueStart + 1) * sizeof(WCHAR));
if (pwszNASId == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed for pwszNASId");
break;
}
memcpy ((VOID *)pwszNASId, (VOID *)pwszTupleValueStart, (pwszTupleValueEnd - pwszTupleValueStart)*sizeof(WCHAR));
pwszNASId[(pwszTupleValueEnd - pwszTupleValueStart)] = L'\0';
TRACE1 (EAP, "Got NASId = %ws", pwszNASId);
}
else
{
if (!(_wcsnicmp (pwszTupleTypeStart, pwczPortId, wcslen (pwczPortId))))
{
pwszTupleValueStart = pwszTupleTypeEnd + 1;
pwszTupleValueEnd = wcschr (pwszTupleValueStart, L',');
if (pwszTupleValueEnd == NULL)
{
// End-of-string
pwszTupleValueEnd = &pwszLocalIdString[dwNumBytes];
}
TRACE1 (EAP, "ElParseIdentityString: For PortId, length = %ld",
pwszTupleValueEnd - pwszTupleValueStart);
pwszPortId = MALLOC ((pwszTupleValueEnd - pwszTupleValueStart + 1) * sizeof(WCHAR));
if (pwszPortId == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed for pwszPortId");
break;
}
memcpy ((VOID *)pwszPortId, (VOID *)pwszTupleValueStart, (pwszTupleValueEnd - pwszTupleValueStart)*sizeof(WCHAR));
pwszPortId[pwszTupleValueEnd - pwszTupleValueStart] = L'\0';
TRACE1 (EAP, "Got PortId = %ws", pwszPortId);
}
else
{
dwRetCode = ERROR_INVALID_DATA;
TRACE0 (EAP, "ElParseIdentityString: Invalid tuple type");
break;
}
}
}
if (*pwszTupleValueEnd == L'\0')
{
TRACE0 (EAP, "ElParseIdentityString: End of String reached");
break;
}
else
{
// Position pointer beyond ','
pwszTupleTypeStart = pwszTupleValueEnd+1;
}
}
TRACE0 (EAP, "ElParseIdentityString: Out of while loop");
if (dwRetCode != NO_ERROR)
{
break;
}
TRACE0 (EAP, "ElParseIdentityString: Out of while loop: NO ERROR");
// Mandatory tuples
if (pwszNetworkId == NULL)
{
dwRetCode = ERROR_INVALID_DATA;
TRACE0 (EAP, "ElParseIdentityString: Invalid NetworkId = NULL");
break;
}
// Network is the SSID for wired networks
if (pPCB->PhysicalMediumType != NdisPhysicalMediumWirelessLan)
{
pPCB->fAuthenticationOnNewNetwork = FALSE;
// Free previous instance of SSID if any
if (pPCB->pwszSSID != NULL)
{
// Verify if NetworkId has changed i.e. we are on a new network
if (wcscmp (pPCB->pwszSSID, pwszNetworkId))
{
pPCB->fAuthenticationOnNewNetwork = TRUE;
TRACE2 (EAP, "ElParseIdentityString: SSIDs are different, old= %ws, new= %ws",
pPCB->pwszSSID, pwszNetworkId);
}
FREE (pPCB->pwszSSID);
pPCB->pwszSSID = NULL;
}
// New instance of SSID will be freed either on receipt of next SSID
// or user logoff
pPCB->pwszSSID =
(WCHAR *) MALLOC((wcslen(pwszNetworkId) + 1)*sizeof(WCHAR));
if (pPCB->pwszSSID == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElParseIdentityString: MALLOC failed. Cannot extract SSID" );
break;
}
if (pPCB->pSSID)
{
FREE (pPCB->pSSID);
pPCB->pSSID = NULL;
}
if ((dwNetworkIdLen > 0) && (dwNetworkIdLen <= MAX_SSID_LEN))
{
if ((pPCB->pSSID = MALLOC (NDIS_802_11_SSID_LEN)) == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (PORT, "ElParseIdentityString: MALLOC failed for pSSID");
break;
}
if (0 == WideCharToMultiByte (
CP_ACP,
0,
pwszNetworkId,
dwNetworkIdLen,
pPCB->pSSID->Ssid,
dwNetworkIdLen,
NULL,
NULL ))
{
dwRetCode = GetLastError();
TRACE2 (ANY, "ElParseIdentityString: WideCharToMultiByte (%ws) failed for SSID: (%ld)",
pwszNetworkId, dwRetCode);
break;
}
pPCB->pSSID->SsidLength = dwNetworkIdLen;
wcscpy (pPCB->pwszSSID, pwszNetworkId);
}
// Retrieve the current interface params
ZeroMemory ((BYTE *)&EapolIntfParams, sizeof(EAPOL_INTF_PARAMS));
EapolIntfParams.dwEapFlags = DEFAULT_EAP_STATE;
EapolIntfParams.dwEapType = DEFAULT_EAP_TYPE;
if (pPCB->pSSID != NULL)
{
memcpy (EapolIntfParams.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
EapolIntfParams.dwSizeOfSSID = pPCB->pSSID->SsidLength;
}
if ((dwRetCode = ElGetInterfaceParams (
pPCB->pwszDeviceGUID,
&EapolIntfParams
)) != NO_ERROR)
{
TRACE1 (PORT, "ElParseIdentityString: ElGetInterfaceParams failed with error %ld",
dwRetCode);
if (dwRetCode == ERROR_FILE_NOT_FOUND)
{
pPCB->dwEapFlags = DEFAULT_EAPOL_STATE;
pPCB->dwEapTypeToBeUsed = DEFAULT_EAP_TYPE;
dwRetCode = NO_ERROR;
}
else
{
break;
}
}
else
{
pPCB->dwEapFlags = EapolIntfParams.dwEapFlags;
pPCB->dwEapTypeToBeUsed = EapolIntfParams.dwEapType;
}
if (!IS_EAPOL_ENABLED(pPCB->dwEapFlags))
{
TRACE0 (PORT, "ElParseIdentityString: Marking port as disabled");
pPCB->dwFlags &= ~EAPOL_PORT_FLAG_ACTIVE;
pPCB->dwFlags |= EAPOL_PORT_FLAG_DISABLED;
}
TRACE1 (EAP, "ElParseIdentityString: Got SSID %ws", pPCB->pwszSSID);
}
//
// Send type=value tuple string to NLA for processing
//
RtlZeroMemory(&location, sizeof(location));
if (0 == WideCharToMultiByte (
CP_ACP,
0,
pPCB->pwszDeviceGUID,
-1,
location.adapterName,
wcslen(pPCB->pwszDeviceGUID)+1,
NULL,
NULL ))
{
dwRetCode = GetLastError();
TRACE2 (ANY, "ElParseIdentityString: WideCharToMultiByte (%ws) failed: (%ld)",
pPCB->pwszDeviceGUID, dwRetCode);
break;
}
location.adapterName[wcslen(pPCB->pwszDeviceGUID)] = '\0';
wcsncpy (location.information, pwszDisplayStringEnd + 1, 2048);
TRACE2 (EAP, "ElParseIdentityString: Calling NLARegister_802_1X with params %ws and %ws",
pPCB->pwszDeviceGUID, location.information);
ElNLARegister_802_1X(&location);
TRACE0 (EAP, "ElParseIdentityString: Returned after calling NLARegister_802_1X");
} while (FALSE);
if (pszLocalIdString != NULL)
{
FREE (pszLocalIdString);
}
if (pwszLocalIdString != NULL)
{
FREE (pwszLocalIdString);
}
if (pwszDisplayString != NULL)
{
FREE (pwszDisplayString);
}
if (pwszNetworkId != NULL)
{
FREE (pwszNetworkId);
}
if (pwszNASId != NULL)
{
FREE (pwszNASId);
}
if (pwszPortId != NULL)
{
FREE (pwszPortId);
}
return dwRetCode;
}
//
// ElEapMakeMessage
//
// Description:
//
// Function called to process a received EAP packet and/or to send
// out an EAP packet.
//
// Arguments:
// pPCB - Pointer to PCB for the port on which data is being processed
// pReceiveBuf - Pointer to EAP Packet that was received
// pSendBuf - output: Pointer to buffer created to hold output EAP packet
// dwSizeOfSendBuf - Number of bytes pSendBuf is allocated
// pResult - output: result structure containing various results of EAP
// processing
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElEapMakeMessage (
IN EAPOL_PCB *pPCB,
IN PPP_EAP_PACKET *pReceiveBuf,
IN OUT PPP_EAP_PACKET *pSendBuf,
IN DWORD dwSizeOfSendBuf,
OUT ELEAP_RESULT *pResult
)
{
DWORD dwIdentityLength = 0;
DWORD dwRetCode = NO_ERROR;
TRACE0 (EAP,"ElEapMakeMessage entered");
if ((pReceiveBuf != NULL) && (pReceiveBuf->Code == EAPCODE_Request))
{
//
// Always respond to notitication request, with a notification response
//
if (pReceiveBuf->Data[0] == EAPTYPE_Notification)
{
pSendBuf->Code = EAPCODE_Response;
pSendBuf->Id = pReceiveBuf->Id;
HostToWireFormat16 (PPP_EAP_PACKET_HDR_LEN + 1, pSendBuf->Length);
pSendBuf->Data[0] = EAPTYPE_Notification;
pResult->Action = ELEAP_Send;
// Indicate to EAPOL what is length of the EAP packet
pResult->wSizeOfEapPkt = PPP_EAP_PACKET_HDR_LEN + 1;
// Extract the notification message from server and save
// it in the result struct for display to the user
ElEapExtractMessage (pReceiveBuf, pResult);
return (NO_ERROR);
}
//
// Always respond to Identity request, with an Identity response
//
if (pReceiveBuf->Data[0] == EAPTYPE_Identity)
{
// Extract SSID out of the body of the received packet
// and save it in the SSID field of the PCB
// Also, save the SSID received as the last used SSID
if ((dwRetCode = ElParseIdentityString (
pReceiveBuf,
pPCB)) != NO_ERROR)
{
TRACE1 (EAP, "ElEapMakeMessage: Error in ElParseIdentityString = %ld",
dwRetCode);
return dwRetCode;
}
// Check if Identity is being fetched for same EAP-Id
if ((pReceiveBuf->Id == pPCB->bCurrentEAPId) &&
(pPCB->EapUIState == EAPUISTATE_WAITING_FOR_IDENTITY))
{
// Restart PCB timer since authtimer has already been set
RESTART_TIMER (pPCB->hTimer,
INFINITE_SECONDS,
"PCB",
&dwRetCode);
if (dwRetCode != NO_ERROR)
{
TRACE1 (EAP, "ElEapMakeMessage: RESTART_TIMER during re-xmit failed with error %ld",
dwRetCode);
}
TRACE0 (EAP, "ElEapMakeMessage: Ignoring re-transmit while waiting for Identity UI");
return (dwRetCode);
};
pPCB->bCurrentEAPId = pReceiveBuf->Id;
if ((dwRetCode = ElGetIdentity (
pPCB)) != NO_ERROR)
{
TRACE1 (EAP, "ElEapMakeMessage: Error in ElGetIdentity %ld",
dwRetCode);
return dwRetCode;
}
pSendBuf->Code = EAPCODE_Response;
pSendBuf->Id = pReceiveBuf->Id;
if (pPCB->pszIdentity != NULL)
{
dwIdentityLength = strlen (pPCB->pszIdentity);
}
else
{
dwIdentityLength = 0;
}
HostToWireFormat16 (
(WORD)(PPP_EAP_PACKET_HDR_LEN+1+dwIdentityLength),
pSendBuf->Length );
strncpy ((CHAR *)pSendBuf->Data+1, (CHAR *)pPCB->pszIdentity,
dwIdentityLength);
TRACE1 (EAPOL, "Identity sent out = %s", pPCB->pszIdentity);
pSendBuf->Data[0] = EAPTYPE_Identity;
pResult->Action = ELEAP_Send;
// Indicate to EAPOL what is length of the EAP packet
pResult->wSizeOfEapPkt = (WORD)(PPP_EAP_PACKET_HDR_LEN+
1+dwIdentityLength);
return( NO_ERROR );
}
}
return
ElMakeSupplicantMessage (
pPCB, pReceiveBuf, pSendBuf, dwSizeOfSendBuf, pResult);
}
//
// ElMakeSupplicantMessage
//
// Description:
//
// EAP Supplicant engine. Can be part of ElEapMakeMessage, but separated for
// readability
//
// Arguments:
// pPCB - Pointer to PCB for the port on which data is being processed
// pReceiveBuf - Pointer to EAP Packet that was received
// pSendBuf - output: Pointer to buffer created to hold output EAP packet
// dwSizeOfSendBuf - Number of bytes pSendBuf is allocated
// pResult - output: result structure containing various results of EAP
// processing
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElMakeSupplicantMessage (
IN EAPOL_PCB *pPCB,
IN PPP_EAP_PACKET* pReceiveBuf,
IN OUT PPP_EAP_PACKET* pSendBuf,
IN DWORD dwSizeOfSendBuf,
IN OUT ELEAP_RESULT* pResult
)
{
DWORD dwEapIndex;
DWORD dwRetCode = NO_ERROR;
TRACE0 (EAP,"ElMakeSupplicantMessage entered");
switch (pPCB->EapState)
{
case EAPSTATE_Initial:
TRACE0 (EAP,"EAPSTATE_Initial");
if (pReceiveBuf == NULL)
{
//
// Do nothing. Wait for request from authenticator
//
TRACE0 (EAP, "ElMakeSupplicantMessage: Received NULL EAP pkt, No Action");
pResult->Action = ELEAP_NoAction;
break;
}
else
{
if (pReceiveBuf->Code != EAPCODE_Request)
{
//
// We are authenticatee side so drop everything other than
// requests, since we do not send requests
//
pResult->Action = ELEAP_NoAction;
break;
}
//
// We got a packet, see if we support this EAP type, also that
// we are authorized to use it
//
dwEapIndex = ElGetEapTypeIndex (pReceiveBuf->Data[0]);
if ((dwEapIndex == -1) ||
((pPCB->dwEapTypeToBeUsed != -1) &&
(dwEapIndex != ElGetEapTypeIndex (pPCB->dwEapTypeToBeUsed))))
{
//
// We do not support this type or we are not authorized to use
// it so we NAK with a type we support
//
pSendBuf->Code = EAPCODE_Response;
pSendBuf->Id = pReceiveBuf->Id;
HostToWireFormat16 (PPP_EAP_PACKET_HDR_LEN + 2,
pSendBuf->Length);
pSendBuf->Data[0] = EAPTYPE_Nak;
if (pPCB->dwEapTypeToBeUsed != -1)
{
pSendBuf->Data[1] = (BYTE)pPCB->dwEapTypeToBeUsed;
}
else
{
pSendBuf->Data[1] =
(BYTE)g_pEapTable[0].RasEapInfo.dwEapTypeId;
}
pResult->Action = ELEAP_Send;
TRACE2 (EAP, "ElMakeSupplicantMessage: Send NAK, Got EAP type (%ld), Expected (%ld)",
pReceiveBuf->Data[0], pPCB->dwEapTypeToBeUsed);
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
EAPOL_INVALID_EAP_TYPE,
pReceiveBuf->Data[0], pPCB->dwEapTypeToBeUsed);
break;
}
else
{
//
// The EAP type is acceptable to us so we begin authentication
//
if ((dwRetCode = ElEapDllBegin (pPCB, dwEapIndex)) != NO_ERROR)
{
break;
}
pPCB->EapState = EAPSTATE_Working;
//
// Fall thru
//
}
}
case EAPSTATE_Working:
TRACE0 (EAP,"EAPSTATE_Working");
if (pReceiveBuf != NULL)
{
if ((pReceiveBuf->Code != EAPCODE_Request) &&
(pReceiveBuf->Code != EAPCODE_Success) &&
(pReceiveBuf->Code != EAPCODE_Failure))
{
//
// We are supplicant side so drop everything other than
// request/success/failure
//
TRACE0 (EAP,"ElMakeSupplicantMessage: Dropping invalid packet not request/success/failure");
pResult->Action = ELEAP_NoAction;
break;
}
if ((pReceiveBuf->Code == EAPCODE_Request) &&
(pReceiveBuf->Data[0] !=
g_pEapTable[pPCB->dwEapIndex].RasEapInfo.dwEapTypeId))
{
TRACE0 (EAP,"ElMakeSupplicantMessage: Dropping invalid request packet with unknown Id");
pResult->Action = ELEAP_NoAction;
break;
}
}
dwRetCode = ElEapDllWork (pPCB,
pReceiveBuf,
pSendBuf,
dwSizeOfSendBuf,
pResult
);
break;
default:
TRACE0 (EAP, "ElMakeSupplicantMessage: Invalid EAP State");
break;
}
return dwRetCode;
}
//
//
// ElEapDllBegin
//
// Description:
//
// Function called to initiate an EAP session for a certain EAP type
//
// Arguments:
// pPCB - Pointer to PCB for the port in context
// dwEapIndex - EAP type for which a session has to be started
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
//
DWORD
ElEapDllBegin (
IN EAPOL_PCB *pPCB,
IN DWORD dwEapIndex
)
{
PPP_EAP_INPUT PppEapInput;
WCHAR *pwszIdentity = NULL;
DWORD dwIdentityLength = 0;
WCHAR *pwszPassword = NULL;
BOOLEAN fRevertToSelf = FALSE;
DWORD dwPasswordLen = 0;
DWORD dwRetCode = NO_ERROR;
TRACE1 (EAP,"ElEapDllBegin called for EAP Type %d",
g_pEapTable[dwEapIndex].RasEapInfo.dwEapTypeId);
do
{
// Format the identity string correctly.
// For EAP-TLS, it will be the identity on the chosen certificate
// For EAP-CHAP, it will be domain\username
if (pPCB->pszIdentity != NULL)
{
dwIdentityLength = strlen (pPCB->pszIdentity);
}
else
{
dwIdentityLength = 0;
}
pwszIdentity = MALLOC ((dwIdentityLength+2) * sizeof(WCHAR));
if (pwszIdentity == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElEapDllBegin: MALLOC failed for pwszIdentity");
break;
}
if (dwIdentityLength > 0)
{
if (0 == MultiByteToWideChar (
CP_ACP,
0,
pPCB->pszIdentity,
-1,
pwszIdentity,
dwIdentityLength+2))
{
dwRetCode = GetLastError();
TRACE2 (EAP,"MultiByteToWideChar(%s) failed: %d",
pPCB->pszIdentity,
dwRetCode);
break;
}
}
else
{
pwszIdentity[0] = L'\0';
}
// Unhash password stored locally
if (pPCB->PasswordBlob.cbData > 0)
{
// Impersonate the user first, since the password has been
// encrypted using the password
if (!ImpersonateLoggedOnUser (pPCB->hUserToken))
{
dwRetCode = GetLastError ();
TRACE1 (EAP, "ElEapDllBegin: ImpersonateLoggedOnUser failed with error %ld",
dwRetCode);
break;
}
fRevertToSelf = TRUE;
if ((dwRetCode = ElSecureDecodePw (
&(pPCB->PasswordBlob),
&((BYTE *)pwszPassword),
&dwPasswordLen
)) != NO_ERROR)
{
TRACE1 (EAP, "ElEapDllBegin: ElSecureDecodePw failed with error %ld",
dwRetCode);
break;
}
fRevertToSelf = FALSE;
if (!RevertToSelf ())
{
dwRetCode = GetLastError ();
TRACE1 (EAP, "ElEapDllBegin: RevertToSelf failed with error %ld",
dwRetCode);
dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL;
break;
}
}
else
{
pwszPassword = MALLOC (sizeof(WCHAR));
if (pwszPassword == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (EAP, "ElEapDllBegin: MALLOC failed for pwszPassword");
break;
}
pwszPassword[0] = L'\0';
}
ZeroMemory (&PppEapInput, sizeof (PppEapInput));
PppEapInput.dwSizeInBytes = sizeof (PPP_EAP_INPUT);
if (IS_MACHINE_AUTH_ENABLED(pPCB->dwEapFlags))
{
// Set flag to indicate machine cert is to be picked up for machine
// authentication
if (pPCB->PreviousAuthenticationType ==
EAPOL_MACHINE_AUTHENTICATION)
{
TRACE0 (EAP, "ElEapDllBegin: Going for machine authentication");
PppEapInput.fFlags |= RAS_EAP_FLAG_MACHINE_AUTH;
}
}
if (IS_GUEST_AUTH_ENABLED(pPCB->dwEapFlags))
{
if (pPCB->pszIdentity == NULL)
{
PppEapInput.fFlags |= RAS_EAP_FLAG_GUEST_ACCESS;
}
}
PppEapInput.fFlags |= RAS_EAP_FLAG_8021X_AUTH;
PppEapInput.fAuthenticator = FALSE; // Always supplicant
PppEapInput.pwszIdentity = pwszIdentity;
PppEapInput.pwszPassword = pwszPassword;
PppEapInput.hTokenImpersonateUser = pPCB->hUserToken;
PppEapInput.fAuthenticationComplete = FALSE;
PppEapInput.dwAuthResultCode = NO_ERROR;
if (pPCB->pCustomAuthConnData != NULL)
{
if (pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData != 0)
{
PppEapInput.pConnectionData =
pPCB->pCustomAuthConnData->pbCustomAuthData;
PppEapInput.dwSizeOfConnectionData =
pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData;
}
}
if (pPCB->pCustomAuthUserData != NULL)
{
if (pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData != 0)
{
PppEapInput.pUserData =
pPCB->pCustomAuthUserData->pbCustomAuthData;
PppEapInput.dwSizeOfUserData =
pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData;
}
}
if (pPCB->EapUIData.pEapUIData != NULL)
{
PppEapInput.pDataFromInteractiveUI =
pPCB->EapUIData.pEapUIData;
PppEapInput.dwSizeOfDataFromInteractiveUI =
pPCB->EapUIData.dwSizeOfEapUIData;
}
if (pPCB->dwEapTypeToBeUsed == EAP_TYPE_TLS)
{
if ((dwRetCode = ElLogCertificateDetails (pPCB))
== ERROR_BAD_IMPERSONATION_LEVEL)
{
TRACE0 (EAP, "ElEapDllBegin: ElLogCertificateDetails failed with RevertToSelf error");
break;
}
dwRetCode = NO_ERROR;
}
// Call the RasEapBegin API
dwRetCode = g_pEapTable[dwEapIndex].RasEapInfo.RasEapBegin (
&pPCB->lpEapDllWorkBuffer,
&PppEapInput);
if (pwszPassword != NULL)
{
FREE (pwszPassword);
pwszPassword = NULL;
}
if (dwRetCode == NO_ERROR)
{
pPCB->dwEapIndex = dwEapIndex;
}
else
{
TRACE1 (EAP, "ElEapDllBegin: RasEapBegin failed with error %ld",
dwRetCode);
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
EAPOL_ERROR_AUTH_PROCESSING, dwRetCode);
pPCB->dwEapIndex = (DWORD)-1;
}
}
while (FALSE);
if (fRevertToSelf)
{
if (!RevertToSelf ())
{
dwRetCode = GetLastError ();
TRACE1 (EAP, "ElEapDllBegin: RevertToSelf failed with error %ld",
dwRetCode);
dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL;
}
}
if (pwszPassword != NULL)
{
FREE (pwszPassword);
}
if (pwszIdentity != NULL)
{
FREE (pwszIdentity);
}
return dwRetCode;
}
//
// ElEapDllEnd
//
// Description:
//
// Function called to end an EAP session
//
// Arguments:
// pPCB - Pointer to the PCB for the port in context
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElEapDllEnd (
EAPOL_PCB *pPCB
)
{
DWORD dwRetCode = NO_ERROR;
TRACE1 (EAP, "ElEapDllEnd called for EAP Index %d", pPCB->dwEapIndex );
if (pPCB->lpEapDllWorkBuffer != NULL)
{
if (pPCB->dwEapIndex != (DWORD)-1)
{
dwRetCode = g_pEapTable[pPCB->dwEapIndex].RasEapInfo.RasEapEnd (
pPCB->lpEapDllWorkBuffer);
}
pPCB->lpEapDllWorkBuffer = NULL;
}
pPCB->dwEapIndex = (DWORD)-1;
pPCB->EapState = EAPSTATE_Initial;
return dwRetCode;
}
//
// ElEapDllWork
//
// Description:
//
// Function called to process an incoming packet or timeout etc
// The RasEapMakeMessage entrypoint in the appropriate EAP DLL is called
// to process the packet.
//
// Arguments:
// pPCB - Pointer to PCB for the port on which data is being processed
// pReceiveBuf - Pointer to EAP Packet that was received
// pSendBuf - output: Pointer to buffer created to hold output EAP packet
// dwSizeOfSendBuf - Number of bytes pSendBuf is allocated
// pResult - output: result structure containing various results of EAP
// processing
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElEapDllWork (
IN EAPOL_PCB *pPCB,
IN PPP_EAP_PACKET *pReceiveBuf,
IN OUT PPP_EAP_PACKET *pSendBuf,
IN DWORD dwSizeOfSendBuf,
IN OUT ELEAP_RESULT *pResult
)
{
PPP_EAP_OUTPUT PppEapOutput;
PPP_EAP_INPUT PppEapInput;
CHAR * pChar = NULL;
DWORD dwRetCode = NO_ERROR;
TRACE1 (EAP, "ElEapDllWork called for EAP Type %d",
g_pEapTable[pPCB->dwEapIndex].RasEapInfo.dwEapTypeId);
ZeroMemory (&PppEapOutput, sizeof (PppEapOutput));
PppEapOutput.dwSizeInBytes = sizeof (PppEapOutput);
ZeroMemory (&PppEapInput, sizeof (PppEapInput));
PppEapInput.dwSizeInBytes = sizeof (PPP_EAP_INPUT);
PppEapInput.fAuthenticator = FALSE; // We are always supplicant
PppEapInput.hTokenImpersonateUser = pPCB->hUserToken;
if (pPCB->fEapUIDataReceived)
{
if (pPCB->EapUIData.dwContextId != pPCB->dwUIInvocationId)
{
// Ignore this data received
pPCB->fEapUIDataReceived = FALSE;
TRACE0 (EAP,"ElEapDllWork: Out of date data received from UI");
return(NO_ERROR);
}
PppEapInput.fDataReceivedFromInteractiveUI = TRUE;
PppEapInput.pDataFromInteractiveUI =
pPCB->EapUIData.pEapUIData;
PppEapInput.dwSizeOfDataFromInteractiveUI =
pPCB->EapUIData.dwSizeOfEapUIData;
pPCB->fEapUIDataReceived = FALSE;
}
dwRetCode = g_pEapTable[pPCB->dwEapIndex].RasEapInfo.RasEapMakeMessage (
pPCB->lpEapDllWorkBuffer,
(PPP_EAP_PACKET *)pReceiveBuf,
(PPP_EAP_PACKET *)pSendBuf,
dwSizeOfSendBuf,
&PppEapOutput,
&PppEapInput);
// Free InvokeInteractive UI data since we no longer need it
if (pPCB->EapUIData.pEapUIData != NULL)
{
FREE (pPCB->EapUIData.pEapUIData);
pPCB->EapUIData.pEapUIData = NULL;
}
if (dwRetCode != NO_ERROR)
{
switch (dwRetCode)
{
case ERROR_PPP_INVALID_PACKET:
TRACE0 (EAP,"Silently discarding invalid EAP packet");
pResult->Action = ELEAP_NoAction;
return (NO_ERROR);
default:
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
EAPOL_ERROR_AUTH_PROCESSING, dwRetCode);
TRACE2 (EAP,"EapDLLMakeMessage for type %d returned %d",
g_pEapTable[pPCB->dwEapIndex].RasEapInfo.dwEapTypeId,
dwRetCode );
break;
}
return dwRetCode;
}
switch (PppEapOutput.Action)
{
case EAPACTION_NoAction:
pResult->Action = ELEAP_NoAction;
TRACE0 (EAP, "EAP Dll returned Action=EAPACTION_NoAction" );
break;
case EAPACTION_Send:
pResult->Action = ELEAP_Send;
TRACE0 (EAP, "EAP Dll returned Action=EAPACTION_Send" );
break;
case EAPACTION_Done:
case EAPACTION_SendAndDone:
if (PppEapOutput.Action == EAPACTION_SendAndDone)
{
pResult->Action = ELEAP_SendAndDone;
TRACE0 (EAP, "EAP Dll returned Action=EAPACTION_SendAndDone" );
}
else
{
pResult->Action = ELEAP_Done;
TRACE0 (EAP, "EAP Dll returned Action=EAPACTION_Done" );
}
// These are the attributes that are filled in by the EAP-DLL
// e.g in EAP-TLS it will be MPPE Keys
pResult->dwError = PppEapOutput.dwAuthResultCode;
pResult->pUserAttributes = PppEapOutput.pUserAttributes;
if (pPCB->pszIdentity != NULL)
{
strncpy (pResult->szUserName, pPCB->pszIdentity, UNLEN);
pResult->szUserName[UNLEN] = '\0';
}
else
{
pResult->szUserName[0] = '\0';
}
break;
case EAPACTION_SendWithTimeout:
case EAPACTION_SendWithTimeoutInteractive:
case EAPACTION_Authenticate:
TRACE1 (EAP, "EAP Dll returned disallowed Action=%d",
PppEapOutput.Action);
break;
default:
TRACE1 (EAP, "EAP Dll returned unknown Action=%d", PppEapOutput.Action);
break;
}
//
// Check to see if EAP dll wants to bring up UI
//
if (PppEapOutput.fInvokeInteractiveUI)
{
if (PppEapOutput.pUIContextData != NULL)
{
pResult->InvokeEapUIData.dwSizeOfUIContextData =
PppEapOutput.dwSizeOfUIContextData;
// The context data memory is freed after the InvokeUI entrypoint
// in the EAP DLL is called
pResult->InvokeEapUIData.pbUIContextData
= MALLOC (PppEapOutput.dwSizeOfUIContextData);
if (pResult->InvokeEapUIData.pbUIContextData == NULL)
{
return (ERROR_NOT_ENOUGH_MEMORY);
}
CopyMemory (pResult->InvokeEapUIData.pbUIContextData,
PppEapOutput.pUIContextData,
pResult->InvokeEapUIData.dwSizeOfUIContextData);
}
else
{
pResult->InvokeEapUIData.pbUIContextData = NULL;
pResult->InvokeEapUIData.dwSizeOfUIContextData = 0;
}
pResult->fInvokeEapUI = TRUE;
pPCB->dwUIInvocationId =
InterlockedIncrement(&(g_dwEAPUIInvocationId));
pResult->InvokeEapUIData.dwContextId = pPCB->dwUIInvocationId;
pResult->InvokeEapUIData.dwEapTypeId =
g_pEapTable[pPCB->dwEapIndex].RasEapInfo.dwEapTypeId;
TRACE0 (EAP, "EAP Dll wants to invoke interactive UI" );
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_DESKTOP_REQUIRED_LOGON);
}
pResult->dwEapTypeId = pPCB->dwEapTypeToBeUsed;
pResult->fSaveUserData = PppEapOutput.fSaveUserData;
pResult->pUserData = PppEapOutput.pUserData;
pResult->dwSizeOfUserData = PppEapOutput.dwSizeOfUserData;
pResult->fSaveConnectionData = PppEapOutput.fSaveConnectionData;
pResult->SetCustomAuthData.pConnectionData =
PppEapOutput.pConnectionData;
pResult->SetCustomAuthData.dwSizeOfConnectionData =
PppEapOutput.dwSizeOfConnectionData;
TRACE2 (EAP,"ElEapDllWork finished for EAP Type %d with error %ld",
g_pEapTable[pPCB->dwEapIndex].RasEapInfo.dwEapTypeId,
dwRetCode);
return dwRetCode;
}
//
// ElGetEapIndex
//
// Description:
//
// Function called to get the index into the global EAP dll table for the
// specified EAP type
//
// Arguments:
// dwEapTypeId - Index into the EAP table for the input EAP type
// e.g. TLS = 13, MD5 = 4
//
DWORD
ElGetEapTypeIndex (
IN DWORD dwEapTypeId
)
{
DWORD dwIndex;
for (dwIndex = 0; dwIndex < g_dwNumEapProtocols; dwIndex++)
{
if (g_pEapTable[dwIndex].RasEapInfo.dwEapTypeId == dwEapTypeId)
{
return(dwIndex);
}
}
return((DWORD)-1);
}