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

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;
}