2207 lines
66 KiB
C
2207 lines
66 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000, Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
eluser.c
|
||
|
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
The module deals with functions related to user interaction, user logon
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
sachins, Apr 23 2000, Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include "pcheapol.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#define cszEapKeyRas TEXT("Software\\Microsoft\\RAS EAP\\UserEapInfo")
|
||
|
|
||
|
#define cszEapValue TEXT("EapInfo")
|
||
|
|
||
|
#ifndef EAPOL_SERVICE
|
||
|
#define cszModuleName TEXT("wzcsvc.dll")
|
||
|
#else
|
||
|
#define cszModuleName TEXT("eapol.exe")
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElSessionChangeHandler
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called to handle user session login/logoff/user-switching
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pEventData - SCM event data
|
||
|
// dwEventType - SCM event type
|
||
|
//
|
||
|
|
||
|
VOID
|
||
|
ElSessionChangeHandler (
|
||
|
PVOID pEventData,
|
||
|
DWORD dwEventType
|
||
|
)
|
||
|
{
|
||
|
DWORD dwEventStatus = 0;
|
||
|
BOOLEAN fDecrWorkerThreadCount = FALSE;
|
||
|
LPTHREAD_START_ROUTINE pUserRoutine = NULL;
|
||
|
PVOID pvBuffer = NULL;
|
||
|
EAPOL_ZC_INTF ZCData;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (g_hEventTerminateEAPOL == NULL)
|
||
|
{
|
||
|
dwRetCode = NO_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
if (( dwEventStatus = WaitForSingleObject (
|
||
|
g_hEventTerminateEAPOL,
|
||
|
0)) == WAIT_FAILED)
|
||
|
{
|
||
|
dwRetCode = GetLastError ();
|
||
|
break;
|
||
|
}
|
||
|
if (dwEventStatus == WAIT_OBJECT_0)
|
||
|
{
|
||
|
dwRetCode = NO_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
if (!(g_dwModulesStarted & LOGON_MODULE_STARTED))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
InterlockedIncrement (&g_lWorkerThreads);
|
||
|
|
||
|
fDecrWorkerThreadCount = TRUE;
|
||
|
|
||
|
if (pEventData)
|
||
|
{
|
||
|
WTSSESSION_NOTIFICATION* pswtsi = (WTSSESSION_NOTIFICATION*)pEventData;
|
||
|
DWORD dwSessionId = pswtsi->dwSessionId;
|
||
|
|
||
|
switch (dwEventType)
|
||
|
{
|
||
|
case WTS_CONSOLE_CONNECT:
|
||
|
case WTS_REMOTE_CONNECT:
|
||
|
{
|
||
|
TRACE1 (USER,"ElSessionChangeHandler: CONNECT for session = (%ld)\n",
|
||
|
dwSessionId);
|
||
|
pUserRoutine = ElUserLogonCallback;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WTS_CONSOLE_DISCONNECT:
|
||
|
case WTS_REMOTE_DISCONNECT:
|
||
|
{
|
||
|
TRACE1 (USER,"ElSessionChangeHandler: DISCONNECT for session = (%ld)\n",
|
||
|
dwSessionId);
|
||
|
pUserRoutine = ElUserLogoffCallback;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WTS_SESSION_LOGON:
|
||
|
{
|
||
|
TRACE1 (USER,"ElSessionChangeHandler: LOGON for session = (%ld)",
|
||
|
dwSessionId);
|
||
|
pUserRoutine = ElUserLogonCallback;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WTS_SESSION_LOGOFF:
|
||
|
{
|
||
|
TRACE1 (USER,"ElSessionChangeHandler: LOGOFF for session=(%ld)",
|
||
|
dwSessionId);
|
||
|
|
||
|
pUserRoutine = ElUserLogoffCallback;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pUserRoutine == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((pvBuffer = MALLOC (sizeof(DWORD))) == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*((DWORD *)pvBuffer) = dwSessionId;
|
||
|
|
||
|
if (!QueueUserWorkItem (
|
||
|
(LPTHREAD_START_ROUTINE)pUserRoutine,
|
||
|
pvBuffer,
|
||
|
WT_EXECUTELONGFUNCTION))
|
||
|
{
|
||
|
dwRetCode = GetLastError();
|
||
|
TRACE1 (DEVICE, "ElSessionChangeHandler: QueueUserWorkItem failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fDecrWorkerThreadCount = FALSE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
if (fDecrWorkerThreadCount)
|
||
|
{
|
||
|
InterlockedDecrement (&g_lWorkerThreads);
|
||
|
}
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
if (pvBuffer != NULL)
|
||
|
{
|
||
|
FREE (pvBuffer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElUserLogonCallback
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Callback function invoked whenever a user logs in
|
||
|
// Will initiate authentication process on all ports of LAN class
|
||
|
// Credentials for the user in case of EAP-TLS can be obtained by
|
||
|
// acquiring user token
|
||
|
// For EAP-CHAP, WinLogon cerdentials will need to be supplied
|
||
|
//
|
||
|
// Arguments:
|
||
|
// None.
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ElUserLogonCallback (
|
||
|
IN PVOID pvContext
|
||
|
)
|
||
|
{
|
||
|
|
||
|
DWORD dwIndex = 0;
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
BOOL fSetCONNECTINGState = FALSE;
|
||
|
EAPOL_ZC_INTF ZCData;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
TRACE1 (USER, "ElUserLogonCallback: UserloggedOn = %ld",
|
||
|
g_fUserLoggedOn);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (g_fUserLoggedOn)
|
||
|
{
|
||
|
TRACE0 (USER, "ElUserLogonCallback: User logon already detected, returning without processing");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pvContext == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (*((DWORD *)pvContext) != USER_SHARED_DATA->ActiveConsoleId)
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogonCallback: Not active console id (%ld)",
|
||
|
*((DWORD *)pvContext));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Check if UserModule is ready for notifications
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
if ((dwRetCode = ElCheckUserModuleReady ()) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogonCallback: ElCheckUserModuleReady failed with error %ld",
|
||
|
dwRetCode);
|
||
|
if (dwRetCode == ERROR_BAD_IMPERSONATION_LEVEL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set global flag to indicate the user logged on
|
||
|
g_fUserLoggedOn = TRUE;
|
||
|
g_dwCurrentSessionId = *((DWORD *)pvContext);
|
||
|
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
|
||
|
|
||
|
for (dwIndex = 0; dwIndex < PORT_TABLE_BUCKETS; dwIndex++)
|
||
|
{
|
||
|
for (pPCB = g_PCBTable.pPCBBuckets[dwIndex].pPorts;
|
||
|
pPCB != NULL;
|
||
|
pPCB = pPCB->pNext)
|
||
|
{
|
||
|
fSetCONNECTINGState = FALSE;
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
switch (pPCB->dwEAPOLAuthMode)
|
||
|
{
|
||
|
case EAPOL_AUTH_MODE_0:
|
||
|
|
||
|
if (pPCB->State == EAPOLSTATE_AUTHENTICATED)
|
||
|
{
|
||
|
if (pPCB->PreviousAuthenticationType ==
|
||
|
EAPOL_UNAUTHENTICATED_ACCESS)
|
||
|
{
|
||
|
fSetCONNECTINGState = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
(VOID) ElEapEnd (pPCB);
|
||
|
fSetCONNECTINGState = TRUE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOL_AUTH_MODE_1:
|
||
|
|
||
|
(VOID) ElEapEnd (pPCB);
|
||
|
fSetCONNECTINGState = TRUE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOL_AUTH_MODE_2:
|
||
|
|
||
|
// Do nothing
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogonCallback: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
fSetCONNECTINGState = FALSE;
|
||
|
}
|
||
|
|
||
|
// Set port to EAPOLSTATE_CONNECTING
|
||
|
|
||
|
if (fSetCONNECTINGState)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_USER_LOGON, pPCB->pwszFriendlyName);
|
||
|
|
||
|
// First send out EAPOL_Logoff message
|
||
|
if ((dwRetCode = FSMLogoff (pPCB, NULL))
|
||
|
!= NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogonCallback: Error in FSMLogoff = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = NO_ERROR;
|
||
|
}
|
||
|
|
||
|
pPCB->dwAuthFailCount = 0;
|
||
|
|
||
|
// With unauthenticated access flag set, port will always
|
||
|
// reauthenticate for logged on user
|
||
|
|
||
|
pPCB->PreviousAuthenticationType =
|
||
|
EAPOL_UNAUTHENTICATED_ACCESS;
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
// Restart authentication on the port
|
||
|
if ((dwRetCode = ElReStartPort (pPCB, 0, NULL)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogonCallback: MachineAuth: Error in ElReStartPort = %ld",
|
||
|
dwRetCode);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&(g_PCBLock));
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
TRACE1 (USER, "ElUserLogonCallback: completed with error %ld", dwRetCode);
|
||
|
|
||
|
if (pvContext != NULL)
|
||
|
{
|
||
|
FREE (pvContext);
|
||
|
}
|
||
|
|
||
|
InterlockedDecrement (&g_lWorkerThreads);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElUserLogoffCallback
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Callback function invoked whenever a user logs off
|
||
|
// Will logoff from all ports which have authentication enabled
|
||
|
//
|
||
|
// Arguments:
|
||
|
// None.
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ElUserLogoffCallback (
|
||
|
IN PVOID pvContext
|
||
|
)
|
||
|
{
|
||
|
DWORD dwIndex = 0;
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
BOOL fSetCONNECTINGState = FALSE;
|
||
|
EAPOL_ZC_INTF ZCData;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (!g_fUserLoggedOn)
|
||
|
{
|
||
|
TRACE0 (USER, "ElUserLogoffCallback: User logoff already called, returning without processing");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pvContext == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (g_dwCurrentSessionId != *((DWORD *)pvContext))
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogoffCallback: Not active console id (%ld)",
|
||
|
*((DWORD *)pvContext));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Reset global flag to indicate the user logged off
|
||
|
|
||
|
g_fUserLoggedOn = FALSE;
|
||
|
g_dwCurrentSessionId = 0xffffffff;
|
||
|
|
||
|
// Reset User Module ready flag
|
||
|
g_fTrayIconReady = FALSE;
|
||
|
|
||
|
TRACE1 (USER, "ElUserLogoffCallback: UserloggedOff = %ld",
|
||
|
g_fUserLoggedOn);
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
|
||
|
|
||
|
for (dwIndex = 0; dwIndex < PORT_TABLE_BUCKETS; dwIndex++)
|
||
|
{
|
||
|
for (pPCB = g_PCBTable.pPCBBuckets[dwIndex].pPorts;
|
||
|
pPCB != NULL;
|
||
|
pPCB = pPCB->pNext)
|
||
|
{
|
||
|
fSetCONNECTINGState = FALSE;
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
switch (pPCB->dwEAPOLAuthMode)
|
||
|
{
|
||
|
case EAPOL_AUTH_MODE_0:
|
||
|
|
||
|
if (pPCB->State == EAPOLSTATE_AUTHENTICATED)
|
||
|
{
|
||
|
if (pPCB->PreviousAuthenticationType !=
|
||
|
EAPOL_MACHINE_AUTHENTICATION)
|
||
|
{
|
||
|
fSetCONNECTINGState = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
(VOID) ElEapEnd (pPCB);
|
||
|
fSetCONNECTINGState = TRUE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOL_AUTH_MODE_1:
|
||
|
|
||
|
(VOID) ElEapEnd (pPCB);
|
||
|
fSetCONNECTINGState = TRUE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case EAPOL_AUTH_MODE_2:
|
||
|
|
||
|
// Do nothing
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogoffCallback: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
fSetCONNECTINGState = FALSE;
|
||
|
}
|
||
|
|
||
|
// Set port to EAPOLSTATE_CONNECTING
|
||
|
if (fSetCONNECTINGState)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB,
|
||
|
EAPOL_USER_LOGOFF, pPCB->pwszFriendlyName);
|
||
|
|
||
|
// First send out EAPOL_Logoff message
|
||
|
if ((dwRetCode = FSMLogoff (pPCB, NULL))
|
||
|
!= NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogoffCallback: Error in FSMLogoff = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = NO_ERROR;
|
||
|
}
|
||
|
|
||
|
pPCB->dwAuthFailCount = 0;
|
||
|
|
||
|
// With Unauthenticated_access, port will always
|
||
|
// reauthenticate
|
||
|
pPCB->PreviousAuthenticationType =
|
||
|
EAPOL_UNAUTHENTICATED_ACCESS;
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
// Restart authentication on the port
|
||
|
if ((dwRetCode = ElReStartPort (pPCB, 0, NULL))
|
||
|
!= NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElUserLogoffCallback: Error in ElReStartPort = %ld",
|
||
|
dwRetCode);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
RELEASE_WRITE_LOCK (&(g_PCBLock));
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
TRACE0 (USER, "ElUserLogoffCallback: completed");
|
||
|
|
||
|
if (pvContext != NULL)
|
||
|
{
|
||
|
FREE (pvContext);
|
||
|
}
|
||
|
|
||
|
InterlockedDecrement (&g_lWorkerThreads);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElGetUserIdentity
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called to initiate and get user identity on a particular
|
||
|
// interface. The RasEapGetIdentity in the appropriate DLL is called
|
||
|
// with the necessary arguments.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to PCB for the specific port/interface
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElGetUserIdentity (
|
||
|
IN EAPOL_PCB *pPCB
|
||
|
)
|
||
|
{
|
||
|
HANDLE hLib = NULL;
|
||
|
RASEAPFREE pFreeFunc = NULL;
|
||
|
RASEAPGETIDENTITY pIdenFunc = NULL;
|
||
|
DWORD dwIndex = -1;
|
||
|
DWORD cbData = 0;
|
||
|
PBYTE pbAuthData = NULL;
|
||
|
PBYTE pbUserIn = NULL;
|
||
|
DWORD dwInSize = 0;
|
||
|
BYTE *pUserDataOut;
|
||
|
DWORD dwSizeOfUserDataOut;
|
||
|
LPWSTR lpwszIdentity = NULL;
|
||
|
CHAR *pszIdentity = NULL;
|
||
|
HWND hwndOwner = NULL;
|
||
|
DWORD dwFlags = 0;
|
||
|
BYTE *pbSSID = NULL;
|
||
|
DWORD dwSizeOfSSID = 0;
|
||
|
EAPOL_STATE TmpEAPOLState;
|
||
|
EAPOL_EAP_UI_CONTEXT *pEAPUIContext = NULL;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
TRACE0 (USER, "ElGetUserIdentity entered");
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (PORT, "ElGetUserIdentity: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
// Port is not active, cannot do further processing on this port
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->PreviousAuthenticationType != EAPOL_MACHINE_AUTHENTICATION)
|
||
|
{
|
||
|
// Get Access Token for user logged on interactively
|
||
|
|
||
|
if (pPCB->hUserToken != NULL)
|
||
|
{
|
||
|
if (!CloseHandle (pPCB->hUserToken))
|
||
|
{
|
||
|
dwRetCode = GetLastError ();
|
||
|
TRACE1 (USER, "ElGetUserIdentity: CloseHandle failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
pPCB->hUserToken = NULL;
|
||
|
|
||
|
if ((dwRetCode = ElGetWinStationUserToken (g_dwCurrentSessionId, &pPCB->hUserToken)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: ElGetWinStationUserToken failed with error (%ld)",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NO_TOKEN;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try to fetch user identity without sending request to
|
||
|
// user module. If not possible, send request to user module
|
||
|
//
|
||
|
|
||
|
if ((dwRetCode = ElGetUserIdentityOptimized (pPCB))
|
||
|
!= ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION)
|
||
|
{
|
||
|
TRACE0 (USER, "ElGetUserIdentity: ElGetUserIdentityOptimized got identity without user module intervention");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
if ((dwRetCode = ElCheckUserModuleReady ()) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: ElCheckUserModuleReady failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_WARN, pPCB, EAPOL_WAITING_FOR_DESKTOP_LOAD);
|
||
|
dwRetCode = ERROR_IO_PENDING;
|
||
|
TRACE0 (USER, "ElGetUserIdentity: TrayIcon NOT ready");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call GetUserIdentityDlgWorker
|
||
|
//
|
||
|
|
||
|
pEAPUIContext = MALLOC (sizeof(EAPOL_EAP_UI_CONTEXT));
|
||
|
if (pEAPUIContext == NULL)
|
||
|
{
|
||
|
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pEAPUIContext");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pEAPUIContext->dwEAPOLUIMsgType = EAPOLUI_GET_USERIDENTITY;
|
||
|
wcscpy (pEAPUIContext->wszGUID, pPCB->pwszDeviceGUID);
|
||
|
pPCB->dwUIInvocationId =
|
||
|
InterlockedIncrement(&(g_dwEAPUIInvocationId));
|
||
|
pEAPUIContext->dwSessionId = g_dwCurrentSessionId;
|
||
|
pEAPUIContext->dwContextId = pPCB->dwUIInvocationId;
|
||
|
pEAPUIContext->dwEapId = pPCB->bCurrentEAPId;
|
||
|
pEAPUIContext->dwEapTypeId = pPCB->dwEapTypeToBeUsed;
|
||
|
pEAPUIContext->dwEapFlags = pPCB->dwEapFlags;
|
||
|
if (pPCB->pwszSSID)
|
||
|
{
|
||
|
wcscpy (pEAPUIContext->wszSSID, pPCB->pwszSSID);
|
||
|
}
|
||
|
if (pPCB->pSSID)
|
||
|
{
|
||
|
pEAPUIContext->dwSizeOfSSID = pPCB->pSSID->SsidLength;
|
||
|
memcpy ((BYTE *)pEAPUIContext->bSSID, (BYTE *)pPCB->pSSID->Ssid,
|
||
|
NDIS_802_11_SSID_LEN-sizeof(ULONG));
|
||
|
}
|
||
|
|
||
|
// Have to notify state change before we post balloon
|
||
|
TmpEAPOLState = pPCB->State;
|
||
|
pPCB->State = EAPOLSTATE_ACQUIRED;
|
||
|
ElNetmanNotify (pPCB, EAPOL_NCS_CRED_REQUIRED, NULL);
|
||
|
// State is changed only in FSMAcquired
|
||
|
// Revert to original
|
||
|
pPCB->State = TmpEAPOLState;
|
||
|
|
||
|
// Post the message to netman
|
||
|
|
||
|
if ((dwRetCode = ElPostShowBalloonMessage (
|
||
|
pPCB,
|
||
|
sizeof(EAPOL_EAP_UI_CONTEXT),
|
||
|
(BYTE *)pEAPUIContext,
|
||
|
0,
|
||
|
NULL
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: ElPostShowBalloonMessage failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Restart PCB timer since UI may take longer time than required
|
||
|
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pPCB->EapUIState = EAPUISTATE_WAITING_FOR_IDENTITY;
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_WAITING_FOR_DESKTOP_IDENTITY);
|
||
|
|
||
|
// Return error code as pending, since credentials have still not
|
||
|
// been acquired
|
||
|
dwRetCode = ERROR_IO_PENDING;
|
||
|
|
||
|
}
|
||
|
else // MACHINE_AUTHENTICATION
|
||
|
{
|
||
|
|
||
|
pPCB->hUserToken = NULL;
|
||
|
|
||
|
// The EAP dll will have already been loaded by the state machine
|
||
|
// Retrieve the handle to the dll from the global EAP table
|
||
|
|
||
|
if ((dwIndex = ElGetEapTypeIndex (pPCB->dwEapTypeToBeUsed)) == -1)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: ElGetEapTypeIndex finds no dll for EAP index %ld",
|
||
|
pPCB->dwEapTypeToBeUsed);
|
||
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hLib = g_pEapTable[dwIndex].hInstance;
|
||
|
|
||
|
pIdenFunc = (RASEAPGETIDENTITY)GetProcAddress(hLib,
|
||
|
"RasEapGetIdentity");
|
||
|
pFreeFunc = (RASEAPFREE)GetProcAddress(hLib, "RasEapFreeMemory");
|
||
|
|
||
|
if ((pFreeFunc == NULL) || (pIdenFunc == NULL))
|
||
|
{
|
||
|
TRACE0 (USER, "ElGetUserIdentity: pIdenFunc or pFreeFunc does not exist in the EAP implementation");
|
||
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->pSSID)
|
||
|
{
|
||
|
pbSSID = pPCB->pSSID->Ssid;
|
||
|
dwSizeOfSSID = pPCB->pSSID->SsidLength;
|
||
|
}
|
||
|
|
||
|
// Get the size of the EAP blob
|
||
|
if ((dwRetCode = ElGetCustomAuthData (
|
||
|
pPCB->pwszDeviceGUID,
|
||
|
pPCB->dwEapTypeToBeUsed,
|
||
|
dwSizeOfSSID,
|
||
|
pbSSID,
|
||
|
NULL,
|
||
|
&cbData
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
if (dwRetCode == ERROR_BUFFER_TOO_SMALL)
|
||
|
{
|
||
|
if (cbData <= 0)
|
||
|
{
|
||
|
// No EAP blob stored in the registry
|
||
|
TRACE0 (USER, "ElGetUserIdentity: NULL sized EAP blob: continue");
|
||
|
pbAuthData = NULL;
|
||
|
// Every port should have connection data !!!
|
||
|
dwRetCode = NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Allocate memory to hold the blob
|
||
|
pbAuthData = MALLOC (cbData);
|
||
|
if (pbAuthData == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE0 (USER, "ElGetUserIdentity: Error in memory allocation for EAP blob");
|
||
|
break;
|
||
|
}
|
||
|
if ((dwRetCode = ElGetCustomAuthData (
|
||
|
pPCB->pwszDeviceGUID,
|
||
|
pPCB->dwEapTypeToBeUsed,
|
||
|
dwSizeOfSSID,
|
||
|
pbSSID,
|
||
|
pbAuthData,
|
||
|
&cbData
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: ElGetCustomAuthData failed with %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// CustomAuthData for "Default" is always created for an
|
||
|
// interface when EAPOL starts up
|
||
|
TRACE1 (USER, "ElGetUserIdentity: ElGetCustomAuthData size estimation failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pIdenFunc)
|
||
|
if ((dwRetCode = (*(pIdenFunc))(
|
||
|
pPCB->dwEapTypeToBeUsed,
|
||
|
hwndOwner, // hwndOwner
|
||
|
RAS_EAP_FLAG_MACHINE_AUTH, // dwFlags
|
||
|
NULL, // lpszPhonebook
|
||
|
pPCB->pwszFriendlyName, // lpszEntry
|
||
|
pbAuthData, // Connection data
|
||
|
cbData, // Count of pbAuthData
|
||
|
pbUserIn, // User data for port
|
||
|
dwInSize, // Size of user data
|
||
|
&pUserDataOut,
|
||
|
&dwSizeOfUserDataOut,
|
||
|
&lpwszIdentity
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
if (dwRetCode == ERROR_NO_EAPTLS_CERTIFICATE)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_NO_CERTIFICATE_MACHINE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_ERROR_GET_IDENTITY, EAPOLAuthTypes[EAPOL_MACHINE_AUTHENTICATION], dwRetCode);
|
||
|
}
|
||
|
TRACE1 (USER, "ElGetUserIdentity: Error in calling GetIdentity = %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Fill in the returned information into the PCB fields for
|
||
|
// later authentication
|
||
|
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
|
||
|
pPCB->pCustomAuthUserData = MALLOC (dwSizeOfUserDataOut + sizeof (DWORD));
|
||
|
if (pPCB->pCustomAuthUserData == NULL)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: Error in allocating memory for UserInfo = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData = dwSizeOfUserDataOut;
|
||
|
|
||
|
if ((dwSizeOfUserDataOut != 0) && (pUserDataOut != NULL))
|
||
|
{
|
||
|
memcpy ((BYTE *)pPCB->pCustomAuthUserData->pbCustomAuthData,
|
||
|
(BYTE *)pUserDataOut,
|
||
|
dwSizeOfUserDataOut);
|
||
|
}
|
||
|
|
||
|
if (lpwszIdentity != NULL)
|
||
|
{
|
||
|
pszIdentity = MALLOC (wcslen(lpwszIdentity)*sizeof(CHAR) + sizeof(CHAR));
|
||
|
if (pszIdentity == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pszIdentity");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (0 == WideCharToMultiByte (
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
lpwszIdentity,
|
||
|
-1,
|
||
|
pszIdentity,
|
||
|
wcslen(lpwszIdentity)*sizeof(CHAR)+sizeof(CHAR),
|
||
|
NULL,
|
||
|
NULL ))
|
||
|
{
|
||
|
dwRetCode = GetLastError();
|
||
|
TRACE2 (USER, "ElGetUserIdentity: WideCharToMultiByte (%ws) failed: %ld",
|
||
|
lpwszIdentity, dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
TRACE1 (USER, "ElGetUserIdentity: Got identity = %s",
|
||
|
pszIdentity);
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
pPCB->pszIdentity = MALLOC (strlen(pszIdentity) + sizeof(CHAR));
|
||
|
if (pPCB->pszIdentity == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pPCB->pszIdentity");
|
||
|
break;
|
||
|
}
|
||
|
memcpy (pPCB->pszIdentity, pszIdentity, strlen (pszIdentity));
|
||
|
pPCB->pszIdentity[strlen(pszIdentity)] = '\0';
|
||
|
}
|
||
|
|
||
|
if (pPCB->pCustomAuthConnData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthConnData);
|
||
|
pPCB->pCustomAuthConnData = NULL;
|
||
|
}
|
||
|
|
||
|
pPCB->pCustomAuthConnData = MALLOC (cbData + sizeof (DWORD));
|
||
|
if (pPCB->pCustomAuthConnData == NULL)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: Error in allocating memory for AuthInfo = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData = cbData;
|
||
|
|
||
|
if ((cbData != 0) && (pbAuthData != NULL))
|
||
|
{
|
||
|
memcpy ((BYTE *)pPCB->pCustomAuthConnData->pbCustomAuthData,
|
||
|
(BYTE *)pbAuthData,
|
||
|
cbData);
|
||
|
}
|
||
|
|
||
|
// Mark the identity has been obtained for this PCB
|
||
|
pPCB->fGotUserIdentity = TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
// Cleanup
|
||
|
if ((dwRetCode != NO_ERROR) && (dwRetCode != ERROR_IO_PENDING))
|
||
|
{
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pEAPUIContext != NULL)
|
||
|
{
|
||
|
FREE (pEAPUIContext);
|
||
|
}
|
||
|
|
||
|
if (pbUserIn != NULL)
|
||
|
{
|
||
|
FREE (pbUserIn);
|
||
|
}
|
||
|
|
||
|
if (pbAuthData != NULL)
|
||
|
{
|
||
|
FREE (pbAuthData);
|
||
|
}
|
||
|
|
||
|
if (pFreeFunc != NULL)
|
||
|
{
|
||
|
if (lpwszIdentity != NULL)
|
||
|
{
|
||
|
if (( dwRetCode = (*(pFreeFunc)) ((BYTE *)lpwszIdentity)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: Error in pFreeFunc = %ld",
|
||
|
dwRetCode);
|
||
|
}
|
||
|
}
|
||
|
if (pUserDataOut != NULL)
|
||
|
{
|
||
|
if (( dwRetCode = (*(pFreeFunc)) ((BYTE *)pUserDataOut)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserIdentity: Error in pFreeFunc = %ld",
|
||
|
dwRetCode);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TRACE1 (USER, "ElGetUserIdentity completed with error %ld", dwRetCode);
|
||
|
|
||
|
return dwRetCode;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElProcessUserIdentityResponse
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function to handle UI response for ElGetUserIdentityResponse
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Return values:
|
||
|
//
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElProcessUserIdentityResponse (
|
||
|
IN EAPOL_EAP_UI_CONTEXT EapolUIContext,
|
||
|
IN EAPOLUI_RESP EapolUIResp
|
||
|
)
|
||
|
{
|
||
|
DWORD dwSizeOfIdentity = 0;
|
||
|
BYTE *pbIdentity = NULL;
|
||
|
DWORD dwSizeOfUserData = 0;
|
||
|
BYTE *pbUserData = NULL;
|
||
|
DWORD dwSizeofConnData = 0;
|
||
|
BYTE *pbConnData = NULL;
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
EAPOL_EAP_UI_CONTEXT *pEAPUIContext = NULL;
|
||
|
BOOLEAN fPortReferenced = FALSE;
|
||
|
BOOLEAN fPCBLocked = FALSE;
|
||
|
BOOLEAN fBlobCopyIncomplete = FALSE;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
pEAPUIContext = (EAPOL_EAP_UI_CONTEXT *)&EapolUIContext;
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if ((pPCB = ElGetPCBPointerFromPortGUID (pEAPUIContext->wszGUID)) != NULL)
|
||
|
{
|
||
|
if (EAPOL_REFERENCE_PORT (pPCB))
|
||
|
{
|
||
|
fPortReferenced = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if (pPCB == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
fPCBLocked = TRUE;
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
|
||
|
// Port is not active, cannot do further processing on this port
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pEAPUIContext->dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
|
||
|
EAPOL_ERROR_DESKTOP_IDENTITY, dwRetCode);
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: Error in Dialog function (%ld)",
|
||
|
pEAPUIContext->dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->EapUIState != EAPUISTATE_WAITING_FOR_IDENTITY)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessUserIdentityResponse: PCB EapUIState has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->EapUIState, EAPUISTATE_WAITING_FOR_IDENTITY);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->dwUIInvocationId != pEAPUIContext->dwContextId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessUserIdentityResponse: PCB UI Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->dwUIInvocationId, pEAPUIContext->dwContextId);
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->bCurrentEAPId != pEAPUIContext->dwEapId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessUserIdentityResponse: PCB EAP Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->bCurrentEAPId, pEAPUIContext->dwEapId);
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
// Since the PCB context is right, restart PCB timer to timeout
|
||
|
// in authPeriod seconds
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwauthPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_PROCESSING_DESKTOP_RESPONSE);
|
||
|
|
||
|
if ((EapolUIResp.rdData0.dwDataLen != 0) && (EapolUIResp.rdData0.pData != NULL))
|
||
|
{
|
||
|
dwSizeOfIdentity = EapolUIResp.rdData0.dwDataLen;
|
||
|
pbIdentity = EapolUIResp.rdData0.pData;
|
||
|
}
|
||
|
|
||
|
if ((EapolUIResp.rdData1.dwDataLen != 0) && (EapolUIResp.rdData1.pData != NULL))
|
||
|
{
|
||
|
dwSizeOfUserData = EapolUIResp.rdData1.dwDataLen;
|
||
|
pbUserData = EapolUIResp.rdData1.pData;
|
||
|
}
|
||
|
|
||
|
if ((EapolUIResp.rdData2.dwDataLen != 0) && (EapolUIResp.rdData2.pData != NULL))
|
||
|
{
|
||
|
dwSizeofConnData = EapolUIResp.rdData2.dwDataLen;
|
||
|
pbConnData = EapolUIResp.rdData2.pData;
|
||
|
}
|
||
|
|
||
|
fBlobCopyIncomplete = TRUE;
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
if (pbIdentity != NULL)
|
||
|
{
|
||
|
pPCB->pszIdentity = MALLOC (dwSizeOfIdentity + sizeof(CHAR));
|
||
|
if (pPCB->pszIdentity == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE0 (USER, "ElProcessUserIdentityResponse: MALLOC failed for pPCB->pszIdentity");
|
||
|
break;
|
||
|
}
|
||
|
memcpy (pPCB->pszIdentity, pbIdentity, dwSizeOfIdentity);
|
||
|
pPCB->pszIdentity[dwSizeOfIdentity] = '\0';
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: Got username = %s",
|
||
|
pPCB->pszIdentity);
|
||
|
}
|
||
|
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
pPCB->pCustomAuthUserData = MALLOC (dwSizeOfUserData + sizeof (DWORD));
|
||
|
if (pPCB->pCustomAuthUserData == NULL)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: Error in allocating memory for UserInfo = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData = dwSizeOfUserData;
|
||
|
if ((dwSizeOfUserData != 0) && (pbUserData != NULL))
|
||
|
{
|
||
|
memcpy ((BYTE *)pPCB->pCustomAuthUserData->pbCustomAuthData,
|
||
|
(BYTE *)pbUserData,
|
||
|
dwSizeOfUserData);
|
||
|
}
|
||
|
|
||
|
if (pPCB->pCustomAuthConnData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthConnData);
|
||
|
pPCB->pCustomAuthConnData = NULL;
|
||
|
}
|
||
|
pPCB->pCustomAuthConnData = MALLOC (dwSizeofConnData + sizeof (DWORD));
|
||
|
if (pPCB->pCustomAuthConnData == NULL)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: Error in allocating memory for AuthInfo = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData = dwSizeofConnData;
|
||
|
if ((dwSizeofConnData != 0) && (pbConnData != NULL))
|
||
|
{
|
||
|
memcpy ((BYTE *)pPCB->pCustomAuthConnData->pbCustomAuthData,
|
||
|
(BYTE *)pbConnData,
|
||
|
dwSizeofConnData);
|
||
|
}
|
||
|
|
||
|
fBlobCopyIncomplete = FALSE;
|
||
|
|
||
|
if ((dwRetCode = ElCreateAndSendIdentityResponse (
|
||
|
pPCB, pEAPUIContext)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserIdentityResponse: ElCreateAndSendIdentityResponse failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Mark the identity has been obtained for this PCB
|
||
|
pPCB->fGotUserIdentity = TRUE;
|
||
|
|
||
|
// Reset the state if identity was obtained, else port will
|
||
|
// recover by itself
|
||
|
pPCB->EapUIState &= ~EAPUISTATE_WAITING_FOR_IDENTITY;
|
||
|
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
// Cleanup
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
if (fPCBLocked && fBlobCopyIncomplete)
|
||
|
{
|
||
|
if (pPCB->pCustomAuthUserData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pCustomAuthUserData);
|
||
|
pPCB->pCustomAuthUserData = NULL;
|
||
|
}
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fPCBLocked)
|
||
|
{
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
}
|
||
|
|
||
|
if (fPortReferenced)
|
||
|
{
|
||
|
EAPOL_DEREFERENCE_PORT (pPCB);
|
||
|
}
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElGetUserNamePassword
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called to get username, domain (if any) and password using
|
||
|
// an interactive dialog. Called if EAP-type is MD5
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to PCB for the port/interface on which credentials
|
||
|
// are to be obtained
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElGetUserNamePassword (
|
||
|
IN EAPOL_PCB *pPCB
|
||
|
)
|
||
|
{
|
||
|
EAPOL_EAP_UI_CONTEXT *pEAPUIContext = NULL;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
TRACE0 (USER, "ElGetUserNamePassword entered");
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (PORT, "ElGetUserNamePassword: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
// Port is not active, cannot do further processing on this port
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Get Access Token for user logged on interactively
|
||
|
|
||
|
if (pPCB->hUserToken != NULL)
|
||
|
{
|
||
|
if (!CloseHandle (pPCB->hUserToken))
|
||
|
{
|
||
|
dwRetCode = GetLastError ();
|
||
|
TRACE1 (USER, "ElGetUserNamePassword: CloseHandle failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
pPCB->hUserToken = NULL;
|
||
|
|
||
|
if ((dwRetCode = ElGetWinStationUserToken (g_dwCurrentSessionId, &pPCB->hUserToken)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserNamePassword: ElGetWinStationUserToken failed with error (%ld)",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NO_TOKEN;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
if ((dwRetCode = ElCheckUserModuleReady ()) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserNamePassword: ElCheckUserModuleReady failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_WARN, pPCB, EAPOL_WAITING_FOR_DESKTOP_LOAD);
|
||
|
dwRetCode = ERROR_IO_PENDING;
|
||
|
TRACE0 (USER, "ElGetUserNamePassword: TrayIcon NOT ready");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call ElGetUserNamePasswordDlgWorker
|
||
|
//
|
||
|
|
||
|
pEAPUIContext = MALLOC (sizeof(EAPOL_EAP_UI_CONTEXT));
|
||
|
if (pEAPUIContext == NULL)
|
||
|
{
|
||
|
TRACE0 (USER, "ElGetUserNamePassword: MALLOC failed for pEAPUIContext");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pEAPUIContext->dwEAPOLUIMsgType = EAPOLUI_GET_USERNAMEPASSWORD;
|
||
|
wcscpy (pEAPUIContext->wszGUID, pPCB->pwszDeviceGUID);
|
||
|
pPCB->dwUIInvocationId =
|
||
|
InterlockedIncrement(&(g_dwEAPUIInvocationId));
|
||
|
pEAPUIContext->dwSessionId = g_dwCurrentSessionId;
|
||
|
pEAPUIContext->dwContextId = pPCB->dwUIInvocationId;
|
||
|
pEAPUIContext->dwEapId = pPCB->bCurrentEAPId;
|
||
|
pEAPUIContext->dwEapTypeId = pPCB->dwEapTypeToBeUsed;
|
||
|
pEAPUIContext->dwEapFlags = pPCB->dwEapFlags;
|
||
|
if (pPCB->pSSID)
|
||
|
{
|
||
|
memcpy ((BYTE *)pEAPUIContext->bSSID, (BYTE *)pPCB->pSSID->Ssid,
|
||
|
NDIS_802_11_SSID_LEN-sizeof(ULONG));
|
||
|
pEAPUIContext->dwSizeOfSSID = pPCB->pSSID->SsidLength;
|
||
|
}
|
||
|
if (pPCB->pwszSSID)
|
||
|
{
|
||
|
wcscpy (pEAPUIContext->wszSSID, pPCB->pwszSSID);
|
||
|
}
|
||
|
|
||
|
// Post the message to netman
|
||
|
|
||
|
if ((dwRetCode = ElPostShowBalloonMessage (
|
||
|
pPCB,
|
||
|
sizeof(EAPOL_EAP_UI_CONTEXT),
|
||
|
(BYTE *)pEAPUIContext,
|
||
|
0,
|
||
|
NULL
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElGetUserNamePassword: ElPostShowBalloonMessage failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Restart PCB timer since UI may take longer time than required
|
||
|
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pPCB->EapUIState = EAPUISTATE_WAITING_FOR_IDENTITY;
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_WAITING_FOR_DESKTOP_IDENTITY);
|
||
|
|
||
|
// Return error code as pending, since credentials have still not
|
||
|
// been acquired
|
||
|
dwRetCode = ERROR_IO_PENDING;
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
if ((dwRetCode != NO_ERROR) && (dwRetCode != ERROR_IO_PENDING))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
if (pEAPUIContext)
|
||
|
{
|
||
|
FREE (pEAPUIContext);
|
||
|
}
|
||
|
|
||
|
TRACE1 (USER, "ElGetUserNamePassword completed with error %ld", dwRetCode);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElProcessUserNamePasswordResponse
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// UI Response handler function for ElGetUserNamePassword
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// non-zero - error
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElProcessUserNamePasswordResponse (
|
||
|
IN EAPOL_EAP_UI_CONTEXT EapolUIContext,
|
||
|
IN EAPOLUI_RESP EapolUIResp
|
||
|
)
|
||
|
{
|
||
|
DWORD dwSizeOfIdentity = 0;
|
||
|
BYTE *pbIdentity = NULL;
|
||
|
DWORD dwSizeOfPassword = 0;
|
||
|
BYTE *pbPassword = NULL;
|
||
|
HWND hwndOwner = NULL;
|
||
|
BOOLEAN fPCBLocked = FALSE;
|
||
|
BOOLEAN fPortReferenced = FALSE;
|
||
|
BOOLEAN fBlobCopyIncomplete = FALSE;
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
EAPOL_EAP_UI_CONTEXT *pEAPUIContext = NULL;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
TRACE0 (USER, "ElProcessUserNamePasswordResponse entered");
|
||
|
|
||
|
pEAPUIContext = (EAPOL_EAP_UI_CONTEXT *)&EapolUIContext;
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if ((pPCB = ElGetPCBPointerFromPortGUID (pEAPUIContext->wszGUID)) != NULL)
|
||
|
{
|
||
|
if (EAPOL_REFERENCE_PORT (pPCB))
|
||
|
{
|
||
|
fPortReferenced = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if (pPCB == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
fPCBLocked = TRUE;
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (PORT, "ElProcessUserNamePasswordResponse: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
// Port is not active, cannot do further processing on this port
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pEAPUIContext->dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
|
||
|
EAPOL_ERROR_DESKTOP_IDENTITY, dwRetCode);
|
||
|
TRACE1 (USER, "ElProcessUserNamePasswordResponse: Error in Dialog function (%ld)",
|
||
|
pEAPUIContext->dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->EapUIState != EAPUISTATE_WAITING_FOR_IDENTITY)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessUserNamePasswordResponse: PCB EapUIState has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->EapUIState, EAPUISTATE_WAITING_FOR_IDENTITY);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->dwUIInvocationId != pEAPUIContext->dwContextId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessUserNamePasswordResponse: PCB UI Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->dwUIInvocationId, pEAPUIContext->dwContextId);
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->bCurrentEAPId != pEAPUIContext->dwEapId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessUserNamePasswordResponse: PCB EAP Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->bCurrentEAPId, pEAPUIContext->dwEapId);
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
// Since the PCB context is right, restart PCB timer to timeout
|
||
|
// in authPeriod seconds
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwauthPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserNamePasswordResponse: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_PROCESSING_DESKTOP_RESPONSE);
|
||
|
|
||
|
if ((EapolUIResp.rdData0.dwDataLen != 0) && (EapolUIResp.rdData0.pData != NULL))
|
||
|
{
|
||
|
dwSizeOfIdentity = EapolUIResp.rdData0.dwDataLen;
|
||
|
pbIdentity = EapolUIResp.rdData0.pData;
|
||
|
}
|
||
|
|
||
|
if ((EapolUIResp.rdData1.dwDataLen != 0) && (EapolUIResp.rdData1.pData != NULL))
|
||
|
{
|
||
|
dwSizeOfPassword = EapolUIResp.rdData1.dwDataLen;
|
||
|
pbPassword = EapolUIResp.rdData1.pData;
|
||
|
}
|
||
|
|
||
|
fBlobCopyIncomplete = TRUE;
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
|
||
|
if (pPCB->PasswordBlob.pbData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->PasswordBlob.pbData);
|
||
|
pPCB->PasswordBlob.pbData = NULL;
|
||
|
pPCB->PasswordBlob.cbData = 0;
|
||
|
}
|
||
|
|
||
|
if (pbIdentity != NULL)
|
||
|
{
|
||
|
pPCB->pszIdentity = MALLOC (dwSizeOfIdentity + sizeof(CHAR));
|
||
|
if (pPCB->pszIdentity == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE0 (USER, "ElProcessUserNamePasswordResponse: MALLOC failed for pPCB->pszIdentity");
|
||
|
break;
|
||
|
}
|
||
|
memcpy (pPCB->pszIdentity, pbIdentity, dwSizeOfIdentity);
|
||
|
pPCB->pszIdentity[dwSizeOfIdentity] = '\0';
|
||
|
TRACE1 (USER, "ElProcessUserNamePasswordResponse: Got username = %s",
|
||
|
pPCB->pszIdentity);
|
||
|
}
|
||
|
|
||
|
if (pbPassword != 0)
|
||
|
{
|
||
|
if ((pPCB->PasswordBlob.pbData =
|
||
|
MALLOC (dwSizeOfPassword)) == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
memcpy (pPCB->PasswordBlob.pbData, pbPassword, dwSizeOfPassword);
|
||
|
pPCB->PasswordBlob.cbData = dwSizeOfPassword;
|
||
|
}
|
||
|
|
||
|
fBlobCopyIncomplete = FALSE;
|
||
|
|
||
|
if ((dwRetCode = ElCreateAndSendIdentityResponse (
|
||
|
pPCB, pEAPUIContext)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessUserNamePasswordResponse: ElCreateAndSendIdentityResponse failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Mark the identity has been obtained for this PCB
|
||
|
pPCB->fGotUserIdentity = TRUE;
|
||
|
|
||
|
// Reset the state if identity was obtained, else the port will recover
|
||
|
// by itself
|
||
|
pPCB->EapUIState &= ~EAPUISTATE_WAITING_FOR_IDENTITY;
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
if (fPCBLocked && fBlobCopyIncomplete)
|
||
|
{
|
||
|
if (pPCB->pszIdentity)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
if (pPCB->PasswordBlob.pbData)
|
||
|
{
|
||
|
FREE (pPCB->PasswordBlob.pbData);
|
||
|
pPCB->PasswordBlob.pbData = NULL;
|
||
|
pPCB->PasswordBlob.cbData = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fPCBLocked)
|
||
|
{
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
}
|
||
|
|
||
|
if (fPortReferenced)
|
||
|
{
|
||
|
EAPOL_DEREFERENCE_PORT (pPCB);
|
||
|
}
|
||
|
|
||
|
TRACE1 (USER, "ElProcessUserNamePasswordResponse completed with error %ld", dwRetCode);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElInvokeInteractiveUI
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called to invoke RasEapInvokeInteractiveUI for an EAP on a
|
||
|
// particular interface
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Pointer to PCB for the specific interface
|
||
|
// pInvokeEapUIIn - Data to be supplied to the InvokeInteractiveUI entrypoint
|
||
|
// provided by the EAP dll through PPP_EAP_OUTPUT structure
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElInvokeInteractiveUI (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN ELEAP_INVOKE_EAP_UI *pInvokeEapUIIn
|
||
|
)
|
||
|
{
|
||
|
EAPOL_EAP_UI_CONTEXT *pEAPUIContext = NULL;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (pInvokeEapUIIn == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_INVALID_PARAMETER;
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
if (pPCB->PreviousAuthenticationType == EAPOL_MACHINE_AUTHENTICATION)
|
||
|
{
|
||
|
TRACE0 (USER, "ElInvokeInteractiveUI: Cannot popup UI during machine authentication");
|
||
|
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_CANNOT_DESKTOP_MACHINE_AUTH);
|
||
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
if ((dwRetCode = ElCheckUserModuleReady ()) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElInvokeInteractiveUI: ElCheckUserModuleReady failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!g_fTrayIconReady)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_WARN, pPCB, EAPOL_WAITING_FOR_DESKTOP_LOAD);
|
||
|
dwRetCode = ERROR_IO_PENDING;
|
||
|
TRACE0 (USER, "ElInvokeInteractiveUI: TrayIcon NOT ready");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
TRACE0 (USER, "ElInvokeInteractiveUI entered");
|
||
|
|
||
|
//
|
||
|
// Call ElInvokeInteractiveUIDlgWorker
|
||
|
//
|
||
|
|
||
|
pEAPUIContext = MALLOC (sizeof(EAPOL_EAP_UI_CONTEXT) +
|
||
|
pInvokeEapUIIn->dwSizeOfUIContextData);
|
||
|
if (pEAPUIContext == NULL)
|
||
|
{
|
||
|
TRACE0 (USER, "ElInvokeInteractiveUI: MALLOC failed for pEAPUIContext");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pEAPUIContext->dwEAPOLUIMsgType = EAPOLUI_INVOKEINTERACTIVEUI;
|
||
|
wcscpy (pEAPUIContext->wszGUID, pPCB->pwszDeviceGUID);
|
||
|
pPCB->dwUIInvocationId =
|
||
|
InterlockedIncrement(&(g_dwEAPUIInvocationId));
|
||
|
pEAPUIContext->dwSessionId = g_dwCurrentSessionId;
|
||
|
pEAPUIContext->dwContextId = pPCB->dwUIInvocationId;
|
||
|
pEAPUIContext->dwEapId = pPCB->bCurrentEAPId;
|
||
|
pEAPUIContext->dwEapTypeId = pPCB->dwEapTypeToBeUsed;
|
||
|
pEAPUIContext->dwEapFlags = pPCB->dwEapFlags;
|
||
|
if (pPCB->pSSID)
|
||
|
{
|
||
|
pEAPUIContext->dwSizeOfSSID = pPCB->pSSID->SsidLength;
|
||
|
memcpy ((BYTE *)pEAPUIContext->bSSID, (BYTE *)pPCB->pSSID->Ssid,
|
||
|
NDIS_802_11_SSID_LEN-sizeof(ULONG));
|
||
|
}
|
||
|
if (pPCB->pwszSSID)
|
||
|
{
|
||
|
wcscpy (pEAPUIContext->wszSSID, pPCB->pwszSSID);
|
||
|
}
|
||
|
pEAPUIContext->dwSizeOfEapUIData =
|
||
|
pInvokeEapUIIn->dwSizeOfUIContextData;
|
||
|
memcpy (pEAPUIContext->bEapUIData, pInvokeEapUIIn->pbUIContextData,
|
||
|
pInvokeEapUIIn->dwSizeOfUIContextData);
|
||
|
|
||
|
// Post the message to netman
|
||
|
|
||
|
if ((dwRetCode = ElPostShowBalloonMessage (
|
||
|
pPCB,
|
||
|
sizeof(EAPOL_EAP_UI_CONTEXT)+pInvokeEapUIIn->dwSizeOfUIContextData,
|
||
|
(BYTE *)pEAPUIContext,
|
||
|
0,
|
||
|
NULL
|
||
|
)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElInvokeInteractiveUI: ElPostShowBalloonMessage failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Restart PCB timer since UI may take longer time than required
|
||
|
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
INFINITE_SECONDS,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pPCB->EapUIState = EAPUISTATE_WAITING_FOR_UI_RESPONSE;
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_WAITING_FOR_DESKTOP_LOGON);
|
||
|
|
||
|
TRACE0 (USER, "ElInvokeInteractiveUI: ElEapWork completed successfully");
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
if (pInvokeEapUIIn->pbUIContextData != NULL)
|
||
|
{
|
||
|
FREE (pInvokeEapUIIn->pbUIContextData);
|
||
|
pInvokeEapUIIn->pbUIContextData = NULL;
|
||
|
pInvokeEapUIIn->dwSizeOfUIContextData = 0;
|
||
|
}
|
||
|
|
||
|
if (pEAPUIContext != NULL)
|
||
|
{
|
||
|
FREE (pEAPUIContext);
|
||
|
}
|
||
|
|
||
|
TRACE1 (USER, "ElInvokeInteractiveUI completed with error %ld", dwRetCode);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElProcessInvokeInteractiveUIResponse
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Worker function for ElInvokeInteractiveUI
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElProcessInvokeInteractiveUIResponse (
|
||
|
IN EAPOL_EAP_UI_CONTEXT EapolUIContext,
|
||
|
IN EAPOLUI_RESP EapolUIResp
|
||
|
)
|
||
|
{
|
||
|
BYTE *pbUIData = NULL;
|
||
|
DWORD dwSizeOfUIData = 0;
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
EAPOL_EAP_UI_CONTEXT *pEAPUIContext = NULL;
|
||
|
BOOLEAN fPortReferenced = FALSE;
|
||
|
BOOLEAN fPCBLocked = FALSE;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
TRACE0 (USER, "ElProcessInvokeInteractiveUIResponse entered");
|
||
|
|
||
|
pEAPUIContext = (EAPOL_EAP_UI_CONTEXT *)&EapolUIContext;
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if ((pPCB = ElGetPCBPointerFromPortGUID (pEAPUIContext->wszGUID)) != NULL)
|
||
|
{
|
||
|
if (EAPOL_REFERENCE_PORT (pPCB))
|
||
|
{
|
||
|
fPortReferenced = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if (pPCB == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
fPCBLocked = TRUE;
|
||
|
|
||
|
if (!EAPOL_PORT_ACTIVE(pPCB))
|
||
|
{
|
||
|
TRACE1 (PORT, "ElProcessInvokeInteractiveUIResponse: Port %ws not active",
|
||
|
pPCB->pwszDeviceGUID);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pEAPUIContext->dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_ERROR_DESKTOP_LOGON, dwRetCode);
|
||
|
TRACE1 (USER, "ElProcessInvokeInteractiveUIResponse: Error in Dialog function (%ld)",
|
||
|
pEAPUIContext->dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->EapUIState != EAPUISTATE_WAITING_FOR_UI_RESPONSE)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessInvokeInteractiveUIResponse: PCB EapUIState has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->EapUIState, EAPUISTATE_WAITING_FOR_UI_RESPONSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->dwUIInvocationId != pEAPUIContext->dwContextId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessInvokeInteractiveUIResponse: PCB UI Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->dwUIInvocationId, pEAPUIContext->dwContextId);
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->bCurrentEAPId != pEAPUIContext->dwEapId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElProcessInvokeInteractiveUIResponse: PCB EAP Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->bCurrentEAPId, pEAPUIContext->dwEapId);
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
// Since the PCB context is right, restart PCB timer to timeout
|
||
|
// in authPeriod seconds
|
||
|
RESTART_TIMER (pPCB->hTimer,
|
||
|
pPCB->EapolConfig.dwauthPeriod,
|
||
|
"PCB",
|
||
|
&dwRetCode);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessInvokeInteractiveUIResponse: Error in RESTART_TIMER %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_PROCESSING_DESKTOP_RESPONSE);
|
||
|
|
||
|
if ((EapolUIResp.rdData0.dwDataLen != 0) && (EapolUIResp.rdData0.pData != NULL))
|
||
|
{
|
||
|
dwSizeOfUIData = EapolUIResp.rdData0.dwDataLen;
|
||
|
pbUIData = EapolUIResp.rdData0.pData;
|
||
|
}
|
||
|
|
||
|
if (pPCB->EapUIData.pEapUIData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->EapUIData.pEapUIData);
|
||
|
pPCB->EapUIData.pEapUIData = NULL;
|
||
|
pPCB->EapUIData.dwSizeOfEapUIData = 0;
|
||
|
}
|
||
|
pPCB->EapUIData.pEapUIData = MALLOC (dwSizeOfUIData);
|
||
|
if (pPCB->EapUIData.pEapUIData == NULL)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessInvokeInteractiveUIResponse: Error in allocating memory for UIData = %ld",
|
||
|
dwRetCode);
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pPCB->EapUIData.dwSizeOfEapUIData = dwSizeOfUIData;
|
||
|
if ((dwSizeOfUIData != 0) && (pbUIData != NULL))
|
||
|
{
|
||
|
memcpy ((BYTE *)pPCB->EapUIData.pEapUIData,
|
||
|
(BYTE *)pbUIData,
|
||
|
dwSizeOfUIData);
|
||
|
}
|
||
|
|
||
|
pPCB->EapUIData.dwContextId = pPCB->dwUIInvocationId;
|
||
|
|
||
|
pPCB->fEapUIDataReceived = TRUE;
|
||
|
|
||
|
TRACE0 (USER, "ElProcessInvokeInteractiveUIResponse: Calling ElEapWork");
|
||
|
|
||
|
// Provide UI data to EAP Dll for processing
|
||
|
// EAP will send out response if required
|
||
|
|
||
|
if ((dwRetCode = ElEapWork (
|
||
|
pPCB,
|
||
|
NULL)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElProcessInvokeInteractiveUIResponse: ElEapWork failed with error = %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Reset the state
|
||
|
pPCB->EapUIState &= ~EAPUISTATE_WAITING_FOR_UI_RESPONSE;
|
||
|
|
||
|
TRACE0 (USER, "ElProcessInvokeInteractiveUIResponse: ElEapWork completed successfully");
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
// Cleanup
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
if (pPCB->EapUIData.pEapUIData != NULL)
|
||
|
{
|
||
|
FREE (pPCB->EapUIData.pEapUIData);
|
||
|
pPCB->EapUIData.pEapUIData = NULL;
|
||
|
pPCB->EapUIData.dwSizeOfEapUIData = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fPCBLocked)
|
||
|
{
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
}
|
||
|
|
||
|
if (fPortReferenced)
|
||
|
{
|
||
|
EAPOL_DEREFERENCE_PORT (pPCB);
|
||
|
}
|
||
|
|
||
|
TRACE1 (USER, "ElProcessInvokeInteractiveUIResponse completed with error %ld",
|
||
|
dwRetCode);
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElCreateAndSendIdentityResponse
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called send out Identity Response packet
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pPCB - Port Control Block for appropriate interface
|
||
|
// pEAPUIContext - UI context blob
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// !NO_ERROR - error
|
||
|
//
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElCreateAndSendIdentityResponse (
|
||
|
IN EAPOL_PCB *pPCB,
|
||
|
IN EAPOL_EAP_UI_CONTEXT *pEAPUIContext
|
||
|
)
|
||
|
{
|
||
|
PPP_EAP_PACKET *pSendBuf = NULL;
|
||
|
EAPOL_PACKET *pEapolPkt = NULL;
|
||
|
WORD wSizeOfEapPkt = 0;
|
||
|
DWORD dwIdentityLength = 0;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Create buffer for EAPOL + EAP and pass pointer to EAP header
|
||
|
|
||
|
pEapolPkt = (EAPOL_PACKET *) MALLOC (MAX_EAPOL_BUFFER_SIZE);
|
||
|
|
||
|
TRACE1 (EAPOL, "ElCreateAndSendIdResp: EapolPkt created at %p", pEapolPkt);
|
||
|
|
||
|
if (pEapolPkt == NULL)
|
||
|
{
|
||
|
TRACE0 (EAPOL, "ElCreateAndSendIdResp: Error allocating EAP buffer");
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Point to EAP header
|
||
|
pSendBuf = (PPP_EAP_PACKET *)((PBYTE)pEapolPkt + sizeof (EAPOL_PACKET) - 1);
|
||
|
|
||
|
pSendBuf->Code = EAPCODE_Response;
|
||
|
pSendBuf->Id = (BYTE)pPCB->bCurrentEAPId;
|
||
|
|
||
|
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, "ElCreateAndSendIdResp: Identity sent out = %s",
|
||
|
pPCB->pszIdentity);
|
||
|
|
||
|
pSendBuf->Data[0] = EAPTYPE_Identity;
|
||
|
|
||
|
// Indicate to EAPOL what is length of the EAP packet
|
||
|
wSizeOfEapPkt = (WORD)(PPP_EAP_PACKET_HDR_LEN+
|
||
|
1+dwIdentityLength);
|
||
|
|
||
|
// Send out EAPOL packet
|
||
|
|
||
|
memcpy ((BYTE *)pEapolPkt->EthernetType,
|
||
|
(BYTE *)pPCB->bEtherType,
|
||
|
SIZE_ETHERNET_TYPE);
|
||
|
pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
|
||
|
pEapolPkt->PacketType = EAP_Packet;
|
||
|
|
||
|
HostToWireFormat16 ((WORD) 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)+wSizeOfEapPkt-1);
|
||
|
|
||
|
if (pPCB->pbPreviousEAPOLPkt == NULL)
|
||
|
{
|
||
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
memcpy (pPCB->pbPreviousEAPOLPkt, pEapolPkt,
|
||
|
sizeof (EAPOL_PACKET)+wSizeOfEapPkt-1);
|
||
|
|
||
|
pPCB->dwSizeOfPreviousEAPOLPkt =
|
||
|
sizeof (EAPOL_PACKET)+wSizeOfEapPkt-1;
|
||
|
|
||
|
pPCB->dwPreviousId = pPCB->bCurrentEAPId;
|
||
|
|
||
|
// Send packet out on the port
|
||
|
dwRetCode = ElWriteToPort (pPCB,
|
||
|
(CHAR *)pEapolPkt,
|
||
|
sizeof (EAPOL_PACKET)+wSizeOfEapPkt-1);
|
||
|
if (dwRetCode != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (EAPOL, "ElCreateAndSendIdResp: Error in writing EAP_Packet to port %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
if (pEapolPkt != NULL)
|
||
|
{
|
||
|
FREE (pEapolPkt);
|
||
|
}
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// ElSendGuestIdentityResponse
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Function called send out Guest Identity Response packet
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pEAPUIContext - UI context blob
|
||
|
//
|
||
|
// Return values:
|
||
|
// NO_ERROR - success
|
||
|
// !NO_ERROR - failure
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ElSendGuestIdentityResponse (
|
||
|
IN EAPOL_EAP_UI_CONTEXT *pEAPUIContext
|
||
|
)
|
||
|
{
|
||
|
EAPOL_PCB *pPCB = NULL;
|
||
|
BOOLEAN fPortReferenced = FALSE;
|
||
|
BOOLEAN fPCBLocked = FALSE;
|
||
|
DWORD dwRetCode = NO_ERROR;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
ACQUIRE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if ((pPCB = ElGetPCBPointerFromPortGUID (pEAPUIContext->wszGUID)) != NULL)
|
||
|
{
|
||
|
if (EAPOL_REFERENCE_PORT (pPCB))
|
||
|
{
|
||
|
fPortReferenced = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPCB = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RELEASE_WRITE_LOCK (&g_PCBLock);
|
||
|
|
||
|
if (pPCB == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
|
||
|
fPCBLocked = TRUE;
|
||
|
|
||
|
// Send the identity out as a EAP-Response packet
|
||
|
|
||
|
if (pPCB->EapUIState != EAPUISTATE_WAITING_FOR_IDENTITY)
|
||
|
{
|
||
|
TRACE2 (USER, "ElSendGuestIdentityResponse: PCB EapUIState has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->EapUIState, EAPUISTATE_WAITING_FOR_IDENTITY);
|
||
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->dwUIInvocationId != pEAPUIContext->dwContextId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElSendGuestIdentityResponse: PCB UI Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->dwUIInvocationId, pEAPUIContext->dwContextId);
|
||
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->bCurrentEAPId != pEAPUIContext->dwEapId)
|
||
|
{
|
||
|
TRACE2 (USER, "ElSendGuestIdentityResponse: PCB EAP Id has changed to (%ld), expected = (%ld)",
|
||
|
pPCB->bCurrentEAPId, pEAPUIContext->dwEapId);
|
||
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pPCB->pszIdentity != NULL)
|
||
|
{
|
||
|
FREE (pPCB->pszIdentity);
|
||
|
pPCB->pszIdentity = NULL;
|
||
|
}
|
||
|
|
||
|
// Do not flag that identity was received
|
||
|
// Reset the UI state though for state machine to proceed
|
||
|
pPCB->EapUIState &= ~EAPUISTATE_WAITING_FOR_IDENTITY;
|
||
|
pPCB->PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
|
||
|
|
||
|
if ((dwRetCode = ElCreateAndSendIdentityResponse (
|
||
|
pPCB, pEAPUIContext)) != NO_ERROR)
|
||
|
{
|
||
|
TRACE1 (USER, "ElSendGuestIdentityResponse: ElCreateAndSendIdentityResponse failed with error %ld",
|
||
|
dwRetCode);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
if (fPCBLocked)
|
||
|
{
|
||
|
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
|
||
|
}
|
||
|
|
||
|
if (fPortReferenced)
|
||
|
{
|
||
|
EAPOL_DEREFERENCE_PORT (pPCB);
|
||
|
}
|
||
|
|
||
|
return dwRetCode;
|
||
|
}
|
||
|
|