2025-11-28 00:35:46 +09:00

1881 lines
58 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
#include <stdio.h>
#include "EapHostSupplicant.h"
#include "memory.h"
#include "EapHostCommon.h"
#include "resource.h"
#include "msxml6.h"
using namespace SDK_METHOD_SAMPLE_COMMON;
#define CONNECTION_PROPERTIES 1
#define USER_PROPERTIES 2
/// Store the SessionId for the entire Authentication Session.
EAP_SESSIONID eapSessionId = 0;
/// Handle to the library that implements EapHost Peer APIs.
HMODULE handleLibrary = NULL;
/// Stores the current action that suppliacnt has to take.
EapHostPeerResponseAction action = EapHostPeerResponseNone;
/// GUID that supplicant-eaphost use for NAP Callback function.
const GUID connectionId = {0x7128fce8,0x3ca0,0x4708,{0x9c, 0x8a, 0xad, 0x76, 0xc1, 0xb2, 0xfc, 0x53}};
/// Stores the connection data.
BYTE *connectionData = NULL;
/// Stores the size of the connection data.
DWORD sizeConnectionData = 0;
/// Stores the user data.
BYTE *userData = NULL;
/// Stores the size of the user data.
DWORD sizeUserData = 0;
/// The execution of runtime APIs and UI APIs should be processed by two different threads.
/// The event used by Runtime thread to wait for a signal from UI thread.
HANDLE event_WaitforUIThread = NULL;
/// The event used by UI thread to wait for a signal from Runtime thread.
HANDLE event_WaitforRuntimeThread = NULL;
/// Handle to a thread that handles UI calls (API - EapHostPeerInvokeInteractiveUI) to EapHost.
HANDLE UIThreadHandle = NULL;
/// Data that is shared between the Runtime thread and UI thread.
DWORD dwSizeofUIContextData = 0;
BYTE* pUIContextData = NULL;
DWORD dwSizeOfDataFromInteractiveUI = 0;
BYTE* pDataFromInteractiveUI = NULL;
EAP_METHOD_TYPE eapType = {0};
/// Stores the most recent packet received from Authenticator.
BYTE *pReceivedPacket = NULL;
/// Stores the size of the most recent packet received from Authenticator.
DWORD gdwReceivedPacketLen = 0;
/// Handle to an event that is used to signal between the receiving thread and
/// authentication thread.
HANDLE event_ReceivePacket = NULL;
BOOL needToWaitForEvent = TRUE;
/// Global variables are defined in supplicantMain.cpp
extern BYTE *g_pIdentityRequest;
extern DWORD g_dwIdentityRequestPacketLen;
//
// Declaration to EAP Host Peer APIs function pointers.
//
EapHostPeerInitialize funcEapHostPeerInitialize = NULL;
EapHostPeerUninitialize funcEapHostPeerUninitialize = NULL;
EapHostPeerBeginSession funcBeginSession = NULL;
EapHostPeerProcessReceivedPacket funcProcessReceivedPacket = NULL;
EapHostPeerGetSendPacket funcGetSendPacket = NULL;
EapHostPeerGetResult funcGetResult = NULL;
EapHostPeerGetUIContext funcGetUIContext = NULL;
EapHostPeerSetUIContext funcSetUIContext = NULL;
EapHostPeerGetResponseAttributes funcGetRespAttributes = NULL;
EapHostPeerSetResponseAttributes funcSetRespAttributes = NULL;
EapHostPeerGetAuthStatus funcGetAuthStatus = NULL;
EapHostPeerEndSession funcEndSession = NULL;
EapHostPeerClearConnection funcClearConnection = NULL;
EapHostPeerFreeEapError funcFreeEapError = NULL;
//
// Demonstrate how to get function pointers to EAP Host Peer APIs.
//
DWORD GetEapHostPeerAPIsFunctionPointers()
{
DWORD retCode = NO_ERROR;
//
//Load the library -- eappprxy.dll that implemenst the Peer Side EapHost Runtime APIs.
//
handleLibrary = LoadLibrary(L"eappprxy.dll");
if (handleLibrary == NULL)
{
retCode = GetLastError();
EapTrace("Loading eappprxy.dll failed: %d\n", retCode);
goto Cleanup;
}
//
//Get the function pointer to all the functions implemented inside the dll.
//
funcEapHostPeerInitialize = (EapHostPeerInitialize)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerInitialize");
funcEapHostPeerUninitialize = (EapHostPeerUninitialize)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerUninitialize");
funcBeginSession = (EapHostPeerBeginSession)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerBeginSession");
funcProcessReceivedPacket = (EapHostPeerProcessReceivedPacket)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerProcessReceivedPacket");
funcGetSendPacket = (EapHostPeerGetSendPacket)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerGetSendPacket");
funcGetResult = (EapHostPeerGetResult)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerGetResult");
funcGetUIContext = (EapHostPeerGetUIContext)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerGetUIContext");
funcSetUIContext = (EapHostPeerSetUIContext)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerSetUIContext");
funcGetRespAttributes = (EapHostPeerGetResponseAttributes)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerGetResponseAttributes");
funcSetRespAttributes = (EapHostPeerSetResponseAttributes)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerSetResponseAttributes");
funcGetAuthStatus = (EapHostPeerGetAuthStatus)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerGetAuthStatus");
funcEndSession = (EapHostPeerEndSession)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerEndSession");
funcClearConnection = (EapHostPeerClearConnection)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerClearConnection");
funcFreeEapError = (EapHostPeerFreeEapError)
GetProcAddress(handleLibrary, (LPCSTR)"EapHostPeerFreeEapError");
if (funcBeginSession == NULL ||
funcProcessReceivedPacket == NULL ||
funcGetSendPacket == NULL ||
funcGetResult == NULL ||
funcGetUIContext == NULL ||
funcSetUIContext == NULL ||
funcGetRespAttributes == NULL ||
funcSetRespAttributes == NULL ||
funcGetAuthStatus == NULL ||
funcEndSession == NULL ||
funcClearConnection == NULL ||
funcFreeEapError == NULL
)
{
retCode = HRESULT_CODE(E_POINTER);
}
Cleanup:
return retCode;
}
//
// Demonstrate usage of EAPHostGetMethods, showing supplicant-specific
// method selection and then using any of the given installed EAP Method
// depending on what properties are supported by that EAP Method.
//
DWORD GetEapMethodFromListOfInstalledEapMethods(EAP_METHOD_TYPE *pEapMethodType)
{
DWORD retCode = ERROR_SUCCESS;
EAP_METHOD_INFO_ARRAY eapMethodsInfo = {0};
EAP_ERROR *pEapError = NULL;
HWND hwndParent = {0};
// Sanity Check
if(!pEapMethodType)
{
//Report Error
retCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
// Call the EapHost Config API to get the list of Eap Methods installed and the properties each
// one supports.
retCode = EapHostPeerGetMethods(&eapMethodsInfo,
&pEapError);
if(retCode != ERROR_SUCCESS)
{
//Report Error
EapHostPeerFreeErrorMemory(pEapError);
goto Cleanup;
}
//
// Raises a GUI to display the information that is received from the EapHostPeerGetMethods API.
// One can also configure EapMethod from the GUI.
retCode = DisplayInstalledEapMethods(hwndParent, &eapMethodsInfo);
if(retCode != ERROR_SUCCESS)
{
//Report Error
}
//
// For demonstration purpose, we select that we will be using EapMethod - EAPTYPE for authentication.
//
pEapMethodType->eapType.type = EAPTYPE;
pEapMethodType->eapType.dwVendorId = 0;
pEapMethodType->eapType.dwVendorType = 0;
pEapMethodType->dwAuthorId = AUTHOR_ID;
//
// Free the Memory that EapHost has allocated.
//
EapHostPeerFreeMemory((BYTE *)eapMethodsInfo.pEapMethods);
Cleanup:
return retCode;
}
//
// Demonstrate how does supplicant find out from EAPHost that
// it needs to re-authenticate when the health state changes.
//
void SdkEapNotificationHandler(
IN GUID connId,
IN void* pContextData
)
{
DWORD retCode = ERROR_SUCCESS;
//
// Verify if the input parameters --- connectionId and ContextData
// are the same as passed to the BeginSession API.
//
UNREFERENCED_PARAMETER(connId);
UNREFERENCED_PARAMETER(pContextData);
//
// Check if any active authentication session is in progress.
// If yes, we need to end the active session and start a fresh authentication session.
// In this Sample code, we assume that the global variable "eapSessionId" is set
// when an active authentication is taking place and is reset to NULL when authentication
// complete.
//
if(eapSessionId) // An Authentication Session is in Progress.
{
// End the current authentication session.
EAP_ERROR *pEapError = NULL;
retCode = funcEndSession(eapSessionId, &pEapError);
if(retCode != ERROR_SUCCESS)
{
//Report Error
funcFreeEapError(pEapError);
return;
}
}
//
// Re-Auth since there is a change in the health state of the supplicant.
//
retCode = BeginAuthentication();
if(retCode != ERROR_SUCCESS)
{
//Report Error
}
}
//
// Initialize the resources used for authentication.
//
DWORD Initialize()
{
DWORD retCode = ERROR_SUCCESS;
//
// Get function pointers to EAP Host Peer APIs
//
retCode = GetEapHostPeerAPIsFunctionPointers();
if(retCode != ERROR_SUCCESS)
{
//Report Error
goto Cleanup;
}
//
//Create an event which Runtime thread uses to listen for UI thread.
//
event_WaitforUIThread = CreateEvent(NULL, // no security attributes
FALSE, // auto-reset enabled
FALSE, // non-signaled state initially
NULL); // event without a name
if(event_WaitforUIThread == NULL)
{
// Report Error
retCode = GetLastError();
goto Cleanup;
}
//
// Create an event which UI thread uses to listen to Runtime thread.
//
event_WaitforRuntimeThread = CreateEvent(NULL, //no security attributes
FALSE, // auto-reset enabled
FALSE, // non-signaled state initially
NULL); // event without a name
if(event_WaitforRuntimeThread == NULL)
{
// Report Error
retCode = GetLastError();
goto Cleanup;
}
//
// Create a thread that handles UI calls (API - EapHostPeerInvokeInteractiveUI) to EapHost.
//
UIThreadHandle = (HANDLE) CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)HandleUICalls,
0,
0,
NULL);
if(UIThreadHandle == NULL)
{
retCode = GetLastError();
goto Cleanup;
}
//
// The following comment is just a suggestion.
// 1. Create a thread (Listener thread) with function "ReceiveEapPackets" to be
// executed by the thread which would listen for EapData from Authenticator.
// Ofcourse, EapData will be contained in 802.1x or PPP packet.
// 2. Create an event "event_ReceivePacket" that listener thread will fire when it
// receives a EapData. The authenticating thread will pass the data to EapHost
// to process through the API -- EapHostPeerProcessReceivedPacket().
Cleanup:
return retCode;
}
//
// Demonstrate the handling of EapHostPeerResponseAction returned from EAP Host.
//
DWORD HandleEapHostPeerResponseAction(EapHostPeerResponseAction responseAction)
{
DWORD retCode = ERROR_SUCCESS;
switch(responseAction)
{
//
// Suggests that authentication result packet has come from the authenticator.
//
case EapHostPeerResponseResult:
retCode = HandleEapHostPeerResponseAction_GetResult(EapHostPeerMethodResultFromMethod);
break;
//
// Suggests that UI needs to be invoked.
//
case EapHostPeerResponseInvokeUi:
retCode = HandleEapHostPeerResponseAction_InvokeUI();
break;
//
// Suggests that there are EapAttributes with EapHost/EapMethod that needs to be processed by supplicant.
//
case EapHostPeerResponseRespond:
retCode = HandleEapHostPeerResponseAction_Respond();
break;
//
// Suggests that some internal problem occured which cannot be fixed. Therefore close the current
// authentication session and begin authentication from start.
//
case EapHostPeerResponseStartAuthentication:
{
//End the existing Session.
EAP_ERROR *pEapError = NULL;
retCode = funcEndSession(eapSessionId, &pEapError);
if(retCode != ERROR_SUCCESS)
{
//Report Error
funcFreeEapError(pEapError);
goto Cleanup;
}
//Start a new Session.
retCode = BeginAuthentication();
if(retCode != ERROR_SUCCESS)
{
//Report Error
goto Cleanup;
}
}
break;
//
// Suggests that there is a packet that EapMethod wants to send to Authenticator. Therefore,
// supplicant should get the packet from EapMethod via EapHost and transport it to the authenticator.
//
case EapHostPeerResponseSend:
retCode = HandleEapHostPeerResponseAction_Send();
break;
//
// No action needs to be taken.
//
case EapHostPeerResponseNone:
break;
//
// Suggests that no action needs to be taken.
//
case EapHostPeerResponseDiscard:
break;
default:
break;
}
if(retCode != ERROR_SUCCESS)
{
// Report Error
goto Cleanup;
}
//
// If action is ResponseResult, and after we process the result, we are done and
// should end the authentication session.
//
if(responseAction == EapHostPeerResponseResult)
{
EAP_ERROR *pEapError = NULL;
retCode = funcEndSession(eapSessionId, &pEapError);
if(retCode != ERROR_SUCCESS)
{
//Report Error
funcFreeEapError(pEapError);
goto Cleanup;
}
//
// Listener thread should no longer expect more packet.
//
needToWaitForEvent = FALSE;
}
Cleanup:
return retCode;
}
//
// Demonstrate the sequence of entire EAP Authentication Process.
//
DWORD BeginAuthentication()
{
DWORD retCode = ERROR_SUCCESS;
HRESULT hr = S_OK;
DWORD dwFlags = 0;
size_t threadId = 0;
EAP_ERROR *pEapError = NULL;
HANDLE hTokenImpersonateUser = NULL;
//Connection Data obtained from EapHost
IXMLDOMDocument2 *pXMLConnectionProperties = NULL;
BYTE *pConnectionDataOut = NULL;
DWORD dwSizeOfConnectionDataOut = 0;
//
// Wait till the UI thread to complete the configuration.
//
retCode = WaitForSingleObject(event_WaitforUIThread, INFINITE);
if(retCode != WAIT_OBJECT_0) /// WAIT_FAILED, WAIT_ABANDONED, WAIT_TIMEOUT all error.
{
//Report Error.
goto Cleanup;
}
//
// There are two main ways to generate Config Blob for authentication.
// One is through UI configuration.
// Other one is using XML files and XML APIs of EapHost to generate Config Blob.
// Below is demosntration of how to do that using XML files/APIs.
//
//
// Get the Config Data and User Data from registry.
// Note: Registry is just an example of a place where to store such data!!!
// If this is the first time user is authenticating, no such registry will be present.
// These data are present in the registry if the EAP method wishes to save them for
// future authentications.
//
retCode = ReadBLOBFromRegistry(CONNECTION_PROPERTIES,
sizeConnectionData,
connectionData);
if((retCode != ERROR_SUCCESS) && (retCode != ERROR_FILE_NOT_FOUND))
{
EapTrace("ReadBLOBFromRegistry returned error = %d",retCode);
goto Cleanup;
}
if(retCode == ERROR_FILE_NOT_FOUND)
{
//
// No registry present that stores Config Data.
// Most common scenario -- Administrator pushes Config Data in XML file format
// through group policy to each machines. These XML files are stored at some location
// or plumbed to some registry.
//
// Here we assume that the Config XML file is stored on hard drive.
//
//
// Demonstrates how to get Config blob from Config XML file using EAPHost APIs.
//
// Convert XML File to XMLDomDocument
retCode = CreateDOMDocumentFromXML(CONNECTION_PROPERTIES, &pXMLConnectionProperties);
if(retCode != ERROR_SUCCESS)
{
//Report Error
goto Cleanup;
}
// Get XMLDOMElement from XMLDOMDocument.
IXMLDOMElement *pEapConnNode;
hr = pXMLConnectionProperties->get_documentElement(&pEapConnNode);
// Call EapHost Config API to convert XMLDomElement to Config BLOB
retCode = EapHostPeerConfigXml2Blob(
dwFlags,
pEapConnNode,
&dwSizeOfConnectionDataOut,
&pConnectionDataOut,
&eapType,
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
//Report Error
EapHostPeerFreeErrorMemory(pEapError);
goto Cleanup;
}
if(pConnectionDataOut)
{
//
// Copy it to the global variable connectiondata.
//
sizeConnectionData = dwSizeOfConnectionDataOut;
retCode = AllocateMemory(sizeConnectionData, (PVOID*)&connectionData);
if (retCode != NO_ERROR)
goto Cleanup;
CopyMemory(connectionData, pConnectionDataOut, dwSizeOfConnectionDataOut);
//
// Finally free the ConnectionData Buffer obtained from EapHost.
//
EapHostPeerFreeMemory(pConnectionDataOut);
}
}
//
// Check to see if user blob is saved from previous authentication which can be used
// for this authentication.
//
retCode = ReadBLOBFromRegistry(USER_PROPERTIES,
sizeUserData,
userData);
if((retCode != ERROR_SUCCESS) && (retCode != ERROR_FILE_NOT_FOUND))
{
EapTrace("ReadBLOBFromRegistry returned error = %d",retCode);
goto Cleanup;
}
if(retCode == ERROR_FILE_NOT_FOUND)
{
//
// In certain cases like Guest Access at some location (e.g. an airport), one may
// receive an user XML file to use for authentication.
// If such is the case, one needs to follow the same sequence demonstrated above
// for getting the ConfigBlob from Config XML file.
// So if required to generate UserBlob from User XML file ---
// 1. Create a IXMLDOMElement from User XML file.
// 2. Call the EapHost API -- EapHostPeerCredentailsXml2Blob that returns UserBlob
// 3. Save it and finally call EapHostPeerFreeMemory when done with the user blob.
//
}
//
// This is just a demonstration of how to create an Impersonation Token.
// Required by methods to access resources (user cert...).
// One will have to pass VALID UserName, Domain and Password.
// Below all the three parameters are passed as NULL.
//
retCode = Impersonate(hTokenImpersonateUser,
NULL,
NULL,
NULL);
//
// Must call EapHostPeerInitialize() before calling any EapHostPeerXXX API.
//
retCode = funcEapHostPeerInitialize();
if(retCode != ERROR_SUCCESS)
{
//Error Reporting
goto Cleanup;
}
//
// Call BeginSession() in the EAP Host. This starts the authentication process.
//
retCode = funcBeginSession(
dwFlags, //Flags
eapType, //EAP_METHOD_TYPE
NULL, //EapAttributes
hTokenImpersonateUser, //HANDLE
sizeConnectionData, //Connection Data Size
connectionData, //Connection Data
sizeUserData, //User Data Size
userData, //User Data
MAX_PACKET_SIZE, //Max Packet
&connectionId, //ConnectionId
(NOTIFICATIONHANDLER)SdkEapNotificationHandler, //Notification Call Back Handler
(void*)threadId, //Context Data (Thread Identifier)
&eapSessionId, // Session Id
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
//Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
// Call EAPHost to process the received packet.
//
// First time this is called, the packet is received from NAS(Network Access Server)/Access Point.
// The packet is EAP-RequestIdentity.
// From then, the packet that is received is from the Authentication Server.
//
// Copy to the global variable.
retCode = AllocateMemory(g_dwIdentityRequestPacketLen, (PVOID *)&pReceivedPacket);
if(retCode != ERROR_SUCCESS)
{
//Report Error.
goto Cleanup;
}
CopyMemory(pReceivedPacket, g_pIdentityRequest, g_dwIdentityRequestPacketLen);
gdwReceivedPacketLen = g_dwIdentityRequestPacketLen;
//
// In a loop, take actions and and wait for next packet from authenticator until we receive
// the Result packet.
//
while(action != EapHostPeerResponseResult)
{
//
// Pass the received packet to EapMethod to process it.
//
retCode = funcProcessReceivedPacket(
eapSessionId, //Session Id
gdwReceivedPacketLen, //Length of the Packet
pReceivedPacket, //Packet
&action, //EapHostPeerResponseAction
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
//
// EapMethod returns an action after processing the received packet.
// Supplicant should take appropriate action.
//
retCode = HandleEapHostPeerResponseAction(action);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
goto Cleanup;
}
retCode = FreeMemory((PVOID *)&pReceivedPacket);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
goto Cleanup;
}
gdwReceivedPacketLen = 0;
//
// Till we receive the Result packet, we should wait for an event which the listener thread
// will set when it receives a packet from authenticator.
//
}
Cleanup:
//
// userData, connectionData and pReceivedPacket all get freed in Cleanup().
//
return retCode;
}
//
// Demonstrate how UI calls need to be executed in a different thread.
// This function is the threadhandler that executes UI calls to EapHost.
//
DWORD HandleUICalls(LPVOID lpParameter)
{
DWORD retCode = ERROR_SUCCESS;
EAP_ERROR *pEapError = NULL;
HWND hwndParent = {0};
UNREFERENCED_PARAMETER(lpParameter);
retCode = GetEapMethodFromListOfInstalledEapMethods(&eapType);
if(retCode != ERROR_SUCCESS)
{
// Either EapHostPeerGetMethods reported an error or
// the required EapMethod is not installed.
goto Cleanup;
}
retCode = SetEvent(event_WaitforUIThread);
if(retCode == 0)
{
retCode = GetLastError();
goto Cleanup;
}
while(needToWaitForEvent == TRUE)
{
retCode = WaitForSingleObject(event_WaitforRuntimeThread, INFINITE);
if(retCode != WAIT_OBJECT_0) /// WAIT_FAILED, WAIT_ABANDONED, WAIT_TIMEOUT all error.
{
//Report Error.
goto Cleanup;
}
//
// Always remember to free the memory that is allocated by EapHost CONFIG APIs.
// While those received from RUNTIME APIs will be freed automatically by EapHost
// when session ends.
//
dwSizeOfDataFromInteractiveUI = 0;
if(pDataFromInteractiveUI != NULL)
EapHostPeerFreeMemory(pDataFromInteractiveUI);
//
// Supplicant will always call InvokeInteractiveUI and EAPHost will take
// care of calling Identity and Interactive UI depending on the context.
//
retCode = EapHostPeerInvokeInteractiveUI(
hwndParent,
dwSizeofUIContextData,
pUIContextData,
&dwSizeOfDataFromInteractiveUI,
&pDataFromInteractiveUI,
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
//Config APIs error should be freed using EapHostPeerFreeErrorMemory API.
EapHostPeerFreeErrorMemory(pEapError);
goto Cleanup;
}
retCode = SetEvent(event_WaitforUIThread);
if(retCode == 0)
{
retCode = GetLastError();
goto Cleanup;
}
}
Cleanup:
return retCode;
}
//
// Demonstrate retrieval and processing of EapAttributes.
//
DWORD HandleEapHostPeerResponseAction_Respond()
{
DWORD retCode = ERROR_SUCCESS;
EapAttributes in_attributes = {0};
EapAttributes *out_attributes = NULL;
EAP_ERROR *pEapError = NULL;
DWORD numInAttributes = 0;
DWORD numAttrCtr = 0;
DWORD isCorrectAttr = 0;
EapAttribute *pEapAttribute = NULL;
//
// Get the attributes from EapHost/EapMethod that needs to be processed by the supplicant.
//
retCode = funcGetRespAttributes(
eapSessionId,
&in_attributes,
&pEapError);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
//
//Process the EapAtributes
//
numInAttributes = in_attributes.dwNumberOfAttributes;
for(numAttrCtr = 0; numAttrCtr < numInAttributes; numAttrCtr++)
{
pEapAttribute = (in_attributes.pAttribs) + numAttrCtr;
switch(pEapAttribute->eaType)
{
case 1:
isCorrectAttr = 1;
//
// Expected Attribute ---- eaType = 1; dwLength = 4; pValue = 40
//
{
DWORD attrLength = 0;
DWORD attrValue = 0;
attrLength = pEapAttribute->dwLength;
if(attrLength != sizeof(DWORD))
isCorrectAttr = 0;
attrValue = *((DWORD *)pEapAttribute->pValue);
if(attrValue != EAPTYPE)
isCorrectAttr = 0;
}
break;
default:
EapTrace("Supplicant does not process attributes except EapAttrType = 1");
break;
}
}
//
// Create the Response attribute. We need to call EapHostPeerSetResponseAttributes even if
// supplicant has no attributes to set. In that case call EapHostPeerSetResponseAttributes
// with EapAttributes having 0 eap attributes.
//
retCode = AllocateAttributes(1, &out_attributes);
if(retCode != ERROR_SUCCESS)
{
EapTrace("HandleEapHostPeerResponseAction_Respond : AllocateAttributes returned error = %d", retCode);
goto Cleanup;
}
//
// Response Attribute --- eaType = 2, dwLength = 4, pValue = 1 (if isCorrectAttr == TRUE) else 0.
//
retCode = AddAttribute(out_attributes, (EapAttributeType)2, sizeof(DWORD), (PVOID)&isCorrectAttr);
if(retCode != ERROR_SUCCESS)
{
EapTrace("HandleEapHostPeerResponseAction_Respond : AddAttribute returned error = %d", retCode);
goto Cleanup;
}
//
// Set the response attributes to EapMethod via EapHost.
//
retCode = funcSetRespAttributes(
eapSessionId,
out_attributes,
&action,
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
retCode = HandleEapHostPeerResponseAction(action);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
goto Cleanup;
}
Cleanup:
//
// Free the out_attributes.
//
FreeAttributes(&out_attributes);
return retCode;
}
//
// Demonstrate what to do when EAP Host returns InvokeUI as the action to take.
//
DWORD HandleEapHostPeerResponseAction_InvokeUI()
{
DWORD retCode = ERROR_SUCCESS;
EAP_ERROR *pEapError = NULL;
//
// Get the current context of the EapMethod so that it can be passed to the
// EapHostPeerInvokeInteractiveUI API.
//
retCode = funcGetUIContext(
eapSessionId,
&dwSizeofUIContextData,
&pUIContextData,
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
//
// Invoke the UI thread as it needs to make a call to EapHostPeerInvokeInteractiveUI API.
//
retCode = SetEvent(event_WaitforRuntimeThread);
if(retCode == 0)
{
retCode = GetLastError();
goto Cleanup;
}
//
// Wait till the UI thread completes.
//
retCode = WaitForSingleObject(event_WaitforUIThread, INFINITE);
if(retCode != WAIT_OBJECT_0) /// WAIT_FAILED, WAIT_ABANDONED, WAIT_TIMEOUT all error.
{
//Report Error.
goto Cleanup;
}
//
// Set the context data received from the above call of EapHostPeerInvokeInteractiveUI.
//
retCode = funcSetUIContext(
eapSessionId,
dwSizeOfDataFromInteractiveUI,
pDataFromInteractiveUI,
&action,
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
//
// EapHost returns an action to take depending on the context data passed to it.
//
retCode = HandleEapHostPeerResponseAction(action);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
goto Cleanup;
}
Cleanup:
return retCode;
}
//
// Demonstrate what to do when EAP Host returns GetResult as the action to take.
//
DWORD HandleEapHostPeerResponseAction_GetResult(EapHostPeerMethodResultReason reason)
{
DWORD retCode = ERROR_SUCCESS;
EAP_ERROR *pEapError = NULL;
EapHostPeerMethodResult result = {0};
//
// Get the final result of authentication from EapHost.
//
retCode = funcGetResult(
eapSessionId,
reason,
&result,
&pEapError
);
if(retCode != ERROR_SUCCESS)
{
// Error Reporting
funcFreeEapError(pEapError);
goto Cleanup;
}
if(result.fIsSuccess == TRUE)
{
//
// Save User and Connection Blob if indicated in the EapHostPeerMethodResult structure.
//
if(result.fSaveConnectionData == TRUE)
{
//
// Store the Connection Data into Registry. This BLOB will be used next time when
// authentication is done.
// Registry is just an example of a place to store it.
// In this example we store raw data in regsitry. One may wish to encrypt it.
//
retCode = StoreBLOBInRegistry(CONNECTION_PROPERTIES,
result.dwSizeofConnectionData,
result.pConnectionData);
if(retCode != ERROR_SUCCESS)
{
EapTrace("StoreBLOBInRegistry returned error = %d",retCode);
goto Cleanup;
}
}
if(result.fSaveUserData == TRUE)
{
//
// Store the User Data into Registry. This BLOB will be used next time when
// authentication is done.
// Registry is just an example of a place to store it.
// In this example we store raw data in regsitry. One may wish to encrypt it.
//
retCode = StoreBLOBInRegistry(USER_PROPERTIES,
result.dwSizeofUserData,
result.pUserData);
if(retCode != ERROR_SUCCESS)
{
EapTrace("StoreBLOBInRegistry returned error = %d",retCode);
goto Cleanup;
}
}
}
else
{
//
// Delete the registry entries for Config and User Blob if present when authentication fails
// using those values.
//
retCode = DeleteBLOBFromRegistry();
if(retCode != ERROR_SUCCESS)
{
EapTrace("DeleteBLOBFromRegistry returned error = %d",retCode);
goto Cleanup;
}
}
//
// Process the result and accordingly take further steps.
//
Cleanup:
return retCode;
}
//
// Demonstrate how the supplicant gets a response from EAP Host and sends to the authenticator.
//
DWORD HandleEapHostPeerResponseAction_Send()
{
DWORD retCode = ERROR_SUCCESS;
DWORD size = 0;
BYTE* pSendPacket = NULL;
EAP_ERROR *pEapError = NULL;
//
// Get the response packet from EapHost.
//
retCode = funcGetSendPacket(eapSessionId, &size, &pSendPacket, &pEapError);
if(retCode != ERROR_SUCCESS)
{
//Report Error
funcFreeEapError(pEapError);
goto Cleanup;
}
retCode = SendEapPackets(pSendPacket, size);
if(retCode != ERROR_SUCCESS)
{
//Report Error
goto Cleanup;
}
Cleanup:
return retCode;
}
//
//Clean up the resources used for authentication.
//
void CleanUp()
{
DWORD retCode = ERROR_SUCCESS;
EAP_ERROR *pEapError = NULL;
//
// This function needs to be called only if BeginSession succeeds.
// Call Clear Connection. Same connection can be used across multiple connections.
//
if(eapSessionId)
{
retCode = funcClearConnection((GUID *)&connectionId, &pEapError);
if(retCode != ERROR_SUCCESS)
{
// Report Error
funcFreeEapError(pEapError);
}
}
//
// Last thing to do with the EapHost is to call PeerUninitialize.
//
funcEapHostPeerUninitialize();
//
// Finally, Unload the eapprxy.dll
//
FreeLibrary(handleLibrary);
//
// Free the resources.
//
if(event_ReceivePacket)
CloseHandle(event_ReceivePacket);
if(event_WaitforRuntimeThread)
CloseHandle(event_WaitforRuntimeThread);
if(event_WaitforUIThread)
CloseHandle(event_WaitforUIThread);
if(UIThreadHandle)
CloseHandle(UIThreadHandle);
if(userData)
FreeMemory((PVOID *)&userData);
if(connectionData)
FreeMemory((PVOID *)&connectionData);
if(pReceivedPacket)
FreeMemory((PVOID *)&pReceivedPacket);
eapSessionId = 0;
}
//
// Demonstrate how to send and receive packet to/from supplicant to the authenticator.
//
DWORD SendEapPackets(BYTE *pEapPacketToSend, DWORD dwPacketSize)
{
DWORD retCode = ERROR_SUCCESS;
UNREFERENCED_PARAMETER(pEapPacketToSend);
UNREFERENCED_PARAMETER(dwPacketSize);
//
// Code that wrap the EapPacket within 802.1x (in case of Access Point) or PPP (in case of Remote Access Server).
// and sends it to the respective NAS.
//
return retCode;
}
DWORD ReceiveEapPackets(LPVOID lpParameter)
{
DWORD retCode = ERROR_SUCCESS;
UNREFERENCED_PARAMETER(lpParameter);
while(needToWaitForEvent == TRUE)
{
//
// Code that will listen for packets from the NAS (Access Point or Remote Access Server).
//
//
// Once a packet is received, copy the received packet to variable pReceivedPacket and
// update gdwReceivedPacketLen.
//
//
// Set the event "event_ReceivePacket" so that authenticator thread wakes up and process
// the recived packet by passing it to EapHost.
//
}
return retCode;
}
//
// Demonstrate how to create IXMLDOMDocument2 interface pointer and load an xml file using it.
//
DWORD CreateDOMDocumentFromXML(DWORD type, IXMLDOMDocument2** pXMLDOMDocument2)
{
DWORD retCode = ERROR_SUCCESS;
HRESULT hr = S_OK;
VARIANT xmlFileNameVariant = {0};
VARIANT_BOOL isSuccessful = {0};
hr = CoInitialize(NULL);
if(FAILED(hr))
{
//Report Error
retCode = HRESULT_CODE(hr);
goto Cleanup;
}
hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument2, (void**)&(*pXMLDOMDocument2));
if(FAILED(hr))
{
//Report Error
retCode = HRESULT_CODE(hr);
goto Cleanup;
}
xmlFileNameVariant.vt = VT_BSTR;
switch(type)
{
case CONNECTION_PROPERTIES:
xmlFileNameVariant.bstrVal = SysAllocString(L"SdkEapConn.xml");
if(xmlFileNameVariant.bstrVal == NULL)
{
retCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
break;
case USER_PROPERTIES:
xmlFileNameVariant.bstrVal = SysAllocString(L"SdkEapUser.xml");
if(xmlFileNameVariant.bstrVal == NULL)
{
retCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
break;
default:
//Report Error
break;
}
hr = (*pXMLDOMDocument2)->load(xmlFileNameVariant, &isSuccessful);
if(FAILED(hr)) //Fails if isSuccessful is VARIANT_FALSE, no need to especially check isSuccessful
{
//Report Error
retCode = HRESULT_CODE(hr);
goto Cleanup;
}
Cleanup:
SysFreeString(xmlFileNameVariant.bstrVal);
return retCode;
}
//
// Generates the Identity Request EAP Packet.
//
DWORD MakeIdentityRequestMessage(BYTE **pIdentityReq, DWORD *pIdentityReqLen)
{
DWORD retCode = ERROR_SUCCESS;
EapPacket *pIdentityReqEapPacket = NULL;
WORD tempPacketLen = 0;
*pIdentityReqLen = 5; //Code = 1, Id = 1, Length = 2, Type = 1
//
//Allocate the buffer to store Identity Request packet.
//
retCode = AllocateMemory(*pIdentityReqLen, (PVOID *)&pIdentityReqEapPacket);
if(retCode != ERROR_SUCCESS)
{
//Report Error
goto Cleanup;
}
//
// Fill the elments of the Identity Request Packet.
//
pIdentityReqEapPacket->Code = EapCodeRequest;
pIdentityReqEapPacket->Id = 0;
HostToWireFormat16((WORD)*pIdentityReqLen, (PBYTE)&tempPacketLen);
CopyMemory(&(pIdentityReqEapPacket->Length), &tempPacketLen, sizeof(WORD));
pIdentityReqEapPacket->Data[0] = 0x01; //Identity Request Type
*pIdentityReq = (BYTE *)pIdentityReqEapPacket;
Cleanup:
return retCode;
}
//
// Do logon user and then impersonate the user.
// pToken is the handle returned after impersonation.
// UserName, Password and Domain are required for Logon.
//
DWORD Impersonate(HANDLE &pToken,
LPCWSTR user,
LPCWSTR domain,
LPCWSTR pswd)
{
DWORD retCode = ERROR_SUCCESS;
BOOL fOk = FALSE;
fOk = LogonUserW( user,
domain,
pswd,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&pToken );
if ( fOk == FALSE )
{
retCode = GetLastError( );
//Report Error
goto Cleanup;
}
fOk = ImpersonateLoggedOnUser(pToken);
if ( fOk == FALSE )
{
retCode = GetLastError( );
//Report Error
goto Cleanup;
}
Cleanup:
return retCode;
}
//
// Stores the BLOB (either UserData or ConnectionData) into registry. The supplicant does not care about the
// content of the BLOB.
//
DWORD StoreBLOBInRegistry(DWORD type, DWORD sizeOfBLOB, BYTE *pBLOB)
{
DWORD retCode = ERROR_SUCCESS;
HKEY hKeyEap = NULL;
bool regkeyopen = false;
LPDWORD lpdwDisposition = NULL;
//
// Create the Registry Key --- HKLM\Software\SdkEap if not created before.
// Location is picked randomly.
//
retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\SdkEap",
0,
KEY_ALL_ACCESS,
&hKeyEap);
if (retCode != ERROR_SUCCESS)
{
if (retCode == ERROR_FILE_NOT_FOUND)
{
// Create a new key.
retCode = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\SdkEap",
0,
NULL,
REG_OPTION_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKeyEap,
lpdwDisposition);
if (retCode != ERROR_SUCCESS)
{
EapTrace("StoreBLOBInRegistry: Could not open reg key");
goto Cleanup;
}
regkeyopen = true;
}
else
{
goto Cleanup;
}
}
//
// Set Values in to the above Registry Key.
//
wchar_t wszKey[128] = { L'\0' };
if(type == CONNECTION_PROPERTIES)
swprintf_s( wszKey, 128, L"ConnectionBlob_%u", EAPTYPE );
else
swprintf_s( wszKey, 128, L"UserBlob_%u", EAPTYPE );
retCode = RegSetValueEx(
hKeyEap,
wszKey,
0,
REG_BINARY,
pBLOB,
sizeOfBLOB
);
if ( retCode != ERROR_SUCCESS )
{
EapTrace("StoreBLOBInRegistry: Cannot set regkey %d", retCode);
goto Cleanup;
}
RegCloseKey(hKeyEap);
Cleanup:
return retCode;
}
//
// Retrieves the BLOB (either UserData or ConnectionData) from registry. The supplicant does not care about the
// content of the BLOB.
//
DWORD ReadBLOBFromRegistry(DWORD type, DWORD &sizeOfBLOB, BYTE *&pBLOB)
{
DWORD retCode = ERROR_SUCCESS;
HKEY hKeyEap = NULL;
DWORD dwRegValueType = REG_BINARY;
DWORD cbRegValueData = 0;
//
// Open the registry value.
//
retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\SdkEap",
0,
KEY_READ,
&hKeyEap);
if (retCode != ERROR_SUCCESS)
{
goto Cleanup;
}
else
{
wchar_t wszKey[128] = { L'\0' };
if(type == CONNECTION_PROPERTIES)
swprintf_s( wszKey, 128, L"ConnectionBlob_%u", EAPTYPE );
else
swprintf_s( wszKey, 128, L"UserBlob_%u", EAPTYPE );
//
// Read the specified regvalue.
//
retCode = RegQueryValueExW(hKeyEap, wszKey, NULL, &dwRegValueType,
NULL, &cbRegValueData);
if (retCode != ERROR_SUCCESS)
{
goto Cleanup;
}
else if (retCode == ERROR_SUCCESS && cbRegValueData > 0)
{
//
// Make sure it's the right type.
//
if (dwRegValueType != REG_BINARY)
{
EapTrace("ReadBLOBFromRegistry(): Error -- registry value was not a string! Ignoring it.");
retCode = NO_ERROR;
goto Cleanup;
}
// Allocate a buffer to hold the value.
retCode = AllocateMemory(cbRegValueData, (PVOID*)&pBLOB);
if (retCode != NO_ERROR)
goto Cleanup;
// Get the real value. (Errors handled by code outside if() clause.)
retCode = RegQueryValueExW(hKeyEap, wszKey, NULL, &dwRegValueType,
(PBYTE)pBLOB, &cbRegValueData);
if (retCode != ERROR_SUCCESS)
{
EapTrace("ReadBLOBFromRegistry(): Error -- couldn't get registry value! (error %d)", retCode);
goto Cleanup;
}
sizeOfBLOB = cbRegValueData;
}
}
Cleanup:
if (hKeyEap)
RegCloseKey(hKeyEap);
// If returning error, free any memory we allocated.
if (retCode != NO_ERROR)
FreeMemory((PVOID*)&pBLOB);
return retCode;
}
//
// Delete the registry entries for Config and User Blob if present when authentication fails
// using those values.
//
DWORD DeleteBLOBFromRegistry()
{
DWORD retCode = ERROR_SUCCESS;
HKEY hkEapBlob = 0;
const wchar_t eapRootKeyName[] = L"Software";
const wchar_t eapKeyName[] = L"SdkEap";
// Check if the key -- "HKLM\Software" exist.
retCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, eapRootKeyName,
0, KEY_ALL_ACCESS, &hkEapBlob);
if(retCode != ERROR_SUCCESS)
{
// Trace Error
goto Cleanup;
}
// Delete the subkey - "SdkEap" which
retCode = RegDeleteKeyW(hkEapBlob, eapKeyName);
if(retCode != ERROR_SUCCESS)
{
// Trace Error
goto Cleanup;
}
Cleanup:
if(hkEapBlob)
RegCloseKey(hkEapBlob);
return retCode;
}
//---------------------------------------------------------------------------
//
// Dialog routines.
//
//---------------------------------------------------------------------------
/**
* Display and Configure Eap Method() helper function
*
* This function displays an UI (the IDD_DIALOG dialog box) that displays the list of
* installed EapMethods and Eap Properties supported by each of them.
*
* @param hwndParent [in] Handle to the parent window for the
* user interface dialog.
*
*
*
* @return If the function succeeds, the return value is NO_ERROR.
*/
DWORD
DisplayInstalledEapMethods(
IN HWND hwndParent,
IN EAP_METHOD_INFO_ARRAY* pEapMethodsData
)
{
DWORD dwErr = NO_ERROR;
int result = 0;
result = (int)DialogBoxParam(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG),
hwndParent,
DialogProc,
(LPARAM)pEapMethodsData);
if (result < 0)
{
dwErr = GetLastError();
EapTrace("Hit error %d while displaying DisplayInstalledEapMethods dialog!",
dwErr);
}
return(dwErr);
}
INT_PTR CALLBACK DialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
DWORD dwErr = FALSE; // By default, return FALSE.
EAP_METHOD_INFO_ARRAY* pEapMethodsData = NULL;
switch (unMsg)
{
case WM_INITDIALOG:
dwErr = InitDialog(hWnd, lParam);
break;
case WM_COMMAND:
pEapMethodsData = (EAP_METHOD_INFO_ARRAY *)((LONG_PTR)GetWindowLongPtr(hWnd, DWLP_USER));
dwErr = CommandProc(pEapMethodsData, LOWORD(wParam), hWnd);
break;
}
return(dwErr);
}
BOOL InitDialog(
IN HWND hWndDlg,
IN LPARAM lParam
)
{
DWORD dwNumberOfEapMethods = 0;
DWORD dwMethodCount = 0;
EAP_METHOD_INFO *pLocalEapMethodInfo = NULL;
HWND hWnd = NULL;
EAP_METHOD_INFO_ARRAY *eapMethodsInfo = NULL;
LRESULT lResult = 0;
SetWindowLongPtr(hWndDlg, DWLP_USER, (LONG)lParam);
eapMethodsInfo = (EAP_METHOD_INFO_ARRAY *)lParam;
hWnd = GetDlgItem(hWndDlg, IDC_METHODLIST);
if (hWnd == NULL) // GetDlgItem() returns NULL for errors.
{
EapTrace("Error -- InitDialog (error %d)",GetLastError());
goto Cleanup;
}
//
// Display the list of Eap Methods Installed with EapHost.
//
dwNumberOfEapMethods = eapMethodsInfo->dwNumberOfMethods;
for(dwMethodCount = 0; dwMethodCount < dwNumberOfEapMethods; dwMethodCount++)
{
pLocalEapMethodInfo = &((eapMethodsInfo->pEapMethods)[dwMethodCount]);
lResult = SendMessage(hWnd,
(UINT) LB_ADDSTRING,
(WPARAM) 0,
(LPARAM)pLocalEapMethodInfo->pwszFriendlyName);
if(lResult == LB_ERR)
goto Cleanup;
}
Cleanup:
return(FALSE);
}
BOOL
CommandProc(
IN EAP_METHOD_INFO_ARRAY* pEapMethodsData,
IN WORD wId,
IN HWND hWndDlg
)
{
BOOL fOk = FALSE;
HWND hWnd = NULL;
DWORD retCode = ERROR_SUCCESS;
DWORD selIndex = 0;
EAP_ERROR *pEapError = NULL;
EAP_METHOD_INFO *pLocalEapMethodInfo = NULL;
WCHAR eapPropText[1000] = {L'\0'};
DWORD eapPropTextCtr = 0;
DWORD eapPropLen = 0;
// Sanity checks.
if (! pEapMethodsData)
{
EapTrace("CommandProc: input dialog pointer is NULL!");
goto Cleanup;
}
//
// Get the index of the selected EapMethod. Done above the switch block as
// this step is required for both IDC_PROPERTIES and IDC_CONFIGURE.
//
hWnd = GetDlgItem(hWndDlg, IDC_METHODLIST);
if (hWnd == NULL) // GetDlgItem() returns NULL for errors.
{
EapTrace("Error -- CommandProc -- IDC_METHODLIST -- (error %d)",GetLastError());
goto Cleanup;
}
selIndex = (DWORD)SendMessage(hWnd,
(UINT) LB_GETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
if(selIndex == LB_ERR)
goto Cleanup;
pLocalEapMethodInfo = &((pEapMethodsData->pEapMethods)[selIndex]);
switch(wId)
{
case IDC_METHODLIST:
//
// We already know about the index that is selected.
// 1. Remove the Eap Properties corresponding to the earlier selected text.
// 2. Check if the new selected Eap suppports configuration. Accordingly, enable/disable the
// the Configure button.
// 1.
hWnd = GetDlgItem(hWndDlg, IDC_PROPERTYTEXT);
if (hWnd == NULL) // GetDlgItem() returns NULL for errors.
{
EapTrace("Error -- CommandProc -- IDC_PROPERTYTEXT -- (error %d)",GetLastError());
goto Cleanup;
}
// eapPropText = NULL
fOk = SetWindowText(hWnd, eapPropText);
if(fOk == 0)
goto Cleanup;
// 2.
hWnd = GetDlgItem(hWndDlg, IDC_CONFIGURE);
if (hWnd == NULL) // GetDlgItem() returns NULL for errors.
{
EapTrace("Error -- CommandProc -- IDC_CONFIGURE -- (error %d)",GetLastError());
goto Cleanup;
}
{
BOOL isHighlighted = FALSE;
if(!(pLocalEapMethodInfo->eapProperties & eapPropSupportsConfig))
{
isHighlighted = TRUE;
}
SendMessage(hWnd,
(UINT) BM_SETSTATE,
(WPARAM) isHighlighted,
(LPARAM) 0);
}
break;
case IDC_PROPERTIES:
//
// Display the Properties that the selected Eap Method supports
//
hWnd = GetDlgItem(hWndDlg, IDC_PROPERTYTEXT);
if (hWnd == NULL) // GetDlgItem() returns NULL for errors.
{
EapTrace("Error -- CommandProc -- IDC_PROPERTYTEXT -- (error %d)",GetLastError());
goto Cleanup;
}
eapPropLen = sizeof(eapPropText)/sizeof(wchar_t);
if(pLocalEapMethodInfo->eapProperties & eapPropCipherSuiteNegotiation)
eapPropTextCtr = swprintf_s(eapPropText, eapPropLen, L"CipherSuiteNegotiation \n");
if(pLocalEapMethodInfo->eapProperties & eapPropMutualAuth)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Mutual Authentication \n");
if(pLocalEapMethodInfo->eapProperties & eapPropIntegrity)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Integrity \n");
if(pLocalEapMethodInfo->eapProperties & eapPropReplayProtection)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Replay Protection \n");
if(pLocalEapMethodInfo->eapProperties & eapPropConfidentiality)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Confidentiality \n");
if(pLocalEapMethodInfo->eapProperties & eapPropKeyDerivation)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Key Derivation \n");
if(pLocalEapMethodInfo->eapProperties & eapPropKeyStrength64)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"KeyStrength64 \n");
if(pLocalEapMethodInfo->eapProperties & eapPropKeyStrength128)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"KeyStrength128 \n");
if(pLocalEapMethodInfo->eapProperties & eapPropKeyStrength256)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"KeyStrength256 \n");
if(pLocalEapMethodInfo->eapProperties & eapPropKeyStrength512)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"KeyStrength512 \n");
if(pLocalEapMethodInfo->eapProperties & eapPropKeyStrength1024)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"KeyStrength1024 \n");
if(pLocalEapMethodInfo->eapProperties & eapPropDictionaryAttackResistance)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"DictionaryAttackResistance \n");
if(pLocalEapMethodInfo->eapProperties & eapPropFastReconnect)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"FastReconnect \n");
if(pLocalEapMethodInfo->eapProperties & eapPropCryptoBinding)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"CryptoBinding \n");
if(pLocalEapMethodInfo->eapProperties & eapPropSessionIndependence)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"SessionIndependence \n");
if(pLocalEapMethodInfo->eapProperties & eapPropFragmentation)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Fragmentation \n");
if(pLocalEapMethodInfo->eapProperties & eapPropChannelBinding)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"ChannelBinding \n");
if(pLocalEapMethodInfo->eapProperties & eapPropNap)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Supports Nap \n");
if(pLocalEapMethodInfo->eapProperties & eapPropStandalone)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"Standalone \n");
if(pLocalEapMethodInfo->eapProperties & eapPropMppeEncryption)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"MppeEncryption \n");
if(pLocalEapMethodInfo->eapProperties & eapPropTunnelMethod)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"TunnelMethod \n");
if(pLocalEapMethodInfo->eapProperties & eapPropSupportsConfig)
eapPropTextCtr += swprintf_s(eapPropText + eapPropTextCtr, eapPropLen - eapPropTextCtr, L"SupportsConfig \n");
fOk = SetWindowText(hWnd, eapPropText);
if(fOk == 0)
goto Cleanup;
break;
case IDC_CONFIGURE:
//
// Invoke the ConfigUI for the selected Eap Method.
//
retCode = EapHostPeerInvokeConfigUI(
hWndDlg,
0,
pLocalEapMethodInfo->eaptype,
0,
NULL,
&sizeConnectionData,
&connectionData,
&pEapError);
if(retCode != ERROR_SUCCESS)
{
//Report Error
EapHostPeerFreeErrorMemory(pEapError);
goto Cleanup;
}
break;
case IDC_EXITDIALOG:
EndDialog(hWndDlg, wId);
break;
default:
break;
}
fOk = TRUE;
Cleanup:
return fOk;
}