windows-nt/Source/XPSP1/NT/net/config/netman/eapol/service/eluser.c

2206 lines
66 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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
//
// Test code declarations for EAP-MD5CHAP
//
// This function is not defined in any header file. Located in
// $(SDK_LIB_PATH)\irnotif.lib
extern HANDLE
GetCurrentUserTokenW (
WCHAR Winsta[],
DWORD DesiredAccess
);
extern BOOL
GetWinStationUserToken(ULONG, PHANDLE);
extern ULONG
GetClientLogonId ();
#define cszEapKeyRas TEXT("Software\\Microsoft\\RAS EAP\\UserEapInfo")
#define cszEapValue TEXT("EapInfo")
#ifndef EAPOL_SERVICE
#define cszModuleName TEXT("netman.dll")
#else
#define cszModuleName TEXT("eapol.exe")
#endif
//
// 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 hUserToken;
HANDLE hLib = NULL;
EAPOLEAPFREE pFreeFunc = NULL;
EAPOLEAPGETIDENTITY pIdenFunc = NULL;
DWORD dwIndex = -1;
DWORD cbData = 0;
PBYTE pbAuthData = NULL;
PBYTE pbUserIn = NULL;
DWORD dwInSize = 0;
BYTE *pUserDataOut;
DWORD dwSizeOfUserDataOut;
LPWSTR lpwszIdentity = NULL;
HWND hwndOwner = NULL;
HWINSTA hwinstaSave;
HDESK hdeskSave;
HWINSTA hwinstaUser;
HDESK hdeskUser;
DWORD dwThreadId;
UNICODE_STRING IdentityUnicodeString;
ANSI_STRING IdentityAnsiString;
CHAR Buffer[256];
WCHAR wszFriendlyName[256]; // Friendly name max 255 char
CHAR *pszUserName = NULL;
DWORD dwFlags = 0;
DWORD dwRetCode = NO_ERROR;
do
{
// If machine auth not enabled
TRACE0 (USER, "ElGetUserIdentity entered");
//
// NOTE:
// Optimize pPCB->rwLock lock holding time
//
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
if (pPCB->PreviousAuthenticationType != EAPOL_MACHINE_AUTHENTICATION)
{
if (!EAPOL_PORT_ACTIVE(pPCB))
{
TRACE1 (PORT, "ElGetUserIdentity: Port %s not active",
pPCB->pszDeviceGUID);
// Port is not active, cannot do further processing on this port
break;
}
//
// Get Access Token for user logged on interactively
//
// Call Terminal Services API
if (GetWinStationUserToken (GetClientLogonId(), &hUserToken)
!= NO_ERROR)
{
TRACE0 (USER, "ElGetUserIdentity: Terminal Services API GetWinStationUserToken failed !!! ");
// Call private API
hUserToken = GetCurrentUserTokenW (L"WinSta0",
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY);
if (hUserToken == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElGetUserIdentity: Error in GetCurrentUserTokenW = %ld",
dwRetCode);
dwRetCode = ERROR_NO_TOKEN;
break;
}
}
if (hUserToken == NULL)
{
dwRetCode = GetLastError ();
TRACE0 (USER, "ElGetUserIdentity: Error in getting current user token");
dwRetCode = ERROR_NO_TOKEN;
break;
}
pPCB->hUserToken = hUserToken;
// Get the size of the user blob
if ((dwRetCode = ElGetEapUserInfo (
pPCB->hUserToken,
pPCB->pszDeviceGUID,
pPCB->dwEapTypeToBeUsed,
pPCB->pszSSID,
NULL,
&dwInSize
)) != NO_ERROR)
{
if (dwRetCode == ERROR_BUFFER_TOO_SMALL)
{
if (dwInSize <= 0)
{
// No blob stored in the registry
// Continue processing
TRACE0 (USER, "ElGetUserIdentity: NULL sized user data");
pbUserIn = NULL;
}
else
{
// Allocate memory to hold the blob
pbUserIn = MALLOC (dwInSize);
if (pbUserIn == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElGetUserIdentity: Error in memory allocation for User data");
break;
}
if ((dwRetCode = ElGetEapUserInfo (
pPCB->hUserToken,
pPCB->pszDeviceGUID,
pPCB->dwEapTypeToBeUsed,
pPCB->pszSSID,
pbUserIn,
&dwInSize
)) != NO_ERROR)
{
TRACE1 (USER, "ElGetUserIdentity: ElGetEapUserInfo failed with %ld",
dwRetCode);
break;
}
}
}
else
{
// User info may not have been created till now
// which is valid condition to proceed
if (dwRetCode != ERROR_FILE_NOT_FOUND)
{
TRACE1 (USER, "ElGetUserIdentity: ElGetEapUserInfo size estimation failed with error %ld",
dwRetCode);
break;
}
}
}
// 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 = (EAPOLEAPGETIDENTITY)GetProcAddress(hLib,
"RasEapGetIdentity");
pFreeFunc = (EAPOLEAPFREE)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;
}
// Get the size of the EAP blob
if ((dwRetCode = ElGetCustomAuthData (
pPCB->pszDeviceGUID,
pPCB->dwEapTypeToBeUsed,
pPCB->pszSSID,
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, cannot continue");
pbAuthData = NULL;
// Every port should have connection data !!!
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
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->pszDeviceGUID,
pPCB->dwEapTypeToBeUsed,
pPCB->pszSSID,
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;
}
}
// Save handles to service window
hwinstaSave = GetProcessWindowStation();
if (hwinstaSave == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "OpenWindowStation: GetProcessWindowStation failed with error %ld",
dwRetCode);
break;
}
dwThreadId = GetCurrentThreadId ();
hdeskSave = GetThreadDesktop (dwThreadId);
if (hdeskSave == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "OpenWindowStation: GetThreadDesktop failed with error %ld",
dwRetCode);
break;
}
if (!ImpersonateLoggedOnUser (pPCB->hUserToken))
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetUserIdentity: ImpersonateLoggedOnUse failed with error %ld",
dwRetCode);
break;
}
// Impersonate the client and connect to the User's window station
// and desktop. This will be the interactively logged-on user
hwinstaUser = OpenWindowStation (L"WinSta0", FALSE, MAXIMUM_ALLOWED);
if (hwinstaUser == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "OpenWindowStation: OpenWindowStation failed with error %ld",
dwRetCode);
break;
}
if (!SetProcessWindowStation(hwinstaUser))
TRACE1 (USER, "ElGetUserIdentity: SetProcessWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
hdeskUser = OpenDesktop (L"Default", 0, FALSE, MAXIMUM_ALLOWED);
if (hdeskUser == NULL)
{
if (!SetProcessWindowStation (hwinstaSave))
TRACE1 (USER, "ElGetUserIdentity: SetProcessWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseWindowStation (hwinstaUser))
TRACE1 (USER, "ElGetUserIdentity: CloseWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
dwRetCode = ERROR_INVALID_WORKSTATION;
break;
}
if (!SetThreadDesktop (hdeskUser))
TRACE1 (USER, "ElGetUserIdentity: SetThreadDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
// Get handle to desktop window
hwndOwner = GetDesktopWindow ();
ZeroMemory (wszFriendlyName, 256*sizeof(WCHAR));
// Convert the friendly name of the adapter to a display ready
// form
if (pPCB->pszFriendlyName)
{
if (0 == MultiByteToWideChar(
CP_ACP,
0,
pPCB->pszFriendlyName,
-1,
wszFriendlyName,
256 ) )
{
dwRetCode = GetLastError();
TRACE2 (USER, "ElGetUserIdentity: MultiByteToWideChar(%s) failed: %d",
pPCB->pszFriendlyName,
dwRetCode);
break;
}
}
if (pIdenFunc)
if ((dwRetCode = (*(pIdenFunc))(
pPCB->dwEapTypeToBeUsed,
hwndOwner, // hwndOwner
0, // dwFlags
NULL, // lpszPhonebook
wszFriendlyName, // lpszEntry
pbAuthData, // Connection data
cbData, // Count of pbAuthData
pbUserIn, // User data for port
dwInSize, // Size of user data
&pUserDataOut,
&dwSizeOfUserDataOut,
&lpwszIdentity
)) != NO_ERROR)
{
TRACE1 (USER, "ElGetUserIdentity: Error in calling GetIdentity = %ld",
dwRetCode);
// Revert impersonation
if (!RevertToSelf())
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetUserIdentity: Error in RevertToSelf = %ld",
dwRetCode);
}
// Restore window station and desktop
if (!SetThreadDesktop (hdeskSave))
TRACE1 (USER, "ElGetUserIdentity: SetThreadDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
if (!SetProcessWindowStation (hwinstaSave))
TRACE1 (USER, "ElGetUserIdentity: SetProcessWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseDesktop(hdeskUser))
TRACE1 (USER, "ElGetUserIdentity: CloseDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseWindowStation(hwinstaUser))
TRACE1 (USER, "ElGetUserIdentity: CloseWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
break;
}
// Revert impersonation
if (!RevertToSelf())
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetUserIdentity: Error in RevertToSelf = %ld",
dwRetCode);
// Restore window station and desktop
if (!SetThreadDesktop (hdeskSave))
TRACE1 (USER, "ElGetUserIdentity: SetThreadDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
if (!SetProcessWindowStation (hwinstaSave))
TRACE1 (USER, "ElGetUserIdentity: SetProcessWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseDesktop(hdeskUser))
TRACE1 (USER, "ElGetUserIdentity: CloseDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseWindowStation(hwinstaUser))
TRACE1 (USER, "ElGetUserIdentity: CloseWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
break;
}
// Restore window station and desktop settings
if (!SetThreadDesktop (hdeskSave))
TRACE1 (USER, "ElGetUserIdentity: SetThreadDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
if (!SetProcessWindowStation (hwinstaSave))
TRACE1 (USER, "ElGetUserIdentity: SetProcessWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseDesktop(hdeskUser))
TRACE1 (USER, "ElGetUserIdentity: CloseDesktop failed with error = %ld",
(dwRetCode = GetLastError()));
if (!CloseWindowStation(hwinstaUser))
TRACE1 (USER, "ElGetUserIdentity: CloseWindowStation failed with error = %ld",
(dwRetCode = GetLastError()));
// 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)
{
// NOTE:
// Assuming 256 character identity maximum
// Convert wchar Identity to char string
RtlInitUnicodeString (&IdentityUnicodeString, lpwszIdentity);
IdentityAnsiString.MaximumLength = sizeof(Buffer);
IdentityAnsiString.Buffer = Buffer;
IdentityAnsiString.Length = 0;
if ((dwRetCode = RtlUnicodeStringToAnsiString (
&IdentityAnsiString,
&IdentityUnicodeString,
FALSE)) != NO_ERROR)
{
TRACE1 (USER, "ElGetUserIdentity: Error in RtlConvertUnicodeStringToAnsiString = %ld",
dwRetCode);
break;
}
pszUserName = MALLOC (IdentityAnsiString.Length + 1);
if (pszUserName == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pszUserName");
break;
}
memcpy (pszUserName,
IdentityAnsiString.Buffer,
IdentityAnsiString.Length);
pszUserName[IdentityAnsiString.Length] = '\0';
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
pPCB->pszIdentity = MALLOC (IdentityAnsiString.Length + 1);
if (pPCB->pszIdentity == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pPCB->pszIdentity");
break;
}
memcpy (pPCB->pszIdentity,
IdentityAnsiString.Buffer,
IdentityAnsiString.Length);
pPCB->pszIdentity[IdentityAnsiString.Length] = '\0';
TRACE1 (USER, "ElGetUserIdentity: Got username = %s",
pszUserName);
}
if (pPCB->pCustomAuthConnData != NULL)
{
FREE (pPCB->pCustomAuthConnData);
pPCB->pCustomAuthConnData = NULL;
}
// Memory for pCustomAuthConnData and pCustomAuthUserData
// is released from the PCB when user logs off and during
// port deletion
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;
}
else // MACHINE_AUTHENTICATION
{
TRACE0 (USER, "ElGetUserIdentity entered");
if (!EAPOL_PORT_ACTIVE(pPCB))
{
TRACE1 (PORT, "ElGetUserIdentity: Port %s not active",
pPCB->pszDeviceGUID);
// Port is not active, cannot do further processing on this port
break;
}
// 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 = (EAPOLEAPGETIDENTITY)GetProcAddress(hLib,
"RasEapGetIdentity");
pFreeFunc = (EAPOLEAPFREE)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;
}
// Get the size of the EAP blob
if ((dwRetCode = ElGetCustomAuthData (
pPCB->pszDeviceGUID,
pPCB->dwEapTypeToBeUsed,
pPCB->pszSSID,
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, cannot continue");
pbAuthData = NULL;
// Every port should have connection data !!!
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
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->pszDeviceGUID,
pPCB->dwEapTypeToBeUsed,
pPCB->pszSSID,
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
wszFriendlyName, // lpszEntry
pbAuthData, // Connection data
cbData, // Count of pbAuthData
pbUserIn, // User data for port
dwInSize, // Size of user data
&pUserDataOut,
&dwSizeOfUserDataOut,
&lpwszIdentity
)) != NO_ERROR)
{
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)
{
// NOTE:
// Assuming 256 character identity maximum
// Convert wchar Identity to char string
RtlInitUnicodeString (&IdentityUnicodeString, lpwszIdentity);
IdentityAnsiString.MaximumLength = sizeof(Buffer);
IdentityAnsiString.Buffer = Buffer;
IdentityAnsiString.Length = 0;
if ((dwRetCode = RtlUnicodeStringToAnsiString (
&IdentityAnsiString,
&IdentityUnicodeString,
FALSE)) != NO_ERROR)
{
TRACE1 (USER, "ElGetUserIdentity: Error in RtlConvertUnicodeStringToAnsiString = %ld",
dwRetCode);
break;
}
TRACE1 (USER, "lpwszIdentity = %ws", lpwszIdentity);
pszUserName = MALLOC (IdentityAnsiString.Length + 1);
if (pszUserName == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pszUserName");
break;
}
memcpy (pszUserName,
IdentityAnsiString.Buffer,
IdentityAnsiString.Length);
pszUserName[IdentityAnsiString.Length] = '\0';
TRACE1 (USER, "pszUserName = %s", pszUserName);
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
pPCB->pszIdentity = MALLOC (IdentityAnsiString.Length + 1);
if (pPCB->pszIdentity == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElGetUserIdentity: MALLOC failed for pPCB->pszIdentity");
break;
}
memcpy (pPCB->pszIdentity,
IdentityAnsiString.Buffer,
IdentityAnsiString.Length);
pPCB->pszIdentity[IdentityAnsiString.Length] = '\0';
TRACE1 (USER, "ElGetUserIdentity: Got username = %s",
pszUserName);
}
if (pPCB->pCustomAuthConnData != NULL)
{
FREE (pPCB->pCustomAuthConnData);
pPCB->pCustomAuthConnData = NULL;
}
// Memory for pCustomAuthConnData and pCustomAuthUserData
// is released from the PCB when user logs off and during
// port deletion
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;
}
// Release the per-interface lock
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
} while (FALSE);
// Cleanup
if (dwRetCode != NO_ERROR)
{
// Release the per-interface lock
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
if (pPCB->pCustomAuthUserData != NULL)
{
FREE (pPCB->pCustomAuthUserData);
pPCB->pCustomAuthUserData = NULL;
}
if (pPCB->pCustomAuthConnData != NULL)
{
FREE (pPCB->pCustomAuthConnData);
pPCB->pCustomAuthConnData = NULL;
}
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
}
if (pbUserIn != NULL)
{
FREE (pbUserIn);
}
if (pbAuthData != NULL)
{
FREE (pbAuthData);
}
if (pszUserName != NULL)
{
FREE (pszUserName);
}
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;
}
//
// 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.
//
VOID
ElUserLogonCallback (
PVOID pvContext,
BOOLEAN fTimerOfWaitFired
)
{
DWORD dwIndex = 0;
EAPOL_PCB *pPCB = NULL;
BOOL fSetCONNECTINGState = FALSE;
DWORD dwRetCode = NO_ERROR;
// Set global flag to indicate the user logged on
TRACE1 (USER, "ElUserLogonCallback: UserloggedOn = %ld",
g_fUserLoggedOn);
g_fUserLoggedOn = InterlockedIncrement (&(g_fUserLoggedOn));
do
{
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)
{
#ifdef DRAFT7
if (g_dwMachineAuthEnabled)
{
#endif
fSetCONNECTINGState = FALSE;
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
switch (pPCB->State)
{
case EAPOLSTATE_CONNECTING:
case EAPOLSTATE_ACQUIRED:
case EAPOLSTATE_AUTHENTICATING:
// Reset AuthFailCount conditionally
pPCB->dwAuthFailCount = 0;
// fall through
case EAPOLSTATE_HELD:
// End EAP session
(VOID) ElEapEnd (pPCB);
fSetCONNECTINGState = TRUE;
break;
case EAPOLSTATE_AUTHENTICATED:
if (pPCB->PreviousAuthenticationType ==
EAPOL_UNAUTHENTICATED_ACCESS)
{
// Reset AuthFailCount
pPCB->dwAuthFailCount = 0;
fSetCONNECTINGState = TRUE;
}
break;
default:
break;
}
if (!EAPOL_PORT_ACTIVE(pPCB))
{
TRACE1 (USER, "ElUserLogonCallback: Port %s not active",
pPCB->pszDeviceGUID);
fSetCONNECTINGState = FALSE;
}
// Set port to EAPOLSTATE_CONNECTING
if (fSetCONNECTINGState)
{
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)) != NO_ERROR)
{
TRACE1 (USER, "ElUserLogonCallback: MachineAuth: Error in ElReStartPort = %ld",
dwRetCode);
continue;
}
}
else
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
continue;
}
#ifdef DRAFT7
}
else
{
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
// If the port is already authenticated due to non-secure
// LAN, authentication can be skipped for this port
if (pPCB->State == EAPOLSTATE_AUTHENTICATED)
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
TRACE0 (USER, "ElUserLogonCallback: Port already authenticated, continuing with next port");
continue;
}
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
// Restart authentication on the port
if ((dwRetCode = ElReStartPort (pPCB)) != NO_ERROR)
{
TRACE1 (USER, "ElUserLogonCallback: Error in ElReStartPort = %ld",
dwRetCode);
break;
}
TRACE1 (USER, "ElUserLogonCallback: = Authentication restarted on port %p",
pPCB);
} // g_dwMachineAuthEnabled
#endif
}
}
RELEASE_WRITE_LOCK (&(g_PCBLock));
if (dwRetCode != NO_ERROR)
{
break;
}
} while (FALSE);
TRACE1 (USER, "ElUserLogonCallback: completed with error %ld", dwRetCode);
return;
}
//
// ElUserLogoffCallback
//
// Description:
//
// Callback function invoked whenever a user logs off
// Will logoff from all ports which have authentication enabled
//
// Arguments:
// None.
//
VOID
ElUserLogoffCallback (
PVOID pvContext,
BOOLEAN fTimerOfWaitFired
)
{
DWORD dwIndex = 0;
EAPOL_PCB *pPCB = NULL;
BOOL fSetCONNECTINGState = FALSE;
DWORD dwRetCode = NO_ERROR;
// Reset global flag to indicate the user logged on
g_fUserLoggedOn = 0;
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)
{
#ifdef DRAFT7
if (g_dwMachineAuthEnabled)
{
#endif
fSetCONNECTINGState = FALSE;
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
switch (pPCB->State)
{
case EAPOLSTATE_CONNECTING:
case EAPOLSTATE_ACQUIRED:
case EAPOLSTATE_AUTHENTICATING:
// Reset AuthFailCount conditionally
pPCB->dwAuthFailCount = 0;
// fall through
case EAPOLSTATE_HELD:
// End EAP session
(VOID) ElEapEnd (pPCB);
fSetCONNECTINGState = TRUE;
break;
case EAPOLSTATE_AUTHENTICATED:
if (pPCB->PreviousAuthenticationType ==
EAPOL_USER_AUTHENTICATION)
{
// Reset AuthFailCount
pPCB->dwAuthFailCount = 0;
fSetCONNECTINGState = TRUE;
}
break;
default:
break;
}
// Set port to EAPOLSTATE_CONNECTING
if (fSetCONNECTINGState)
{
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)) != NO_ERROR)
{
TRACE1 (USER, "ElUserLogoffCallback: MachineAuth: Error in ElReStartPort = %ld",
dwRetCode);
continue;
}
}
else
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
continue;
}
#ifdef DRAFT7
}
else
{
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
// If remote end has sent responses earlier and if EAPOL_Logoff
// was not sent out on this port, send out EAPOL_Logoff
if ((pPCB->fIsRemoteEndEAPOLAware) && (!(pPCB->dwLogoffSent)))
{
// End EAP session
// Will always return NO_ERROR, so no check on return value
(VOID) ElEapEnd (pPCB);
// Send out EAPOL_Logoff on the port
if ((dwRetCode = FSMLogoff (pPCB)) != NO_ERROR)
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
TRACE1 (USER, "ElUserLogoffCallback: Error in FSMLogoff = %ld",
dwRetCode);
continue;
}
}
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
TRACE1 (USER, "ElUserLogoffCallback: = Logoff sent out on port %p",
pPCB);
} // g_dwMachineAuthEnabled
#endif
}
}
RELEASE_WRITE_LOCK (&(g_PCBLock));
TRACE0 (USER, "ElUserLogonCallback: completed");
return;
}
//
// 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
//
//
// NOTE: Could be done in a better way. Require EAP config structures
// as in ..\ras\ui\rasdlg\dial.c
//
DWORD
ElGetUserNamePassword (
IN EAPOL_PCB *pPCB
)
{
HANDLE hUserToken;
DWORD dwIndex = -1;
DWORD dwInSize = 0;
HWND hwndOwner = NULL;
HWINSTA hwinstaSave;
HDESK hdeskSave;
HWINSTA hwinstaUser;
HDESK hdeskUser;
DWORD dwThreadId;
DWORD dwRetCode = NO_ERROR;
do
{
TRACE0 (USER, "ElGetUserNamePassword entered");
//
// NOTE:
// Optimize pPCB->rwLock lock holding time
//
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
if (!EAPOL_PORT_ACTIVE(pPCB))
{
TRACE1 (PORT, "ElGetUserNamePassword: Port %s not active",
pPCB->pszDeviceGUID);
// Port is not active, cannot do further processing on this port
break;
}
//
// Get Access Token for user logged on interactively
//
// Call Terminal Services API
if (GetWinStationUserToken (GetClientLogonId(), &hUserToken)
!= NO_ERROR)
{
TRACE0 (USER, "ElGetUserNamePassword: Terminal Services API GetWinStationUserToken failed !!! ");
// Call private API
hUserToken = GetCurrentUserTokenW (L"WinSta0",
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY);
if (hUserToken == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElGetUserNamePassword: Error in GetCurrentUserTokenW = %ld",
dwRetCode);
dwRetCode = ERROR_NO_TOKEN;
break;
}
}
if (hUserToken == NULL)
{
dwRetCode = GetLastError ();
TRACE0 (USER, "ElGetUserNamePassword: Error in getting current user token");
dwRetCode = ERROR_NO_TOKEN;
break;
}
pPCB->hUserToken = hUserToken;
// 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, "ElGetUserNamePassword: ElGetEapTypeIndex finds no dll for EAP index %ld",
pPCB->dwEapTypeToBeUsed);
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
// Save handles to service window
hwinstaSave = GetProcessWindowStation();
if (hwinstaSave == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElGetUserNamePassword: GetProcessWindowStation failed with error %ld",
dwRetCode);
break;
}
dwThreadId = GetCurrentThreadId ();
hdeskSave = GetThreadDesktop (dwThreadId);
if (hdeskSave == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElGetUserNamePassword: GetThreadDesktop failed with error %ld",
dwRetCode);
break;
}
if (!ImpersonateLoggedOnUser (pPCB->hUserToken))
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetUserNamePassword: ImpersonateLoggedOnUse failed with error %ld",
dwRetCode);
break;
}
// Impersonate the client and connect to the User's window station
// and desktop. This will be the interactively logged-on user
hwinstaUser = OpenWindowStation (L"WinSta0", FALSE, MAXIMUM_ALLOWED);
if (hwinstaUser == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElGetUserNamePassword: OpenWindowStation failed with error %ld",
dwRetCode);
break;
}
SetProcessWindowStation(hwinstaUser);
hdeskUser = OpenDesktop (L"Default", 0, FALSE, MAXIMUM_ALLOWED);
if (hdeskUser == NULL)
{
SetProcessWindowStation (hwinstaSave);
CloseWindowStation (hwinstaUser);
dwRetCode = ERROR_INVALID_WORKSTATION;
break;
}
SetThreadDesktop (hdeskUser);
// Get handle to desktop window
hwndOwner = GetDesktopWindow ();
//
// Call the user dialog for obtaining the username and password
//
if ((dwRetCode = ElUserDlg (hwndOwner, pPCB)) != NO_ERROR)
{
TRACE0 (USER, "ElGetUserNamePassword: ElUserDlg failed");
RevertToSelf();
// Restore window station and desktop
SetThreadDesktop (hdeskSave);
SetProcessWindowStation (hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
break;
}
// Revert impersonation
if (!RevertToSelf())
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetUserNamePassword: Error in RevertToSelf = %ld",
dwRetCode);
// Restore window station and desktop
SetThreadDesktop (hdeskSave);
SetProcessWindowStation (hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
break;
}
// Restore window station and desktop settings
SetThreadDesktop (hdeskSave);
SetProcessWindowStation (hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
// Mark the identity has been obtained for this PCB
pPCB->fGotUserIdentity = TRUE;
// Release the per-interface lock
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
} while (FALSE);
// Cleanup
if (dwRetCode != NO_ERROR)
{
// Release the per-interface lock
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
if (pPCB->pCustomAuthUserData != NULL)
{
FREE (pPCB->pCustomAuthUserData);
}
if (pPCB->pCustomAuthConnData != NULL)
{
FREE (pPCB->pCustomAuthConnData);
}
}
TRACE1 (USER, "ElGetUserNamePassword completed with error %ld", dwRetCode);
return dwRetCode;
}
//
// ElUserDlg
//
// Description:
//
// Function called to pop dialog box to user to enter username, password,
// domainname etc.
//
// Arguments:
// hwndOwner - handle to user desktop
// pPCB - Pointer to PCB for the port/interface on which credentials
// are to be obtained
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElUserDlg (
IN HWND hwndOwner,
IN EAPOL_PCB *pPCB
)
{
USERDLGARGS args;
DWORD dwRetCode = NO_ERROR;
TRACE0 (USER, "ElUserDlg: Entered");
args.pPCB = pPCB;
if ( DialogBoxParam (
GetModuleHandle(cszModuleName),
MAKEINTRESOURCE (DID_DR_DialerUD),
hwndOwner,
ElUserDlgProc,
(LPARAM)&args ) == -1)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlg: DialogBoxParam failed with error %ld",
dwRetCode);
}
return dwRetCode;
}
//
// ElUserDlgProc
//
// Description:
//
// Function handling all events for username/password/... dialog box
//
// Arguments:
// hwnd -
// unMsg -
// wparam -
// lparam -
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
INT_PTR
ElUserDlgProc (
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
{
switch (unMsg)
{
case WM_INITDIALOG:
{
return ElUserDlgInit( hwnd, (USERDLGARGS* )lparam );
break;
}
case WM_HELP:
case WM_CONTEXTMENU:
{
break;
}
case WM_COMMAND:
{
USERDLGINFO* pInfo = (USERDLGINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
return ElUserDlgCommand (
pInfo, HIWORD(wparam), LOWORD(wparam), (HWND)lparam );
break;
}
case WM_DESTROY:
{
USERDLGINFO* pInfo = (USERDLGINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ElUserDlgTerm (hwnd, pInfo);
break;
}
}
return FALSE;
}
BOOL
ElUserDlgInit (
IN HWND hwndDlg,
IN USERDLGARGS *pArgs
)
{
USERDLGINFO *pInfo = NULL;
WCHAR wszFriendlyName[256];
DWORD dwRetCode = NO_ERROR;
TRACE0 (USER, "ElUserDlgInit entered");
do
{
pInfo = MALLOC (sizeof (USERDLGINFO));
if (pInfo == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElUserDlgInit: MALLOC failed for pInfo");
break;
}
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr (hwndDlg, DWLP_USER, (ULONG_PTR)pInfo);
#if 0
if (!SetWindowLongPtr (hwndDlg, DWLP_USER, (ULONG_PTR)pInfo))
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlgInit: SetWindowLongPtr failed with error %ld",
dwRetCode);
break;
}
#endif
TRACE0 (USER, "ElUserDlgInit: Context Set");
//
// Set the title
//
ZeroMemory (wszFriendlyName, 256*sizeof(WCHAR));
// Convert the friendly name of the adapter to a display ready
// form
if (pArgs->pPCB->pszFriendlyName)
{
if (0 == MultiByteToWideChar(
CP_ACP,
0,
pArgs->pPCB->pszFriendlyName,
-1,
wszFriendlyName,
256 ) )
{
dwRetCode = GetLastError();
TRACE2 (USER, "ElUserDlgInit: MultiByteToWideChar(%s) failed: %d",
pArgs->pPCB->pszFriendlyName,
dwRetCode);
}
if (!SetWindowText (hwndDlg, wszFriendlyName))
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlgInit: SetWindowText failed with error %ld",
dwRetCode);
break;
}
}
else
{
if (!SetWindowText (hwndDlg, NULL))
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlgInit: SetWindowText - NULL failed with error %ld",
dwRetCode);
break;
}
}
pInfo->hwndEbUser = GetDlgItem( hwndDlg, CID_DR_EB_User );
ASSERT (pInfo->hwndEbUser);
pInfo->hwndEbPw = GetDlgItem( hwndDlg, CID_DR_EB_Password );
ASSERT (pInfo->hwndEbPw);
pInfo->hwndEbDomain = GetDlgItem( hwndDlg, CID_DR_EB_Domain );
ASSERT (pInfo->hwndEbDomain);
}
while (FALSE);
if (dwRetCode != NO_ERROR)
{
return FALSE;
}
else
{
return TRUE;
}
}
//
// ElUserDlgCommand
//
// Description:
//
// Function called on WM_COMMAND
// domainname etc.
//
// Arguments:
// PInfo - dialog context
// WNotification - notification code of the command
// wId - control/menu identifier of the command
// HwndCtrl - control window handle the command.
//
// Return values:
// TRUE - success
// FALSE - error
//
BOOL
ElUserDlgCommand (
IN USERDLGINFO *pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl
)
{
TRACE3 (USER, "ElUserDlgCommand: n=%d, i=%d, c=%x",
(DWORD)wNotification, (DWORD)wId, (ULONG_PTR)hwndCtrl);
switch (wId)
{
case IDOK:
case CID_DR_PB_DialConnect:
{
ElUserDlgSave (pInfo);
EndDialog (pInfo->hwndDlg, TRUE);
return TRUE;
}
case IDCANCEL:
case CID_DR_PB_Cancel:
{
EndDialog (pInfo->hwndDlg, TRUE);
return TRUE;
}
default:
{
TRACE0 (USER, "ElUserDlgCommand: Got something we are not interested in");
break;
}
}
return FALSE;
}
VOID
ElUserDlgSave (
IN USERDLGINFO *pInfo
)
{
EAPOL_PCB *pPCB = NULL;
int iError;
CHAR szUserName[UNLEN + 1];
CHAR szDomain[DNLEN + 1];
CHAR szPassword[DNLEN + 1];
DWORD dwRetCode = NO_ERROR;
pPCB = (EAPOL_PCB *)pInfo->pArgs->pPCB;
do
{
// Username
if ((iError =
GetWindowTextA(
pInfo->hwndEbUser,
&(szUserName[0]),
UNLEN + 1 )) == 0)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlgSave: GetWindowText - Username failed with error %ld",
dwRetCode);
}
szUserName[iError] = '\0';
TRACE1 (USER, "ElUserDlgSave: Get Username %s", szUserName);
// Password
if ((iError =
GetWindowTextA(
pInfo->hwndEbPw,
&(szPassword[0]),
PWLEN + 1 )) == 0)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlgSave: GetWindowText - Password failed with error %ld",
dwRetCode);
}
szPassword[iError] = '\0';
if (pPCB->pszPassword != NULL)
{
FREE (pPCB->pszPassword);
pPCB->pszPassword = NULL;
}
pPCB->pszPassword = MALLOC (strlen(szPassword) + 1);
if (pPCB->pszPassword == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElUserDlgSave: MALLOC failed for pPCB->pszPassword");
break;
}
memcpy (pPCB->pszPassword, szPassword, strlen(szPassword) + 1);
// Uncomment only if absolutely required
// Security issue, since we are writing trace to file
// TRACE1 (USER, "ElUserDlgSave: Got Password %s", pPCB->pszPassword);
// Domain
if ((iError =
GetWindowTextA(
pInfo->hwndEbDomain,
&(szDomain[0]),
DNLEN + 1 )) == 0)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElUserDlgSave: GetWindowText - Domain failed with error %ld",
dwRetCode);
}
szDomain[iError] = '\0';
TRACE1 (USER, "ElUserDlgSave: Got Domain %s", szDomain);
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
if ((szDomain != NULL) &&
(szDomain[0] != (CHAR)NULL))
{
pPCB->pszIdentity =
MALLOC (strlen(szDomain)+strlen(szUserName)+2);
if (pPCB->pszIdentity == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElUserDlgSave: MALLOC failed for pPCB->pszIdentity 1");
break;
}
strcpy (pPCB->pszIdentity, szDomain);
strcat( pPCB->pszIdentity, "\\" );
strcat (pPCB->pszIdentity, szUserName);
}
else
{
pPCB->pszIdentity =
MALLOC (strlen(szUserName)+1);
if (pPCB->pszIdentity == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (USER, "ElUserDlgSave: MALLOC failed for pPCB->pszIdentity 2");
break;
}
strcpy (pPCB->pszIdentity, szUserName);
}
TRACE1 (USER, "ElUserDlgSave: Got identity %s", pPCB->pszIdentity);
TRACE1 (USER, "ElUserDlgSave: PCB->GUID = %s", pPCB->pszDeviceGUID);
// Hash-up password while storing locally
ElEncodePw (pPCB->pszPassword);
}
while (FALSE);
if (dwRetCode != NO_ERROR)
{
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
if (pPCB->pszPassword != NULL)
{
FREE (pPCB->pszPassword);
pPCB->pszPassword = NULL;
}
}
return;
}
VOID
ElUserDlgTerm (
IN HWND hwndDlg,
IN USERDLGINFO *pInfo
)
{
EndDialog (hwndDlg, TRUE);
FREE (pInfo);
}
//
// 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
)
{
HANDLE hUserToken = NULL;
HANDLE hLib = NULL;
EAPOLEAPFREE pFreeFunc = NULL;
EAPOLEAPINVOKEINTERACTIVEUI pEapInvokeUI = NULL;
DWORD dwIndex = -1;
BYTE *pUIDataOut = NULL;
DWORD dwSizeOfUIDataOut;
HWND hwndOwner = NULL;
HWINSTA hwinstaSave = NULL;
HDESK hdeskSave = NULL;
HWINSTA hwinstaUser = NULL;
HDESK hdeskUser = NULL;
DWORD dwThreadId = 0;
DWORD dwRetCode = NO_ERROR;
do
{
TRACE0 (USER, "ElInvokeInteractiveUI entered");
// 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, "ElInvokeInteractiveUI: ElGetEapTypeIndex finds no dll for EAP index %ld",
pPCB->dwEapTypeToBeUsed);
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
hLib = g_pEapTable[dwIndex].hInstance;
pEapInvokeUI = (EAPOLEAPINVOKEINTERACTIVEUI) GetProcAddress
(hLib, "RasEapInvokeInteractiveUI");
pFreeFunc = (EAPOLEAPFREE) GetProcAddress (hLib, "RasEapFreeMemory");
if ((pFreeFunc == NULL) || (pEapInvokeUI == NULL))
{
TRACE0 (USER, "ElInvokeInteractiveUI: pEapInvokeUI or pFreeFunc does not exist in the EAP implementation");
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
// Get Access Token for user logged on interactively
// Call Terminal Services API
if (GetWinStationUserToken (GetClientLogonId(), &hUserToken)
!= NO_ERROR)
{
TRACE0 (USER, "ElInvokeInteractiveUI: Terminal Services API GetWinStationUserToken failed !!! ");
// Call private API
hUserToken = GetCurrentUserTokenW (L"WinSta0",
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY);
if (hUserToken == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElInvokeInteractiveUI: Error in GetCurrentUserTokenW = %ld",
dwRetCode);
dwRetCode = ERROR_NO_TOKEN;
break;
}
}
if (hUserToken == NULL)
{
dwRetCode = GetLastError ();
TRACE0 (USER, "ElInvokeInteractiveUI: Error in getting current user token");
dwRetCode = ERROR_NO_TOKEN;
break;
}
pPCB->hUserToken = hUserToken;
// Save handles to service window
hwinstaSave = GetProcessWindowStation();
if (hwinstaSave == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElInvokeInteractiveUI: GetProcessWindowStation failed with error %ld",
dwRetCode);
break;
}
dwThreadId = GetCurrentThreadId ();
hdeskSave = GetThreadDesktop (dwThreadId);
if (hdeskSave == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "ElInvokeInteractiveUI: GetThreadDesktop failed with error %ld",
dwRetCode);
break;
}
if (!ImpersonateLoggedOnUser (pPCB->hUserToken))
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElInvokeInteractiveUI: ImpersonateLoggedOnUse failed with error %ld",
dwRetCode);
break;
}
// Impersonate the client and connect to the User's window station
// and desktop. This will be the interactively logged-on user
hwinstaUser = OpenWindowStation (L"WinSta0", FALSE, MAXIMUM_ALLOWED);
if (hwinstaUser == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (USER, "OpenWindowStation: OpenWindowStation failed with error %ld",
dwRetCode);
break;
}
SetProcessWindowStation(hwinstaUser);
hdeskUser = OpenDesktop (L"Default", 0, FALSE, MAXIMUM_ALLOWED);
if (hdeskUser == NULL)
{
SetProcessWindowStation (hwinstaSave);
CloseWindowStation (hwinstaUser);
dwRetCode = ERROR_INVALID_WORKSTATION;
break;
}
SetThreadDesktop (hdeskUser);
// Get handle to desktop window
hwndOwner = GetDesktopWindow ();
if ((dwRetCode = (*(pEapInvokeUI))(
pPCB->dwEapTypeToBeUsed,
hwndOwner, // hwndOwner
// Context data from EAP
pInvokeEapUIIn->pbUIContextData,
// Size of context data
pInvokeEapUIIn->dwSizeOfUIContextData,
&pUIDataOut,
&dwSizeOfUIDataOut
)) != NO_ERROR)
{
TRACE1 (USER, "ElInvokeInteractiveUI: Error in calling InvokeInteractiveUI = %ld",
dwRetCode);
// Revert impersonation
if (!RevertToSelf())
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElInvokeInteractiveUI: Error in RevertToSelf = %ld",
dwRetCode);
}
// Restore window station and desktop
SetThreadDesktop (hdeskSave);
SetProcessWindowStation (hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
break;
}
// Revert impersonation
if (!RevertToSelf())
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElInvokeInteractiveUI: Error in RevertToSelf = %ld",
dwRetCode);
// Restore window station and desktop
SetThreadDesktop (hdeskSave);
SetProcessWindowStation (hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
break;
}
// Restore window station and desktop settings
SetThreadDesktop (hdeskSave);
SetProcessWindowStation (hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
// Free the context we passed to the dll
if (pInvokeEapUIIn->pbUIContextData != NULL)
{
FREE (pInvokeEapUIIn->pbUIContextData);
pInvokeEapUIIn->pbUIContextData = NULL;
pInvokeEapUIIn->dwSizeOfUIContextData = 0;
}
// Fill in the returned information into the PCB fields for
// later authentication
if (pPCB->EapUIData.pEapUIData != NULL)
{
FREE (pPCB->EapUIData.pEapUIData);
pPCB->EapUIData.pEapUIData = NULL;
pPCB->EapUIData.dwSizeOfEapUIData = 0;
}
pPCB->EapUIData.pEapUIData = MALLOC (dwSizeOfUIDataOut + sizeof (DWORD));
if (pPCB->EapUIData.pEapUIData == NULL)
{
TRACE1 (USER, "ElInvokeInteractiveUI: Error in allocating memory for UIData = %ld",
dwRetCode);
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pPCB->EapUIData.dwSizeOfEapUIData = dwSizeOfUIDataOut;
if ((dwSizeOfUIDataOut != 0) && (pUIDataOut != NULL))
{
memcpy ((BYTE *)pPCB->EapUIData.pEapUIData,
(BYTE *)pUIDataOut,
dwSizeOfUIDataOut);
}
pPCB->fEapUIDataReceived = TRUE;
TRACE0 (USER, "ElInvokeInteractiveUI: 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, "ElInvokeInteractiveUI: ElEapWork failed with error = %ld",
dwRetCode);
break;
}
TRACE0 (USER, "ElInvokeInteractiveUI: 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 (pInvokeEapUIIn->pbUIContextData != NULL)
{
FREE (pInvokeEapUIIn->pbUIContextData);
pInvokeEapUIIn->pbUIContextData = NULL;
pInvokeEapUIIn->dwSizeOfUIContextData = 0;
}
if (pFreeFunc != NULL)
{
if (pUIDataOut != NULL)
{
if (( dwRetCode = (*(pFreeFunc)) ((BYTE *)pUIDataOut)) != NO_ERROR)
{
TRACE1 (USER, "ElInvokeInteractiveUI: Error in pFreeFunc = %ld",
dwRetCode);
}
}
}
TRACE1 (USER, "ElInvokeInteractiveUI completed with error %ld", dwRetCode);
return dwRetCode;
}