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

4535 lines
127 KiB
C

/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
eapolutil.c
Abstract:
Tools and ends
Revision History:
sachins, Apr 23 2000, Created
--*/
#include "pcheapol.h"
#pragma hdrstop
//
// Definitions used to read/write to registry
//
#define MAX_REGISTRY_VALUE_LENGTH ((64*1024) - 1)
// Location of User blob
#define cszEapKeyEapolUser "Software\\Microsoft\\EAPOL\\UserEapInfo"
// Location of Connection blob
#define cszEapKeyEapolConn "Software\\Microsoft\\EAPOL\\Parameters\\Interfaces"
// Location of EAPOL Parameters Service
#define cszEapKeyEapolServiceParams "Software\\Microsoft\\EAPOL\\Parameters\\General"
// Location of EAPOL Global state machine params
#define cszEAPOLGlobalParams "Software\\Microsoft\\EAPOL\\Parameters\\General\\Global"
// Location of EAPOL Global Workspace
#define cszEAPOLWorkspace "Software\\Microsoft\\EAPOL\\Parameters\\General\\Workspace"
#define cszDefault "Default"
#define cszDefault "Default"
#define cszEapolEnabled "EapolEnabled"
#define cszDefaultEAPType "DefaultEAPType"
#define cszLastUsedSSID "LastUsedSSID"
#define cszInterfaceList "InterfaceList"
#define cszAuthPeriod "authPeriod"
#define cszHeldPeriod "heldPeriod"
#define cszStartPeriod "startPeriod"
#define cszMaxStart "maxStart"
#define cszLastModifiedGUID "LastModifiedGUID"
//
// Definitions and structures used in creating default EAP-TLS connection
// blob in the registry
//
#define EAPTLS_CONN_FLAG_REGISTRY 0x00000001
#define EAPTLS_CONN_FLAG_NO_VALIDATE_CERT 0x00000002
#define EAPTLS_CONN_FLAG_NO_VALIDATE_NAME 0x00000004
typedef struct _EAPTLS_CONN_PROPERTIES
{
DWORD dwVersion;
DWORD dwSize;
DWORD fFlags;
//EAPTLS_HASH Hash;
DWORD cbHash;
BYTE pbHash[20]; // MAX_HASH_SIZE = 20
WCHAR awszServerName[1];
} EAPTLS_CONN_PROPERTIES, *PEAPTLS_CONN_PROPERTIES;
#define PASSWORDMAGIC 0xA5
//
// HostToWireFormat16
//
// Description:
//
// Will convert a 16 bit integer from host format to wire format
//
VOID
HostToWireFormat16 (
IN WORD wHostFormat,
IN OUT PBYTE pWireFormat
)
{
*((PBYTE)(pWireFormat)+0) = (BYTE) ((DWORD)(wHostFormat) >> 8);
*((PBYTE)(pWireFormat)+1) = (BYTE) (wHostFormat);
}
//
// WireToHostFormat16
//
// Description:
//
// Will convert a 16 bit integer from wire format to host format
//
WORD
WireToHostFormat16 (
IN PBYTE pWireFormat
)
{
WORD wHostFormat = ((*((PBYTE)(pWireFormat)+0) << 8) +
(*((PBYTE)(pWireFormat)+1)));
return( wHostFormat );
}
//
// HostToWireFormat32
//
// Description:
//
// Will convert a 32 bit integer from host format to wire format
//
VOID
HostToWireFormat32 (
IN DWORD dwHostFormat,
IN OUT PBYTE pWireFormat
)
{
*((PBYTE)(pWireFormat)+0) = (BYTE) ((DWORD)(dwHostFormat) >> 24);
*((PBYTE)(pWireFormat)+1) = (BYTE) ((DWORD)(dwHostFormat) >> 16);
*((PBYTE)(pWireFormat)+2) = (BYTE) ((DWORD)(dwHostFormat) >> 8);
*((PBYTE)(pWireFormat)+3) = (BYTE) (dwHostFormat);
}
//
// WireToHostFormat32
//
// Description:
//
// Will convert a 32 bit integer from wire format to host format
//
DWORD
WireToHostFormat32 (
IN PBYTE pWireFormat
)
{
DWORD dwHostFormat = ((*((PBYTE)(pWireFormat)+0) << 24) +
(*((PBYTE)(pWireFormat)+1) << 16) +
(*((PBYTE)(pWireFormat)+2) << 8) +
(*((PBYTE)(pWireFormat)+3) ));
return( dwHostFormat );
}
//
// ElSetCustomAuthData
//
// Description:
//
// Function called to set the connection data for an interface for a specific
// EAP type and SSID (if any). Data will be stored in the HKLM hive
//
// Arguments:
// pszGUID - pointer to GUID string for the interface
// dwEapTypeId - EAP type for which connection data is to be stored
// pszSSID - Special identifier, if any, for the EAP blob
// pbConnInfo - pointer to EAP connection data blob
// dwInfoSize - Size of EAP connection blob
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
// ISSUE:
// Can we optimize the key openings??? Only open 1 key somehow?
DWORD
ElSetCustomAuthData (
IN CHAR *pszGUID,
IN DWORD dwEapTypeId,
IN CHAR *pszSSID,
IN PBYTE pbConnInfo,
IN DWORD dwInfoSize
)
{
HKEY hkey = NULL;
HKEY hkey1 = NULL;
HKEY hkey2 = NULL;
DWORD dwDisposition;
CHAR szEapTypeId[4]; // EapTypeId can be max 256 + 1 for null char
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = ERROR_SUCCESS;
do
{
// Validate input params
if (pszGUID == NULL)
{
TRACE0 (ANY, "ElSetCustomAuthData: GUID = NULL");
break;
}
if (dwEapTypeId == 0)
{
TRACE0 (ANY, "ElSetCustomAuthData: GUID = NULL");
break;
}
if ((pbConnInfo == NULL) || (dwInfoSize <= 0))
{
TRACE0 (ANY, "ElSetCustomAuthData: Invalid blob data");
break;
}
// Get handle to HKLM\Software\Microsoft\EAPOL\Parameters\Interfaces
if ((lError = RegCreateKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolConn,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetCustomAuthData: Error in RegCreateKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKLM\Software\...\Interfaces\<GUID>
if ((lError = RegCreateKeyExA (
hkey,
pszGUID,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey1,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetCustomAuthData: Error in RegCreateKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
_ltoa(dwEapTypeId, szEapTypeId, 10);
// Get handle to HKLM\Software\...\Interfaces\<GUID>\<EapTypeId>
if ((lError = RegCreateKeyExA (
hkey1,
szEapTypeId,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey2,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetCustomAuthData: Error in RegCreateKeyExA for EapTypeId, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// If no SSID is supplied, set the blob as value for "Default"
if (pszSSID == NULL)
{
pszSSID = cszDefault;
}
//
// Set the value of ..\Interfaces\GUID\<EAPTypeId>\(<SSID> or default)
// key
if ((lError = RegSetValueExA (
hkey2,
pszSSID,
0,
REG_BINARY,
pbConnInfo,
dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetCustomAuthData: Error in RegSetValueExA for SSID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
TRACE0 (ANY, "ElSetCustomAuthData: Set value succeeded");
} while (FALSE);
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (hkey1 != NULL)
{
RegCloseKey (hkey1);
}
if (hkey2 != NULL)
{
RegCloseKey (hkey2);
}
return dwRetCode;
}
//
// ElGetCustomAuthData
//
// Description:
//
// Function called to retrieve the connection data for an interface for a
// specific EAP type and SSID (if any). Data is retrieved from the HKLM hive
//
// Arguments:
//
// pszGUID - pointer to GUID string for the interface
// dwEapTypeId - EAP type for which connection data is to be retrieved
// pszSSID - Special identifier if any for the EAP blob
// pbUserInfo - output: pointer to EAP connection data blob
// dwInfoSize - output: pointer to size of EAP connection blob
//
// Return values:
//
// NO_ERROR - success
// non-zero - error
//
DWORD
ElGetCustomAuthData (
IN CHAR *pszGUID,
IN DWORD dwEapTypeId,
IN CHAR *pszSSID,
IN OUT BYTE *pbConnInfo,
IN OUT DWORD *pdwInfoSize
)
{
HKEY hkey = NULL;
HKEY hkey1 = NULL;
HKEY hkey2 = NULL;
PBYTE pbInfo = NULL;
DWORD dwInfoSize = 0;
DWORD dwType = 0;
CHAR szEapTypeId[4]; // EapTypeId can be max 256 + 1 for null char
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = ERROR_SUCCESS;
do
{
// Validate input params
if (pszGUID == NULL)
{
TRACE0 (ANY, "ElGetCustomAuthData: GUID = NULL");
break;
}
if (dwEapTypeId == 0)
{
TRACE0 (ANY, "ElGetCustomAuthData: GUID = NULL");
break;
}
// Get handle to HKLM\Software\Microsoft\EAPOL\Parameters\Interfaces
if ((lError = RegOpenKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolConn,
0,
KEY_READ,
&hkey
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetCustomAuthData: Error in RegOpenKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKLM\Software\...\Interfaces\<GUID>
if ((lError = RegOpenKeyExA (
hkey,
pszGUID,
0,
KEY_READ,
&hkey1
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetCustomAuthData: Error in RegOpenKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
_ltoa(dwEapTypeId, szEapTypeId, 10);
// Get handle to HKLM\Software\...\Interfaces\<GUID>\<EapTypeId>
if ((lError = RegOpenKeyExA (
hkey1,
szEapTypeId,
0,
KEY_READ,
&hkey2
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetCustomAuthData: Error in RegOpenKeyExA for EapTypeId, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// If no SSID is supplied, set the blob as value for "Default"
if (pszSSID == NULL)
{
pszSSID = cszDefault;
}
// Get the value of ..\Interfaces\GUID\<EAPType>\(<SSID> or default)
// key
if ((lError = RegQueryValueExA (
hkey2,
pszSSID,
0,
&dwType,
NULL,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetCustomAuthData: Error in RegQueryValueExA for size estimation for SSID, %ld",
lError);
// If pszSSID is "Default" and we cannot read the value for
// the key, bail out
if (!strcmp(pszSSID, cszDefault))
{
dwRetCode = (DWORD)lError;
break;
}
else
{
// Second try with pszSSID = cszDefault
TRACE0 (ANY, "ElGetCustomAuthData: Second try for size estimation with SSID = Default");
pszSSID = cszDefault;
if ((lError = RegQueryValueExA (
hkey2,
pszSSID,
0,
&dwType,
NULL,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetCustomAuthData: Error in RegQueryValueExA for SSID=Default, 2nd try , %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
}
}
// Data can be read
pbInfo = MALLOC (dwInfoSize);
if (pbInfo == NULL)
{
TRACE0 (ANY, "ElGetCustomAuthData: Error in memory allocation");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if ((lError = RegQueryValueExA (
hkey2,
pszSSID,
0,
&dwType,
pbInfo,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElGetCustomAuthData: Error in RegQueryValueExA for SSID = %s, %ld",
pszSSID, lError);
dwRetCode = (DWORD)lError;
break;
}
TRACE1 (ANY, "ElGetCustomAuthData: Succeeded: Data size = %ld",
dwInfoSize);
} while (FALSE);
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (hkey1 != NULL)
{
RegCloseKey (hkey1);
}
if (hkey2 != NULL)
{
RegCloseKey (hkey2);
}
// check if caller has allocated enough memory
// to hold the info
if ((pbConnInfo != NULL) && (*pdwInfoSize >= dwInfoSize))
{
memcpy ((VOID *)pbConnInfo, (VOID *)pbInfo, dwInfoSize);
}
else
{
dwRetCode = ERROR_BUFFER_TOO_SMALL;
}
*pdwInfoSize = dwInfoSize;
// Free the memory allocated for holding blob
if (pbInfo != NULL)
{
FREE (pbInfo);
pbInfo = NULL;
}
return dwRetCode;
}
//
// ElSetEapUserInfo
//
// Description:
//
// Function called to store the user data for an interface for a
// specific EAP type and SSID (if any). Data is stored in the HKCU hive.
// In case of EAP-TLS, this data will be the hash blob of the certificate
// chosen for the last successful authentication.
//
// Arguments:
//
// hToken - Handle to token for the logged on user
// pszGUID - pointer to GUID string for the interface
// dwEapTypeId - EAP type for which user data is to be stored
// pszSSID - Special identifier if any for the EAP user blob
// pbUserInfo - pointer to EAP user data blob
// dwInfoSize - Size of EAP user blob
//
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElSetEapUserInfo (
IN HANDLE hToken,
IN CHAR *pszGUID,
IN DWORD dwEapTypeId,
IN CHAR *pszSSID,
IN PBYTE pbUserInfo,
IN DWORD dwInfoSize
)
{
HKEY hkey = NULL;
HKEY hkey1 = NULL;
HKEY hkey2 = NULL;
HKEY hkey3 = NULL;
DWORD dwDisposition;
CHAR szEapTypeId[4]; // EapTypeId can be max 256 + 1 for null char
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = ERROR_SUCCESS;
do
{
// Validate input params
if (hToken == NULL)
{
TRACE0 (ANY, "ElSetEapUserInfo: User Token = NULL");
break;
}
if (pszGUID == NULL)
{
TRACE0 (ANY, "ElSetEapUserInfo: GUID = NULL");
break;
}
if (dwEapTypeId == 0)
{
TRACE0 (ANY, "ElSetEapUserInfo: GUID = NULL");
break;
}
if ((pbUserInfo == NULL) || (dwInfoSize <= 0))
{
TRACE0 (ANY, "ElSetEapUserInfo: Invalid blob data");
break;
}
// Get handle to HKCU
if ((dwRetCode = ElGetEapKeyFromToken (
hToken,
&hkey)) != NO_ERROR)
{
TRACE1 (ANY, "ElSetEapUserInfo: Error in ElGetEapKeyFromToken %ld",
dwRetCode);
break;
}
if ((lError = RegCreateKeyExA (
hkey,
cszEapKeyEapolUser,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey1,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetEapUserInfo: Error in RegCreateKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKCU\Software\...\UserEapInfo\<GUID>
if ((lError = RegCreateKeyExA (
hkey1,
pszGUID,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey2,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetEapUserInfo: Error in RegCreateKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
_ltoa(dwEapTypeId, szEapTypeId, 10);
// Get handle to HKCU\Software\...\UserEapInfo\<GUID>\<EAPTypeId>
if ((lError = RegCreateKeyExA (
hkey2,
szEapTypeId,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey3,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetEapUserInfo: Error in RegCreateKeyExA for EapTypeId, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// If no SSID is supplied, set the blob as value for "Default"
if (pszSSID == NULL)
{
pszSSID = cszDefault;
}
// Set value of ...\UserEapInfo\<GUID>\<EAPTypeId>\(<SSID> or default)
// key
if ((lError = RegSetValueExA (
hkey3,
pszSSID,
0,
REG_BINARY,
pbUserInfo,
dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElSetEapUserInfo: Error in RegSetValueExA for SSID = %s, %ld",
pszSSID, lError);
dwRetCode = (DWORD)lError;
break;
}
TRACE0 (ANY, "ElSetEapUserInfo: Set value succeeded");
} while (FALSE);
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (hkey1 != NULL)
{
RegCloseKey (hkey1);
}
if (hkey2 != NULL)
{
RegCloseKey (hkey2);
}
if (hkey3 != NULL)
{
RegCloseKey (hkey3);
}
return dwRetCode;
}
//
// ElGetEapUserInfo
//
// Description:
//
// Function called to retrieve the user data for an interface for a
// specific EAP type and SSID (if any). Data is retrieved from the HKCU hive
//
// Arguments:
// hToken - Handle to token for the logged on user
// pszGUID - pointer to GUID string for the interface
// dwEapTypeId - EAP type for which user data is to be stored
// pszSSID - Special identifier if any for the EAP user blob
// pbUserInfo - output: pointer to EAP user data blob
// dwInfoSize - output: pointer to size of EAP user blob
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElGetEapUserInfo (
IN HANDLE hToken,
IN CHAR *pszGUID,
IN DWORD dwEapTypeId,
IN CHAR *pszSSID,
IN OUT PBYTE pbUserInfo,
IN OUT DWORD *pdwInfoSize
)
{
HKEY hkey = NULL;
HKEY hkey1 = NULL;
HKEY hkey2 = NULL;
HKEY hkey3 = NULL;
PBYTE pbInfo = NULL;
DWORD dwInfoSize = 0;
DWORD dwType = 0;
CHAR szEapTypeId[4]; // EapTypeId can be max 256 + 1 for null char
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = ERROR_SUCCESS;
do
{
// Validate input params
if (pszGUID == NULL)
{
TRACE0 (ANY, "ElGetEapUserInfo: GUID = NULL");
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
if (dwEapTypeId == 0)
{
TRACE0 (ANY, "ElGetEapUserInfo: GUID = NULL");
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
// Get handle to HKCU
if ((dwRetCode = ElGetEapKeyFromToken (
hToken,
&hkey)) != NO_ERROR)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in ElGetEapKeyFromToken %ld",
dwRetCode);
break;
}
// Get handle to HKCU\Software\...\UserEapInfo\<GUID>
if ((lError = RegOpenKeyExA (
hkey,
cszEapKeyEapolUser,
0,
KEY_READ,
&hkey1
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in RegOpenKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKCU\Software\...\UserEapInfo\<GUID>
if ((lError = RegOpenKeyExA (
hkey1,
pszGUID,
0,
KEY_READ,
&hkey2
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in RegOpenKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
_ltoa(dwEapTypeId, szEapTypeId, 10);
// Get handle to HKCU\Software\...\UserEapInfo\<GUID>\<EAPTypeId>
if ((lError = RegOpenKeyExA (
hkey2,
szEapTypeId,
0,
KEY_READ,
&hkey3
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in RegOpenKeyExA for EapTypeId, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// If no SSID is supplied, set the blob as value for "Default"
if (pszSSID == NULL)
{
pszSSID = cszDefault;
}
// Get value of ...\UserEapInfo\<GUID>\<EAPTypeId>\(<SSID> or default)
// key
if ((lError = RegQueryValueExA (
hkey3,
pszSSID,
0,
&dwType,
NULL,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in RegQueryValueExA for size estimation for SSID, %ld",
lError);
// If pszSSID is "Default" and we cannot read the value for
// the key, bail out
if (!strcmp(pszSSID, cszDefault))
{
dwRetCode = (DWORD)lError;
break;
}
else
{
// Second try with pszSSID = cszDefault
TRACE0 (ANY, "ElGetEapUserInfo: Second try for size estimation with SSID = Default");
pszSSID = cszDefault;
if ((lError = RegQueryValueExA (
hkey3,
pszSSID,
0,
&dwType,
NULL,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in RegOpenKeyExA for SSID=Default in 2nd try , %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
}
}
// Data can be read
pbInfo = MALLOC (dwInfoSize);
if (pbInfo == NULL)
{
TRACE0 (ANY, "ElGetEapUserInfo: Error in memory allocation");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if ((lError = RegQueryValueExA (
hkey3,
pszSSID,
0,
&dwType,
pbInfo,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetEapUserInfo: Error in RegQueryValueExA, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
TRACE0 (ANY, "ElGetEapUserInfo: Get value succeeded");
} while (FALSE);
// Close all the open registry keys
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (hkey1 != NULL)
{
RegCloseKey (hkey1);
}
if (hkey2 != NULL)
{
RegCloseKey (hkey2);
}
if (hkey3 != NULL)
{
RegCloseKey (hkey3);
}
if (dwRetCode == ERROR_SUCCESS)
{
// check if caller has allocated enough memory
// to hold the info
if ((pbUserInfo != NULL) && (*pdwInfoSize >= dwInfoSize))
{
memcpy ((VOID *)pbUserInfo, (VOID *)pbInfo, dwInfoSize);
}
else
{
// Else just return the size of the blob but not the blob
dwRetCode = ERROR_BUFFER_TOO_SMALL;
}
*pdwInfoSize = dwInfoSize;
}
// Free the memory allocated for holding blob
if (pbInfo != NULL)
{
FREE (pbInfo);
}
return dwRetCode;
}
//
// ElGetInterfaceParams
//
// Description:
//
// Function called to retrieve the EAPOL parameters for an interface, stored
// in the HKLM hive.
//
// Arguments:
//
// pszGUID - pointer to GUID string for the interface
// pdwDefaultEAPType - output: Pointer to default EAP type for interface
// pszLastUsedSSID - output: Pointer to last used SSID for the interface
// pdwEapolEnabled - output: Is EAPOL enabled for the interface?
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElGetInterfaceParams (
IN CHAR *pszGUID,
IN OUT DWORD *pdwDefaultEAPType,
IN OUT CHAR *pszLastUsedSSID,
IN OUT DWORD *pdwEapolEnabled
)
{
HKEY hkey = NULL;
HKEY hkey1 = NULL;
DWORD dwInfoSize = 0;
DWORD dwType = 0;
BYTE bValueBuffer[256];
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = ERROR_SUCCESS;
do
{
// Validate input params
if (pszGUID == NULL)
{
TRACE0 (ANY, "ElGetInterfaceParams: GUID = NULL");
break;
}
TRACE1 (ANY, "ElGetInterfaceParams: Getting stuff from registry for %s", pszGUID);
// Get handle to HKLM\Software\Microsoft\EAPOL\Parameters\Interfaces
if ((lError = RegOpenKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolConn,
0,
KEY_READ,
&hkey
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetInterfaceParams: Error in RegOpenKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKLM\Software\...\Interfaces\<GUID>
if ((lError = RegOpenKeyExA (
hkey,
pszGUID,
0,
KEY_READ,
&hkey1
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetInterfaceParams: Error in RegOpenKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get the value of ..\Interfaces\GUID\EapolEnabled
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hkey1,
cszEapolEnabled,
0,
&dwType,
(BYTE *)pdwEapolEnabled,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElGetInterfaceParams: Error in RegQueryValueExA for EapolEnabled, %ld, InfoSize=%ld",
lError, dwInfoSize);
*pdwEapolEnabled = DEFAULT_EAPOL_STATE;
}
TRACE1 (ANY, "ElGetInterfaceParams: Got EapolEnabled = %ld", *pdwEapolEnabled);
// Get the value of ..\Interfaces\GUID\DefaultEAPType
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hkey1,
cszDefaultEAPType,
0,
&dwType,
(BYTE *)pdwDefaultEAPType,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElGetInterfaceParams: Error in RegQueryValueExA for DefaultEAPType, %ld, InfoSize=%ld",
lError, dwInfoSize);
*pdwDefaultEAPType = DEFAULT_EAP_TYPE;
}
TRACE1 (ANY, "ElGetInterfaceParams: Got DefaultEAPType = %ld", *pdwDefaultEAPType);
// Get the value of ..\Interfaces\GUID\LastUsedSSID
dwInfoSize = 256;
if ((lError = RegQueryValueExA (
hkey1,
cszLastUsedSSID,
0,
&dwType,
(PUCHAR)pszLastUsedSSID,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetInterfaceParams: Error in RegQueryValueExA for LastUsedSSID, %ld",
lError);
pszLastUsedSSID = NULL;
}
} while (FALSE);
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (hkey1 != NULL)
{
RegCloseKey (hkey1);
}
return dwRetCode;
}
//
// ElSetInterfaceParams
//
// Description:
//
// Function called to set the EAPOL parameters for an interface, in the HKLM
// hive
//
// Arguments:
//
// pszGUID - Pointer to GUID string for the interface
// pdwDefaultEAPType - default EAP type for interface
// pszLastUsedSSID - SSID that was received in the last EAP-Request/Identity
// packet
// pdwEapolEnabled - Is EAPOL enabled for the interface
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
//
DWORD
ElSetInterfaceParams (
IN CHAR *pszGUID,
IN DWORD *pdwDefaultEAPType,
IN CHAR *pszLastUsedSSID,
IN DWORD *pdwEapolEnabled
)
{
HKEY hkey = NULL;
HKEY hkey1 = NULL;
DWORD dwInfoSize = 0;
DWORD dwType = 0;
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = ERROR_SUCCESS;
do
{
// Validate input params
if (pszGUID == NULL)
{
TRACE0 (ANY, "ElSetInterfaceParams: GUID = NULL");
break;
}
TRACE1 (ANY, "Setting stuff from registry for %s", pszGUID);
// Get handle to HKLM\Software\Microsoft\EAPOL\Parameters\Interfaces
if ((lError = RegOpenKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolConn,
0,
KEY_WRITE,
&hkey
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetInterfaceParams: Error in RegOpenKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKLM\Software\...\Interfaces\<GUID>
if ((lError = RegOpenKeyExA (
hkey,
pszGUID,
0,
KEY_WRITE,
&hkey1
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetInterfaceParams: Error in RegOpenKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Set the value of ..\Interfaces\GUID\EapolEnabled
if ((lError = RegSetValueExA (
hkey1,
cszEapolEnabled,
0,
REG_DWORD,
(BYTE *)pdwEapolEnabled,
sizeof(DWORD))) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetInterfaceParams: Error in RegSetValueExA for EapolEnabled, %ld",
lError);
}
// Set the value of ..\Interfaces\GUID\DefaultEAPType
if ((lError = RegSetValueExA (
hkey1,
cszDefaultEAPType,
0,
REG_DWORD,
(BYTE *)pdwDefaultEAPType,
sizeof(DWORD))) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElSetInterfaceParams: Error in RegSetValueExA for DefaultEAPType, %ld",
lError);
}
// Set the value of ..\Interfaces\GUID\LastUsedSSID
if ((lError = RegSetValueExA (
hkey1,
cszLastUsedSSID,
0,
REG_SZ,
pszLastUsedSSID,
strlen(pszLastUsedSSID))) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElGetInterfaceParams: Error in RegSetValueExA for LastUsedSSID, %ld",
lError);
}
} while (FALSE);
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (hkey1 != NULL)
{
RegCloseKey (hkey1);
}
return dwRetCode;
}
//
// ElGetEapKeyFromToken
//
// Description:
//
// Function to get handle to User hive from User Token
//
// Arguments:
// hUserToken - handle to user token
// phkey - output: pointer to handle to user hive
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElGetEapKeyFromToken (
IN HANDLE hUserToken,
OUT HKEY *phkey
)
{
DWORD dwSizeNeeded;
TOKEN_USER *pTokenData = NULL;
UNICODE_STRING UnicodeSidString;
WCHAR wsUnicodeBuffer[256];
HKEY hUserKey;
HKEY hkeyEap;
DWORD dwDisposition;
NTSTATUS Status = STATUS_SUCCESS;
PBYTE pbInfo = NULL;
CHAR *pszInfo = NULL;
DWORD dwType;
DWORD dwInfoSize = 0;
LONG lRetVal;
EAPOL_PCB *pPCB;
DWORD i;
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = NO_ERROR;
do
{
if (hUserToken != NULL)
{
if (!GetTokenInformation(hUserToken, TokenUser, 0, 0, &dwSizeNeeded))
{
if ((dwRetCode = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)
{
pTokenData = (TOKEN_USER *) MALLOC (dwSizeNeeded);
if (pTokenData == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (ANY,"ElGetEapKeyFromToken: Allocation for TokenData failed");
break;
}
// Reset error code since we are continuing processing
// This was a valid scenario
dwRetCode = NO_ERROR;
}
else
{
TRACE1 (ANY,"ElGetEapKeyFromToken: Error in GetTokenInformation = %ld",
dwRetCode);
break;
}
if (!GetTokenInformation (hUserToken,
TokenUser,
pTokenData,
dwSizeNeeded,
&dwSizeNeeded))
{
dwRetCode = GetLastError ();
TRACE1 (ANY,"ElGetEapKeyFromToken: GetTokenInformation failed with error %ld",
dwRetCode);
break;
}
UnicodeSidString.Buffer = wsUnicodeBuffer;
UnicodeSidString.Length = 0;
UnicodeSidString.MaximumLength = sizeof(wsUnicodeBuffer);
Status = RtlConvertSidToUnicodeString (
&UnicodeSidString,
pTokenData->User.Sid,
FALSE);
if (!NT_SUCCESS(Status))
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElGetEapKeyFromToken: RtlconvertSidToUnicodeString failed with error %ld",
dwRetCode);
break;
}
UnicodeSidString.Buffer[UnicodeSidString.Length] = 0;
// Open the user's key
if ((lError = RegOpenKeyEx(HKEY_USERS,
UnicodeSidString.Buffer,
0,
KEY_ALL_ACCESS,
&hUserKey)) != ERROR_SUCCESS)
{
dwRetCode = (DWORD)lError;
TRACE1 (USER, "ElGetEapKeyFromToken: RegOpenKeyExA failed with error %ld",
dwRetCode);
break;
}
else
{
TRACE0 (ANY, "ElGetEapKeyFromToken: RegOpenKeyExA succeeded");
}
}
else
{
TRACE0 (ANY,"ElGetEapKeyFromToken: GetTokenInformation succeeded when it should have failed");
break;
}
}
else
{
TRACE0 (ANY, "ElGetEapKeyFromToken: Error, hUserToken == NULL ");
break;
}
*phkey = hUserKey;
} while (FALSE);
if (pTokenData != NULL)
{
FREE (pTokenData);
}
return dwRetCode;
}
//
// ElInitRegPortData
//
// Description:
//
// Function to verify existence of connection data for the port
// If no data exists, initialize with default values
// For EAP-TLS, default settings are no server certificate authentication,
// registry certificates
//
// Arguments:
// pszDeviceGUID - Pointer to GUID string for the port for which data is being
// initialized
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElInitRegPortData (
CHAR *pszDeviceGUID
)
{
PBYTE pbInfo = NULL;
DWORD dwInfoSize = 0;
EAPTLS_CONN_PROPERTIES *pConnProp = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
// Get the size of the Eap data first
if ((dwRetCode = ElGetCustomAuthData (
pszDeviceGUID,
EAPCFG_DefaultKey,
NULL, // SSID
NULL, // pbInfo
&dwInfoSize
)) != NO_ERROR)
{
TRACE1 (ANY, "ElInitRegPortData: ElGetCustomAuthData returned error %ld",
dwRetCode);
if ((dwRetCode == ERROR_BUFFER_TOO_SMALL) && (dwInfoSize != 0))
{
// There is valid data in the default key in the registry
dwRetCode = NO_ERROR;
TRACE1 (ANY, "ElInitRegPortData: ElGetCustomAuthData returned blob size = %ld",
dwInfoSize);
break;
}
// Initialize port place with default data
pConnProp = MALLOC (sizeof (EAPTLS_CONN_PROPERTIES));
if (pConnProp == NULL)
{
TRACE0 (ANY, "ElInitRegPortData: Failed allocation for Conn Prop");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Registry certs, No server cert validation, No server name
// comparison
pConnProp->fFlags = (EAPTLS_CONN_FLAG_REGISTRY |
EAPTLS_CONN_FLAG_NO_VALIDATE_CERT |
EAPTLS_CONN_FLAG_NO_VALIDATE_NAME);
#if REG_CERT_VALIDATE
pConnProp->fFlags = EAPTLS_CONN_FLAG_REGISTRY;
pConnProp->fFlags &= ~EAPTLS_CONN_FLAG_NO_VALIDATE_CERT;
pConnProp->fFlags &= ~EAPTLS_CONN_FLAG_NO_VALIDATE_NAME;
#endif
pConnProp->dwSize = sizeof (EAPTLS_CONN_PROPERTIES);
// Set this blob into the registry for the port
if ((dwRetCode = ElSetCustomAuthData (
pszDeviceGUID,
EAPCFG_DefaultKey,
NULL,
(BYTE *)pConnProp,
pConnProp->dwSize
)) != NO_ERROR)
{
TRACE1 (ANY, "ElInitRegPortData: ElSetCustomAuthData failed with %ld",
dwRetCode);
break;
}
}
} while (FALSE);
if (pConnProp != NULL)
{
FREE (pConnProp);
pConnProp = NULL;
}
TRACE1 (ANY, "ElInitRegPortData: completed with error %ld", dwRetCode);
return dwRetCode;
}
//
// ElAuthAttributeGetVendorSpecific
//
//
// Description:
// Helper function used to extract MPPE Key out of Attrribute.
//
RAS_AUTH_ATTRIBUTE *
ElAuthAttributeGetVendorSpecific (
IN DWORD dwVendorId,
IN DWORD dwVendorType,
IN RAS_AUTH_ATTRIBUTE * pAttributes
)
{
HANDLE hAttribute;
RAS_AUTH_ATTRIBUTE * pAttribute;
//
// First search for the vendor specific attribute
//
pAttribute = ElAuthAttributeGetFirst ( raatVendorSpecific,
pAttributes,
&hAttribute );
while ( pAttribute != NULL )
{
//
// If this attribute is of at least size to hold vendor Id/Type
//
if ( pAttribute->dwLength >= 8 )
{
//
// Does this have the correct VendorId
//
if (WireToHostFormat32( (PBYTE)(pAttribute->Value) ) == dwVendorId)
{
//
// Does this have the correct Vendor Type
//
if ( *(((PBYTE)(pAttribute->Value))+4) == dwVendorType )
{
return( pAttribute );
}
}
}
pAttribute = ElAuthAttributeGetNext ( &hAttribute,
raatVendorSpecific );
}
return( NULL );
}
//
// ElAuthAttributeGetFirst
//
// Description:
// Helper function used to extract MPPE Key out of Attrribute.
//
RAS_AUTH_ATTRIBUTE *
ElAuthAttributeGetFirst (
IN RAS_AUTH_ATTRIBUTE_TYPE raaType,
IN RAS_AUTH_ATTRIBUTE * pAttributes,
OUT HANDLE * phAttribute
)
{
DWORD dwIndex;
RAS_AUTH_ATTRIBUTE * pRequiredAttribute;
pRequiredAttribute = ElAuthAttributeGet ( raaType, pAttributes );
if ( pRequiredAttribute == NULL )
{
*phAttribute = NULL;
return( NULL );
}
*phAttribute = pRequiredAttribute;
return( pRequiredAttribute );
}
//
// ElAuthAttributeGetNext
//
// Description:
// Helper function used to extract MPPE Key out of Attrribute.
//
RAS_AUTH_ATTRIBUTE *
ElAuthAttributeGetNext (
IN OUT HANDLE * phAttribute,
IN RAS_AUTH_ATTRIBUTE_TYPE raaType
)
{
DWORD dwIndex;
RAS_AUTH_ATTRIBUTE * pAttributes = (RAS_AUTH_ATTRIBUTE *)*phAttribute;
if ( pAttributes == NULL )
{
return( NULL );
}
pAttributes++;
while( pAttributes->raaType != raatMinimum )
{
if ( pAttributes->raaType == raaType )
{
*phAttribute = pAttributes;
return( pAttributes );
}
pAttributes++;
}
*phAttribute = NULL;
return( NULL );
}
//
// ElAuthAttributeGet
//
// Description:
// Helper function used to extract MPPE Key out of Attrribute.
//
RAS_AUTH_ATTRIBUTE *
ElAuthAttributeGet (
IN RAS_AUTH_ATTRIBUTE_TYPE raaType,
IN RAS_AUTH_ATTRIBUTE * pAttributes
)
{
DWORD dwIndex;
if ( pAttributes == NULL )
{
return( NULL );
}
for( dwIndex = 0; pAttributes[dwIndex].raaType != raatMinimum; dwIndex++ )
{
if ( pAttributes[dwIndex].raaType == raaType )
{
return( &(pAttributes[dwIndex]) );
}
}
return( NULL );
}
//
// ElReverseString
//
// Description:
// Reverses order of characters in 'psz'
//
VOID
ElReverseString (
CHAR* psz
)
{
CHAR* pszBegin;
CHAR* pszEnd;
for (pszBegin = psz, pszEnd = psz + strlen( psz ) - 1;
pszBegin < pszEnd;
++pszBegin, --pszEnd)
{
CHAR ch = *pszBegin;
*pszBegin = *pszEnd;
*pszEnd = ch;
}
}
//
// ElEncodePw
//
// Description:
//
// Obfuscate 'pszPassword' in place to foil memory scans for passwords.
// Returns the address of 'pszPassword'.
//
CHAR*
ElEncodePw (
IN OUT CHAR* pszPassword
)
{
if (pszPassword)
{
CHAR* psz;
ElReverseString (pszPassword);
for (psz = pszPassword; *psz != '\0'; ++psz)
{
if (*psz != (CHAR)PASSWORDMAGIC)
*psz ^= PASSWORDMAGIC;
}
}
return pszPassword;
}
//
// ElDecodePw
//
// Description:
//
// Un-obfuscate 'pszPassword' in place.
// Returns the address of 'pszPassword'.
//
CHAR*
ElDecodePw (
IN OUT CHAR* pszPassword
)
{
return ElEncodePw (pszPassword);
}
//
// Call: ElEncryptKeyUsingMD5
//
// Description:
// Given a secret, encrypt a given blob
//
//
//
VOID
ElEncryptBlockUsingMD5 (
IN BYTE *pbSecret,
IN ULONG ulSecretLen,
IN OUT BYTE *pbBuf,
IN ULONG ulBufLen
)
{
MD5_CTX MD5Context;
BYTE bcipherText[MD5DIGESTLEN];
BYTE *pbWork = NULL, *pbEnd = NULL;
BYTE *pbEndBlock = NULL, *pbSrc = NULL;
//
// Compute the beginning and end of the data to be crypted
//
pbWork = pbBuf;
pbEnd = pbBuf + ulBufLen;
//
// Loop through the buffer
//
while (pbWork < pbEnd)
{
// Compute the digest
MD5Init (&MD5Context);
MD5Update (&MD5Context, pbSecret, ulSecretLen);
MD5Final (&MD5Context);
// Find the end of the block to be decrypted
pbEndBlock = pbWork + MD5DIGESTLEN;
if (pbEndBlock >= pbEnd)
{
// We've reached the end of the buffer
pbEndBlock = pbEnd;
}
else
{
// ISSUE: Save the ciphertext for the next pass?
}
// Crypt the block
for (pbSrc = MD5Context.digest; pbWork < pbEndBlock; ++pbWork, ++pbSrc)
{
*pbWork ^= *pbSrc;
}
}
}
//
// ElDecryptKeyUsingMD5
//
// Description:
// Given a secret, decrypt a given blob
//
//
//
VOID
ElDecryptBlockUsingMD5 (
IN BYTE *pbSecret,
IN ULONG ulSecretLen,
IN OUT BYTE *pbBuf,
IN ULONG ulBufLen
)
{
MD5_CTX MD5Context;
BYTE bcipherText[MD5DIGESTLEN];
BYTE *pbWork = NULL, *pbEnd = NULL;
BYTE *pbEndBlock = NULL, *pbSrc = NULL;
DWORD dwNumBlocks = 0;
DWORD dwBlock = 0;
DWORD dwIndex = 0;
dwNumBlocks = ( ulBufLen - 2 ) / MD5DIGESTLEN;
//
// Walk through the blocks
//
for (dwBlock = 0; dwBlock < dwNumBlocks; dwBlock++ )
{
MD5Init ( &MD5Context);
MD5Update ( &MD5Context, (PBYTE)pbSecret, ulSecretLen);
//
// ISSUE:
// Do we use any part of the ciphertext at all to generate
// the digest
//
MD5Final ( &MD5Context);
for ( dwIndex = 0; dwIndex < MD5DIGESTLEN; dwIndex++ )
{
*pbBuf ^= MD5Context.digest[dwIndex];
pbBuf++;
}
}
}
//
// ElGetHMACMD5Digest
//
// Description:
//
// Given a secret, generate a MD5 digest
//
// Arguments:
// pbBuf - pointer to data stream
// dwBufLen - length of data stream
// pbKey - pointer to authentication key
// dwKeyLen - length of authentication key
// pvDigest - caller digest to be filled in
//
// Return values:
// None
//
VOID
ElGetHMACMD5Digest (
IN BYTE *pbBuf,
IN DWORD dwBufLen,
IN BYTE *pbKey,
IN DWORD dwKeyLen,
IN OUT VOID *pvDigest
)
{
MD5_CTX MD5context;
UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */
UCHAR k_opad[65]; /* outer padding - key XORd with opad */
UCHAR tk[16];
DWORD dwIndex = 0;
//
// the HMAC_MD5 transform looks like:
//
// MD5(K XOR opad, MD5(K XOR ipad, text))
//
// where K is an n byte key
// ipad is the byte 0x36 repeated 64 times
// opad is the byte 0x5c repeated 64 times
// and text is the data being protected
//
// start out by storing key in pads
ZeroMemory ( k_ipad, sizeof k_ipad);
ZeroMemory ( k_opad, sizeof k_opad);
memcpy ( k_ipad, pbKey, dwKeyLen);
memcpy ( k_opad, pbKey, dwKeyLen);
// XOR key with ipad and opad values
for (dwIndex=0; dwIndex<64; dwIndex++)
{
k_ipad[dwIndex] ^= 0x36;
k_opad[dwIndex] ^= 0x5c;
}
//
// perform inner MD5
//
// init context for 1st pass
MD5Init(&MD5context);
// start with inner pad
MD5Update(&MD5context, k_ipad, 64);
// then text of datagram
MD5Update(&MD5context, pbBuf, dwBufLen);
// finish up 1st pass
MD5Final(&MD5context);
memcpy (pvDigest, MD5context.digest, MD5DIGESTLEN);
//
// perform outer MD5
//
// init context for 2nd pass
MD5Init(&MD5context);
// start with outer pad
MD5Update(&MD5context, k_opad, 64);
// then results of 1st hash
MD5Update(&MD5context, pvDigest, 16);
// finish up 2nd pass
MD5Final(&MD5context);
memcpy (pvDigest, MD5context.digest, MD5DIGESTLEN);
}
//
// ElWmiGetValue
//
// Description:
//
// Get a value for a GUID instance through WMI
//
// Arguments:
// pGuid - Pointer to guid for which value is to be fetched
// pszInstanceName - Friendly name for the interface
// pbInputBuffer - Pointer to data
// dwInputBufferSize - Size of data
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElWmiGetValue (
IN GUID *pGuid,
IN CHAR *pszInstanceName,
IN OUT BYTE *pbOutputBuffer,
IN OUT DWORD *pdwOutputBufferSize
)
{
WMIHANDLE WmiHandle = NULL;
PWNODE_SINGLE_INSTANCE pWnode;
ULONG ulBufferSize = 0;
WCHAR *pwszInstanceName = NULL;
BYTE *pbLocalBuffer = NULL;
DWORD dwLocalBufferSize = 0;
LONG lStatus = ERROR_SUCCESS;
do
{
if ((pwszInstanceName = MALLOC ((strlen(pszInstanceName)+1) * sizeof (WCHAR))) == NULL)
{
TRACE2 (ANY, "ElWmiGetValue: MALLOC failed for pwszInstanceName, Friendlyname =%s, len= %ld",
pszInstanceName, strlen(pszInstanceName));
lStatus = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (0 == MultiByteToWideChar(
CP_ACP,
0,
pszInstanceName,
-1,
pwszInstanceName,
strlen(pszInstanceName)+1 ) )
{
lStatus = GetLastError();
TRACE2 (ANY, "ElWmiGetValue: MultiByteToWideChar(%s) failed: %ld",
pszInstanceName, lStatus);
break;
}
pwszInstanceName[strlen(pszInstanceName)] = L'\0';
TRACE1 (ANY, "ElWmiGetValue: MultiByteToWideChar succeeded: %S",
pwszInstanceName);
if ((lStatus = WmiOpenBlock (pGuid, 0, &WmiHandle)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWmiGetValue: WmiOpenBlock failed with error %ld",
lStatus);
break;
}
if ((lStatus = WmiQuerySingleInstance (WmiHandle,
pwszInstanceName,
&dwLocalBufferSize,
NULL)) != ERROR_SUCCESS)
{
if (lStatus == ERROR_INSUFFICIENT_BUFFER)
{
TRACE1 (ANY, "ElWmiGetValue: Size Required = %ld",
dwLocalBufferSize);
if ((pbLocalBuffer = MALLOC (dwLocalBufferSize)) == NULL)
{
TRACE0 (ANY, "ElWmiGetValue: MALLOC failed for pbLocalBuffer");
lStatus = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if ((lStatus = WmiQuerySingleInstance (WmiHandle,
pwszInstanceName,
&dwLocalBufferSize,
pbLocalBuffer))
!= ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWmiGetValue: WmiQuerySingleInstance failed with error %ld",
lStatus);
break;
}
pWnode = (PWNODE_SINGLE_INSTANCE)pbLocalBuffer;
// If enough space in the output buffer, copy the data block
if (*pdwOutputBufferSize >= pWnode->SizeDataBlock)
{
memcpy (pbOutputBuffer,
(PBYTE)((BYTE *)pWnode + pWnode->DataBlockOffset),
pWnode->SizeDataBlock
);
}
else
{
lStatus = ERROR_INSUFFICIENT_BUFFER;
TRACE0 (ANY, "ElWmiGetValue: Not sufficient space to copy DataBlock");
*pdwOutputBufferSize = pWnode->SizeDataBlock;
break;
}
*pdwOutputBufferSize = pWnode->SizeDataBlock;
TRACE0 (ANY, "ElWmiGetValue: Got values from Wmi");
TRACE1 (ANY, "SizeofDataBlock = %ld", pWnode->SizeDataBlock);
EAPOL_DUMPBA (pbOutputBuffer, *pdwOutputBufferSize);
}
else
{
TRACE1 (ANY, "ElWmiGetValue: WmiQuerySingleInstance failed with error %ld",
lStatus);
break;
}
}
} while (FALSE);
if (WmiHandle != NULL)
{
if ((lStatus = WmiCloseBlock (WmiHandle)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWmiGetValue: WmiOpenBlock failed with error %ld",
lStatus);
}
}
if (pbLocalBuffer != NULL)
{
FREE (pbLocalBuffer);
}
if (pwszInstanceName != NULL)
{
FREE (pwszInstanceName);
}
return (DWORD)lStatus;
}
//
// ElWmiSetValue
//
// Description:
//
// Set a value for a GUID instance through WMI
//
// Arguments:
// pGuid - Pointer to guid for which value is to be set
// pszInstanceName - Friendly name for the interface
// pbInputBuffer - Pointer to data
// dwInputBufferSize - Size of data
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElWmiSetValue (
IN GUID *pGuid,
IN CHAR *pszInstanceName,
IN BYTE *pbInputBuffer,
IN DWORD dwInputBufferSize
)
{
WMIHANDLE WmiHandle = NULL;
PWNODE_SINGLE_INSTANCE pWnode;
ULONG ulBufferSize = 0;
WCHAR *pwszInstanceName = NULL;
BYTE bBuffer[4096];
LONG lStatus = ERROR_SUCCESS;
do
{
if ((pwszInstanceName = MALLOC ((strlen(pszInstanceName)+1) * sizeof (WCHAR))) == NULL)
{
TRACE0 (ANY, "ElWmiSetValue: MALLOC failed for pwszInstanceName");
lStatus = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (0 == MultiByteToWideChar (
CP_ACP,
0,
pszInstanceName,
-1,
pwszInstanceName,
strlen(pszInstanceName)+1 ) )
{
lStatus = GetLastError();
TRACE2 (ANY, "ElWmiSetValue: MultiByteToWideChar(%s) failed: %d",
pszInstanceName,
lStatus);
break;
}
pwszInstanceName[strlen(pszInstanceName)] = L'\0';
if ((lStatus = WmiOpenBlock (pGuid, 0, &WmiHandle)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWmiSetValue: WmiOpenBlock failed with error %ld",
lStatus);
break;
}
if ((lStatus = WmiSetSingleInstance (WmiHandle,
pwszInstanceName,
1,
dwInputBufferSize,
pbInputBuffer))
!= ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWmiSetValue: WmiSetSingleInstance failed with error %ld",
lStatus);
break;
}
TRACE0 (ANY, "ElWmiSetValue: Successful !!!");
} while (FALSE);
if (WmiHandle != NULL)
{
if ((lStatus = WmiCloseBlock (WmiHandle)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWmiSetValue: WmiOpenBlock failed with error %ld",
lStatus);
}
}
if (pwszInstanceName != NULL)
{
FREE (pwszInstanceName);
}
return (DWORD)lStatus;
}
//
// ElNdisuioSetOIDValue
//
// Description:
//
// Set a value for an OID for an interface using Ndisuio
//
// Arguments:
// hInterface - Ndisuio handle to interface
// Oid - Oid for which value needs to be set
// pbOidData - Pointer to Oid data
// ulOidDataLength - Oid data length
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElNdisuioSetOIDValue (
IN HANDLE hInterface,
IN NDIS_OID Oid,
IN BYTE *pbOidData,
IN ULONG ulOidDataLength
)
{
PNDISUIO_SET_OID pSetOid = NULL;
DWORD BytesReturned = 0;
BOOLEAN fSuccess = TRUE;
DWORD dwRetCode = NO_ERROR;
do
{
pSetOid = (PNDISUIO_SET_OID) MALLOC (ulOidDataLength + sizeof(NDISUIO_SET_OID));
if (pSetOid == NULL)
{
TRACE0 (ANY, "ElNdisuioSetOIDValue: MALLOC failed for pSetOid");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pSetOid->Oid = Oid;
memcpy(&pSetOid->Data[0], pbOidData, ulOidDataLength);
fSuccess = (BOOLEAN) DeviceIoControl (
hInterface,
IOCTL_NDISUIO_SET_OID_VALUE,
(LPVOID)pSetOid,
FIELD_OFFSET(NDISUIO_SET_OID, Data) + ulOidDataLength,
(LPVOID)pSetOid,
0,
&BytesReturned,
NULL);
if (!fSuccess)
{
TRACE1 (ANY, "ElNdisuioSetOIDValue: DeviceIoControl failed with error %ld",
(dwRetCode = GetLastError()));
break;
}
else
{
TRACE0 (ANY, "ElNdisuioSetOIDValue: DeviceIoControl succeeded");
}
}
while (FALSE);
if (pSetOid != NULL)
{
FREE (pSetOid);
}
return dwRetCode;
}
//
// ElNdisuioQueryOIDValue
//
// Description:
//
// Query the value for an OID for an interface using Ndisuio
//
// Arguments:
// hInterface - Ndisuio handle to interface
// Oid - Oid for which value needs to be set
// pbOidValue - Pointer to Oid value
// pulOidDataLength - Pointer to Oid data length
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElNdisuioQueryOIDValue (
IN HANDLE hInterface,
IN NDIS_OID Oid,
IN BYTE *pbOidData,
IN ULONG *pulOidDataLength
)
{
PNDISUIO_QUERY_OID pQueryOid = NULL;
DWORD BytesReturned = 0;
BOOLEAN fSuccess = TRUE;
DWORD dwRetCode = NO_ERROR;
do
{
pQueryOid = (PNDISUIO_QUERY_OID) MALLOC (*pulOidDataLength + sizeof(NDISUIO_QUERY_OID));
if (pQueryOid == NULL)
{
TRACE0 (ANY, "ElNdisuioQueryOIDValue: MALLOC failed for pQueryOid");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pQueryOid->Oid = Oid;
fSuccess = (BOOLEAN) DeviceIoControl (
hInterface,
IOCTL_NDISUIO_QUERY_OID_VALUE,
(LPVOID)pQueryOid,
FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + *pulOidDataLength,
(LPVOID)pQueryOid,
FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + *pulOidDataLength,
&BytesReturned,
NULL);
if (!fSuccess)
{
dwRetCode = GetLastError();
TRACE2 (ANY, "ElNdisuioQueryOIDValue: DeviceIoControl failed with error %ld, BytesReturned = %ld",
dwRetCode, BytesReturned);
*pulOidDataLength = BytesReturned;
break;
}
else
{
TRACE0 (ANY, "ElNdisuioQueryOIDValue: DeviceIoControl succeeded");
if (BytesReturned >= *pulOidDataLength)
{
TRACE2 (ANY, "ElNdisuioQueryOIDValue: BytesRet (%ld) >= SizeofInput (%ld); truncating data",
BytesReturned, *pulOidDataLength);
BytesReturned = *pulOidDataLength;
}
else
{
dwRetCode = ERROR_INVALID_DATA;
TRACE2 (ANY, "ElNdisuioQueryOIDValue: BytesRet (%ld) < SizeofInput (%ld)",
BytesReturned, *pulOidDataLength);
*pulOidDataLength = BytesReturned;
}
memcpy(pbOidData, &pQueryOid->Data[0], BytesReturned);
}
}
while (FALSE);
if (pQueryOid != NULL)
{
FREE (pQueryOid);
}
return dwRetCode;
}
#if 0
//
// ElGuidFromString
//
// Description:
//
// Convert a GUID-string to GUID
//
// Arguments:
// pGuid - pointer to GUID
// pszGuidString - pointer to string version of GUID
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElGuidFromString (
IN OUT GUID *pGuid,
IN CHAR *pszGuidString
)
{
DWORD dwGuidLen = 0;
WCHAR wszGuidString[64];
LPWSTR lpwszWithBraces = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
if (pszGuidString == NULL)
{
break;
}
ZeroMemory (pGuid, sizeof(GUID));
dwGuidLen = strlen (pszGuidString);
if (dwGuidLen != 36)
{
TRACE0 (ANY, "GuidFromString: Guid Length != required 36");
break;
}
if (0 == MultiByteToWideChar(
CP_ACP,
0,
pszGuidString,
-1,
wszGuidString,
dwGuidLen ) )
{
dwRetCode = GetLastError();
TRACE2 (ANY, "GuidFromString: MultiByteToWideChar(%s) failed: %d",
pszGuidString,
dwRetCode);
break;
}
wszGuidString[dwGuidLen] = L'\0';
// add the braces
lpwszWithBraces = (LPWSTR) MALLOC ((dwGuidLen + 1 + 2) * sizeof(WCHAR));
wsprintf (lpwszWithBraces, L"{%s}", wszGuidString);
CLSIDFromString (lpwszWithBraces, pGuid);
} while (FALSE);
return dwRetCode;
}
#endif
//
// ElGetLoggedOnUserName
//
// Description:
//
// Get the Username and Domain of the currently logged in user
//
// Arguments:
// pPCB - Pointer to port on which logged-on user's name is to be
// obtained
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
//
DWORD
ElGetLoggedOnUserName (
IN EAPOL_PCB *pPCB
)
{
HANDLE hUserToken;
WCHAR *pwszUserNameBuffer = NULL;
DWORD dwBufferSize = 0;
BOOL fNeedToRevertToSelf = FALSE;
DWORD dwRetCode = NO_ERROR;
do
{
hUserToken = pPCB->hUserToken;
if (hUserToken != NULL)
{
if (!ImpersonateLoggedOnUser (hUserToken))
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetLoggedOnUserName: ImpersonateLoggedOnUser failed with error %ld",
dwRetCode);
break;
}
fNeedToRevertToSelf = TRUE;
dwBufferSize = 0;
if (!GetUserNameEx (NameSamCompatible,
NULL,
&dwBufferSize))
{
dwRetCode = GetLastError ();
if (dwRetCode == ERROR_MORE_DATA)
{
if ((pwszUserNameBuffer = MALLOC (dwBufferSize*sizeof(WCHAR))) == NULL)
{
TRACE0 (ANY, "ElGetLoggedOnUserName: MALLOC failed for pwszUserNameBuffer");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (!GetUserNameEx (NameSamCompatible,
pwszUserNameBuffer,
&dwBufferSize))
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElGetLoggedOnUserName: GetUserNameEx failed with error %ld",
dwRetCode);
break;
}
pwszUserNameBuffer[dwBufferSize]=L'\0';
TRACE1 (ANY, "ElGetLoggedOnUserName: Got User Name %S",
pwszUserNameBuffer);
}
else
{
TRACE1 (ANY, "ElGetLoggedOnUserName: GetUserNameEx failed with error %ld",
dwRetCode);
break;
}
}
}
else
{
TRACE0 (ANY, "ElGetLoggedOnUserName: UserToken is NULL");
break;
}
} while (FALSE);
if (pwszUserNameBuffer != NULL)
{
FREE (pwszUserNameBuffer);
}
// Revert impersonation
if (fNeedToRevertToSelf)
{
if (!RevertToSelf())
{
dwRetCode = GetLastError();
TRACE1 (USER, "ElGetLoggedOnUserName: Error in RevertToSelf = %ld",
dwRetCode);
}
}
return dwRetCode;
}
//
// ElGetMachineName
//
// Description:
//
// Get the machine name of the computer the service is currently running on
//
// Arguments:
// pPCB - Pointer to PCB for the port on which machine name is to
// to be obtained
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
//
DWORD
ElGetMachineName (
IN EAPOL_PCB *pPCB
)
{
WCHAR *pwszComputerNameBuffer = NULL;
CHAR *pszComputerNameBuffer = NULL;
WCHAR *pwszComputerDomainBuffer = NULL;
CHAR *pszComputerDomainBuffer = NULL;
DWORD dwBufferSize = 0;
DWORD dwRetCode = NO_ERROR;
do
{
dwBufferSize = 0;
if (!GetComputerNameEx (ComputerNamePhysicalNetBIOS,
NULL,
&dwBufferSize))
{
dwRetCode = GetLastError ();
if (dwRetCode == ERROR_MORE_DATA)
{
// Reset error
dwRetCode = NO_ERROR;
if ((pwszComputerNameBuffer = MALLOC (dwBufferSize*sizeof(WCHAR))) == NULL)
{
TRACE0 (ANY, "ElGetMachineName: MALLOC failed for pwszComputerNameBuffer");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (!GetComputerNameEx (ComputerNamePhysicalNetBIOS,
pwszComputerNameBuffer,
&dwBufferSize))
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElGetMachineName: GetComputerNameEx failed with error %ld",
dwRetCode);
break;
}
TRACE1 (ANY, "ElGetMachineName: Got Computer Name %S",
pwszComputerNameBuffer);
pszComputerNameBuffer =
MALLOC (wcslen(pwszComputerNameBuffer) + 1);
if (pszComputerNameBuffer == NULL)
{
TRACE0 (ANY, "ElGetMachineName: MALLOC failed for pszComputerNameBuffer");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (0 == WideCharToMultiByte (
CP_ACP,
0,
pwszComputerNameBuffer,
-1,
pszComputerNameBuffer,
wcslen(pwszComputerNameBuffer)+1,
NULL,
NULL ))
{
dwRetCode = GetLastError();
TRACE2 (ANY, "ElGetMachineName: WideCharToMultiByte (%ws) failed: %ld",
pwszComputerNameBuffer, dwRetCode);
break;
}
pszComputerNameBuffer[wcslen(pwszComputerNameBuffer)] = L'\0';
}
else
{
TRACE1 (ANY, "ElGetMachineName: GetComputerNameEx failed with error %ld",
dwRetCode);
break;
}
}
dwBufferSize = 0;
if (!GetComputerNameEx (ComputerNamePhysicalDnsDomain,
NULL,
&dwBufferSize))
{
dwRetCode = GetLastError ();
if (dwRetCode == ERROR_MORE_DATA)
{
// Reset error
dwRetCode = NO_ERROR;
if ((pwszComputerDomainBuffer = MALLOC (dwBufferSize*sizeof(WCHAR))) == NULL)
{
TRACE0 (ANY, "ElGetMachineName: MALLOC failed for pwszComputerDomainBuffer");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (!GetComputerNameEx (ComputerNamePhysicalDnsDomain,
pwszComputerDomainBuffer,
&dwBufferSize))
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElGetMachineName: GetComputerNameEx Domain failed with error %ld",
dwRetCode);
break;
}
TRACE1 (ANY, "ElGetMachineName: Got Computer Domain %S",
pwszComputerDomainBuffer);
pszComputerDomainBuffer =
MALLOC (wcslen(pwszComputerDomainBuffer) + 1);
if (pszComputerDomainBuffer == NULL)
{
TRACE0 (ANY, "ElGetMachineName: MALLOC failed for pszComputerDomainBuffer");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (0 == WideCharToMultiByte (
CP_ACP,
0,
pwszComputerDomainBuffer,
-1,
pszComputerDomainBuffer,
wcslen(pwszComputerDomainBuffer)+1,
NULL,
NULL ))
{
dwRetCode = GetLastError();
TRACE2 (ANY, "ElGetMachineName: WideCharToMultiByte (%ws) failed: %ld",
pwszComputerDomainBuffer, dwRetCode);
break;
}
pszComputerDomainBuffer[wcslen(pwszComputerDomainBuffer)] = L'\0';
*(strrchr (pszComputerDomainBuffer, '.')) = '\0';
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
pPCB->pszIdentity = MALLOC (strlen(pszComputerDomainBuffer) +
strlen(pszComputerNameBuffer) + 3);
if (pPCB->pszIdentity == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (ANY, "ElGetMachineName: MALLOC failed for pPCB->pszIdentity");
break;
}
memcpy (pPCB->pszIdentity,
pszComputerDomainBuffer,
strlen(pszComputerDomainBuffer));
pPCB->pszIdentity[strlen(pszComputerDomainBuffer)] = '\\';
memcpy (&pPCB->pszIdentity[strlen(pszComputerDomainBuffer)+1],
pszComputerNameBuffer,
strlen(pszComputerNameBuffer));
pPCB->pszIdentity[strlen(pszComputerDomainBuffer)+1+strlen(pszComputerNameBuffer)] = '$';
pPCB->pszIdentity[strlen(pszComputerDomainBuffer)+1+strlen(pszComputerNameBuffer)+1] = '\0';
}
else
{
TRACE1 (ANY, "ElGetMachineName: GetComputerNameEx failed with error %ld",
dwRetCode);
break;
}
}
} while (FALSE);
if (pwszComputerNameBuffer != NULL)
{
FREE (pwszComputerNameBuffer);
}
if (pszComputerNameBuffer != NULL)
{
FREE (pszComputerNameBuffer);
}
if (pwszComputerDomainBuffer != NULL)
{
FREE (pwszComputerDomainBuffer);
}
if (pszComputerDomainBuffer != NULL)
{
FREE (pszComputerDomainBuffer);
}
return dwRetCode;
}
//
// ElUpdateRegistryInterfaceList
//
// Description:
//
// Write the interface list to which NDISUIO is bound to, to the registry
//
// Arguments:
// Interfaces - Interface list containing Device Name and Description
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
//
DWORD
ElUpdateRegistryInterfaceList (
IN PNDIS_ENUM_INTF Interfaces
)
{
CHAR *pszRegInterfaceList = NULL;
HKEY hkey = NULL;
DWORD dwDisposition = 0;
LONG lError = ERROR_SUCCESS;
DWORD dwRetCode = NO_ERROR;
do
{
ANSI_STRING InterfaceName;
UCHAR ucBuffer[256];
DWORD i;
DWORD dwSizeOfList = 0;
// Determine the number of bytes in the list
for (i=0; i < Interfaces->TotalInterfaces; i++)
{
ZeroMemory (ucBuffer, 256);
InterfaceName.Length = 0;
InterfaceName.MaximumLength = 256;
InterfaceName.Buffer = ucBuffer;
if (Interfaces->Interface[i].DeviceName.Buffer != NULL)
{
if (RtlUnicodeStringToAnsiString(&InterfaceName,
&(Interfaces->Interface[i].DeviceName), FALSE) != STATUS_SUCCESS)
{
TRACE1 (ANY, "ElUpdateRegistryInterfaceList: Error in RtlUnicodeStringToAnsiString for DeviceName %ws",
Interfaces->Interface[i].DeviceName.Buffer);
}
InterfaceName.Buffer[InterfaceName.Length] = '\0';
dwSizeOfList += (strlen(InterfaceName.Buffer) + 1);
}
else
{
TRACE0(INIT, "ElUpdateRegistryInterfaceList: Device Name was NULL");
continue;
}
TRACE1(INIT, "Device: %s", InterfaceName.Buffer);
}
// One extra char for terminating NULL char
pszRegInterfaceList = (CHAR *) MALLOC ( dwSizeOfList + 1 );
if ( pszRegInterfaceList == NULL )
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (ANY, "ElUpdateRegistryInterfaceList: MALLOC failed for pszRegInterfaceList");
break;
}
// Start again
dwSizeOfList = 0;
// Create the string in REG_SZ format
for (i=0; i < Interfaces->TotalInterfaces; i++)
{
ZeroMemory (ucBuffer, 256);
InterfaceName.Length = 0;
InterfaceName.MaximumLength = 256;
InterfaceName.Buffer = ucBuffer;
if (Interfaces->Interface[i].DeviceName.Buffer != NULL)
{
if (RtlUnicodeStringToAnsiString(&InterfaceName,
&Interfaces->Interface[i].DeviceName, FALSE) !=
STATUS_SUCCESS)
{
TRACE0 (ANY, "ElUpdateRegistryInterfaceList: Error in RtlUnicodeStringToAnsiString for DeviceName");
}
InterfaceName.Buffer[InterfaceName.Length] = '\0';
memcpy (&pszRegInterfaceList[dwSizeOfList],
InterfaceName.Buffer,
(strlen(InterfaceName.Buffer) ));
dwSizeOfList += (strlen(InterfaceName.Buffer));
}
else
{
TRACE0(INIT, "ElUpdateRegistryInterfaceList: Device Name was NULL");
continue;
}
}
// Final NULL character
pszRegInterfaceList[dwSizeOfList++] = '\0';
// Write the string as a REG_SZ value
// Get handle to
// HKLM\Software\Microsoft\EAPOL\Parameters\General
if ((lError = RegCreateKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolServiceParams,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hkey,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElUpdateRegistryInterfaceList: Error in RegCreateKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
//
// Set the value of
// ...\EAPOL\Parameters\General\InterfaceList key
//
if ((lError = RegSetValueExA (
hkey,
cszInterfaceList,
0,
REG_SZ,
pszRegInterfaceList,
dwSizeOfList)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElUpdateRegistryInterfaceList: Error in RegSetValueExA for InterfaceList, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
TRACE0 (ANY, "ElUpdateRegistryInterfaceList: Set value succeeded");
} while (FALSE);
if (hkey != NULL)
{
RegCloseKey (hkey);
}
if (pszRegInterfaceList != NULL)
{
FREE (pszRegInterfaceList);
}
return dwRetCode;
}
//
// ElWatchGlobalRegistryParams
//
// Description:
//
// Watch the registry for changes for global params. Update in-memory values
//
// Arguments:
// Unused
//
// Return values:
//
//
VOID
ElWatchGlobalRegistryParams (
IN PVOID pvContext
)
{
HKEY hKey = NULL;
HANDLE hRegChangeEvent = NULL;
HANDLE hEvents[2];
BOOL fExitThread = FALSE;
DWORD dwDisposition = 0;
DWORD dwStatus = 0;
LONG lError = 0;
DWORD dwRetCode = NO_ERROR;
TRACE0 (ANY, "ElWatchGlobalRegistryParams: Entered");
do
{
// Get handle to
// HKLM\Software\Microsoft\EAPOL\Parameters\General\Global
if ((lError = RegCreateKeyExA (
HKEY_LOCAL_MACHINE,
cszEAPOLGlobalParams,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWatchGlobalRegistryParams: Error in RegCreateKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Open a handle to a event to perform wait on that event
hRegChangeEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (hRegChangeEvent == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElWatchGlobalRegistryParams: Error in CreateEvent for hRegChangeEvent = %ld",
dwRetCode);
break;
}
// Register to notify change in registry value
if ((lError = RegNotifyChangeKeyValue (
hKey,
TRUE, // watch entire sub-tree
REG_NOTIFY_CHANGE_LAST_SET, // detect value add/delete
hRegChangeEvent,
TRUE // asynchronous
)) != ERROR_SUCCESS)
{
dwRetCode = (DWORD)lError;
TRACE1 (ANY, "ElWatchGlobalRegistryParams: RegNotifyChangeKeyValue failed with error %ld",
dwRetCode);
break;
}
do
{
// Wait for Registry changes or service termination
hEvents[0] = hRegChangeEvent;
hEvents[1] = g_hEventTerminateEAPOL;
if ((dwStatus = WaitForMultipleObjects(
2,
hEvents,
FALSE,
INFINITE
)) == WAIT_FAILED)
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElWatchGlobalRegistryParams: WaitForMultipleObjects failed with error %ld",
dwRetCode);
break;
}
switch (dwStatus)
{
case WAIT_OBJECT_0:
// Registry values changed
// Update in-memory values
if ((dwRetCode = ElReadGlobalRegistryParams ()) != NO_ERROR)
{
TRACE1 (ANY, "ElWatchGlobalRegistryParams: ElReadGlobalRegistryParams failed with error %ld",
dwRetCode);
// continue processing since this is not a critical error
dwRetCode = NO_ERROR;
}
if (!ResetEvent(hRegChangeEvent))
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElWatchGlobalRegistryParams: ResetEvent failed with error %ld",
dwRetCode);
break;
}
break;
case WAIT_OBJECT_0+1:
// Service shutdown detected
fExitThread = TRUE;
break;
default:
TRACE1 (ANY, "ElWatchGlobalRegistryParams: No such event = %ld",
dwStatus);
break;
}
if ((dwRetCode != NO_ERROR) || (fExitThread))
{
break;
}
} while (TRUE);
} while (FALSE);
TRACE1 (ANY, "ElWatchGlobalRegistryParams: Completed with error %ld",
dwRetCode);
if (hKey != NULL)
{
RegCloseKey(hKey);
}
return;
}
//
// ElReadGlobalRegistryParams
//
// Description:
//
// Read registry parameters global to EAPOL state machine
// i.e. maxStart, startPeriod, authPeriod, heldPeriod
//
// Arguments:
// Unused
//
// Return values:
//
// NO_ERROR - success
// non-zero - error
//
DWORD
ElReadGlobalRegistryParams ()
{
HKEY hKey = NULL;
DWORD dwDisposition = 0;
DWORD dwType = 0;
DWORD dwInfoSize = 0;
DWORD lError = 0;
DWORD dwmaxStart=0, dwstartPeriod=0, dwauthPeriod=0, dwheldPeriod=0;
DWORD dwRetCode = NO_ERROR;
do
{
// Get handle to
// HKLM\Software\Microsoft\EAPOL\Parameters\General\Global
if ((lError = RegCreateKeyExA (
HKEY_LOCAL_MACHINE,
cszEAPOLGlobalParams,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElReadGlobalRegistryParams: Error in RegCreateKeyExA for base key, %ld",
lError);
break;
}
ACQUIRE_WRITE_LOCK (&g_EAPOLConfig);
// If setting values for the first time, initialize values
if (!(g_dwmaxStart || g_dwstartPeriod || g_dwauthPeriod || g_dwheldPeriod))
{
g_dwmaxStart = EAPOL_MAX_START;
g_dwstartPeriod = EAPOL_START_PERIOD;
g_dwauthPeriod = EAPOL_AUTH_PERIOD;
g_dwheldPeriod = EAPOL_HELD_PERIOD;
}
RELEASE_WRITE_LOCK (&g_EAPOLConfig);
dwmaxStart = g_dwmaxStart;
dwstartPeriod = g_dwstartPeriod;
dwauthPeriod = g_dwauthPeriod;
dwheldPeriod = g_dwheldPeriod;
// Get the value of ..\General\EAPOLGlobal\authPeriod
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hKey,
cszAuthPeriod,
0,
&dwType,
(BYTE *)&dwauthPeriod,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElReadGlobalRegistryParams: Error in RegQueryValueExA for cszAuthPeriod, %ld, InfoSize=%ld",
lError, dwInfoSize);
dwauthPeriod = g_dwauthPeriod;
lError = ERROR_SUCCESS;
}
// Get the value of ..\General\EAPOLGlobal\heldPeriod
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hKey,
cszHeldPeriod,
0,
&dwType,
(BYTE *)&dwheldPeriod,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElReadGlobalRegistryParams: Error in RegQueryValueExA for cszHeldPeriod, %ld, InfoSize=%ld",
lError, dwInfoSize);
dwheldPeriod = g_dwheldPeriod;
lError = ERROR_SUCCESS;
}
// Get the value of ..\General\EAPOLGlobal\startPeriod
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hKey,
cszStartPeriod,
0,
&dwType,
(BYTE *)&dwstartPeriod,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElReadGlobalRegistryParams: Error in RegQueryValueExA for cszStartPeriod, %ld, InfoSize=%ld",
lError, dwInfoSize);
dwstartPeriod = g_dwstartPeriod;
lError = ERROR_SUCCESS;
}
// Get the value of ..\General\EAPOLGlobal\maxStart
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hKey,
cszMaxStart,
0,
&dwType,
(BYTE *)&dwmaxStart,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElReadGlobalRegistryParams: Error in RegQueryValueExA for cszMaxStart, %ld, InfoSize=%ld",
lError, dwInfoSize);
dwmaxStart = g_dwmaxStart;
lError = ERROR_SUCCESS;
}
// Successful in reading all parameters
ACQUIRE_WRITE_LOCK (&g_EAPOLConfig);
g_dwmaxStart = dwmaxStart;
g_dwstartPeriod = dwstartPeriod;
g_dwauthPeriod = dwauthPeriod;
g_dwheldPeriod = dwheldPeriod;
RELEASE_WRITE_LOCK (&g_EAPOLConfig);
} while (FALSE);
dwRetCode = (DWORD)lError;
if (dwRetCode != NO_ERROR)
{
TRACE1 (ANY, "ElReadGlobalRegistryParams: failed with error %ld",
dwRetCode);
}
if (hKey != NULL)
{
RegCloseKey(hKey);
}
return dwRetCode;
}
//
// ElWatchEapConfigRegistryParams
//
// Description:
//
// Watch the registry for changes in EAP config
// - HKLM - EAP type
// - HKLM - EAPOLEnabled
//
// Restart the state machine if the params change
//
// Arguments:
//
// Return values:
//
//
VOID
ElWatchEapConfigRegistryParams (
IN PVOID pvContext
)
{
HKEY hUserKey = NULL;
HKEY hWorkspaceKey = NULL;
HKEY hRegChangeKey = NULL;
HANDLE hRegChangeEvent = NULL;
HANDLE hEvents[2];
HANDLE hUserToken = NULL;
DWORD dwDisposition = 0;
BOOL fExitThread = FALSE;
DWORD dwStatus = 0;
LONG lError = 0;
DWORD dwRetCode = NO_ERROR;
TRACE0 (ANY, "ElWatchEapConfigRegistryParams: Entered");
do
{
// Get handle to
// HKLM\Software\Microsoft\EAPOL\Parameters\Interfaces
if ((lError = RegCreateKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolConn,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hWorkspaceKey,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: Error in RegCreateKeyExA for cszEapKeyEapolConn, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Open a handle to a event to perform wait on that event
hRegChangeEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (hRegChangeEvent == NULL)
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: Error in CreateEvent for hRegChangeEvent = %ld",
dwRetCode);
break;
}
do
{
// Register to notify change in registry value
if ((lError = RegNotifyChangeKeyValue (
hWorkspaceKey,
TRUE, // watch entire sub-tree
REG_NOTIFY_CHANGE_LAST_SET, // detect value add/delete
hRegChangeEvent,
TRUE // asynchronous
)) != ERROR_SUCCESS)
{
dwRetCode = (DWORD)lError;
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: RegNotifyChangeKeyValue failed with error %ld",
dwRetCode);
break;
}
// Wait for Registry changes, service termination
hEvents[0] = hRegChangeEvent;
hEvents[1] = g_hEventTerminateEAPOL;
if ((dwStatus = WaitForMultipleObjects(
2,
hEvents,
FALSE,
INFINITE
)) == WAIT_FAILED)
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: WaitForMultipleObjects failed with error %ld",
dwRetCode);
break;
}
switch (dwStatus)
{
case WAIT_OBJECT_0:
TRACE0 (ANY, "ElWatchEapConfigRegistryParams: Got reg change event !!! ");
// Registry values changed
// Update in memory values
if ((dwRetCode = ElProcessEapConfigChange ()) != NO_ERROR)
{
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: ElProcessEapConfigChange failed with error %ld",
dwRetCode);
// log
// continue processing since this is not a critical error
dwRetCode = NO_ERROR;
}
if (!ResetEvent(hRegChangeEvent))
{
dwRetCode = GetLastError ();
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: ResetEvent failed with error %ld",
dwRetCode);
break;
}
break;
case WAIT_OBJECT_0+1:
// Service shutdown detected
fExitThread = TRUE;
TRACE0 (ANY, "ElWatchEapConfigRegistryParams: Service shutdonw");
break;
default:
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: No such event = %ld",
dwStatus);
break;
}
if ((dwRetCode != NO_ERROR) || (fExitThread))
{
break;
}
TRACE0 (ANY, "ElWatchEapConfigRegistryParams: RegNotifyChangeKeyValue being reposted !!!");
} while (TRUE);
} while (FALSE);
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: Completed with error %ld",
dwRetCode);
if (hUserKey != NULL)
{
RegCloseKey(hUserKey);
}
if (hWorkspaceKey != NULL)
{
RegCloseKey(hWorkspaceKey);
}
if (!CloseHandle(hRegChangeEvent))
{
TRACE1 (ANY, "ElWatchEapConfigRegistryParams: Error in closing event handle", (dwRetCode = GetLastError()));
}
return;
}
//
// ElProcessEapConfigChange
//
// Description:
//
// Read EAP config changes made in registry. Restart EAPOL on the particular
// interface or stop EAPOL
//
// Arguments:
//
// Return values:
//
// NO_ERROR - success
// non-zero - error
//
DWORD
ElProcessEapConfigChange ()
{
DWORD dwEapolEnabled = 0;
DWORD dwDefaultEAPType = 0;
CHAR szLastUsedSSID[256];
HKEY hWorkspaceKey = NULL;
HKEY hKey = NULL, hKey1 = NULL;
DWORD dwType = 0;
DWORD dwInfoSize = 0;
DWORD dwDisposition = 0;
CHAR *pszLastModifiedGUID = NULL;
DWORD dwbData = 0;
PBYTE pbAuthData = NULL;
EAPOL_PCB *pPCB = NULL;
BOOL fReStartAuthentication = FALSE;
LONG lError = 0;
DWORD dwRetCode = NO_ERROR;
do
{
// Get the GUID for the interface for which EAP config was modified
// Get handle to
// HKLM\Software\Microsoft\EAPOL\Parameters\General\EAPOLGlobal
if ((lError = RegCreateKeyExA (
HKEY_LOCAL_MACHINE,
cszEAPOLWorkspace,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hWorkspaceKey,
&dwDisposition)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElProcessEapConfigChange: Error in RegCreateKeyExA for cszEAPOLWorkspace key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get the value of ..\General\EAPOLGlobal\LastModifiedGUID
dwInfoSize = 0;
if ((lError = RegQueryValueExA (
hWorkspaceKey,
cszLastModifiedGUID,
0,
&dwType,
NULL,
&dwInfoSize)) == ERROR_SUCCESS)
{
if ((pszLastModifiedGUID = (CHAR *) MALLOC ( dwInfoSize ))
== NULL)
{
TRACE0 (ANY, "ElProcessEapConfigChange: Error in MALLOC for pszLastModifiedGUID");
lError = (ULONG) ERROR_NOT_ENOUGH_MEMORY;
dwRetCode = (DWORD)lError;
break;
}
if ((lError = RegQueryValueExA (
hWorkspaceKey,
cszLastModifiedGUID,
0,
&dwType,
pszLastModifiedGUID,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElProcessEapConfigChange: RegQueryValueExA failed for pszLastModifiedGUID with error %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
}
else
{
TRACE1 (ANY, "ElProcessEapConfigChange: Error in estimating size fo cszLastModifiedGUID = %ld",
lError);
break;
}
// Check the value of EAPOLEnabled for that interface
// Get handle to HKLM\Software\Microsoft\EAPOL\Parameters\Interfaces
if ((lError = RegOpenKeyExA (
HKEY_LOCAL_MACHINE,
cszEapKeyEapolConn,
0,
KEY_READ,
&hKey
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElProcessEapConfigChange: Error in RegOpenKeyExA for base key, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get handle to HKLM\Software\...\Interfaces\<GUID>
if ((lError = RegOpenKeyExA (
hKey,
pszLastModifiedGUID,
0,
KEY_READ,
&hKey1
)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElProcessEapConfigChange: Error in RegOpenKeyExA for GUID, %ld",
lError);
dwRetCode = (DWORD)lError;
break;
}
// Get the value of ..\Interfaces\GUID\EapolEnabled
// This value should exist since it will always be set from UI
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hKey1,
cszEapolEnabled,
0,
&dwType,
(BYTE *)&dwEapolEnabled,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElProcessEapConfigChange: Error in RegQueryValueExA for EapolEnabled, %ld, InfoSize=%ld",
lError, dwInfoSize);
dwRetCode = (DWORD)lError;
break;
}
TRACE1 (ANY, "ElProcessEapConfigChange: Got EapolEnabled = %ld", dwEapolEnabled);
// Get the value of ..\Interfaces\GUID\DefaultEAPType
// This value should exist since it will always be set from UI
dwInfoSize = sizeof(DWORD);
if ((lError = RegQueryValueExA (
hKey1,
cszDefaultEAPType,
0,
&dwType,
(BYTE *)&dwDefaultEAPType,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE2 (ANY, "ElProcessEapConfigChange: Error in RegQueryValueExA for DefaultEAPType, %ld, InfoSize=%ld",
lError, dwInfoSize);
dwRetCode = (DWORD)lError;
break;
}
// Get the value of ..\Interfaces\GUID\LastUsedSSID
dwInfoSize = 256;
ZeroMemory ((BYTE *)szLastUsedSSID, 256);
if ((lError = RegQueryValueExA (
hKey1,
cszLastUsedSSID,
0,
&dwType,
(PUCHAR)szLastUsedSSID,
&dwInfoSize)) != ERROR_SUCCESS)
{
TRACE1 (ANY, "ElProcessEapConfigChange: Error in RegQueryValueExA for LastUsedSSID, %ld",
lError);
dwRetCode = (DWORD)lError;
if (dwRetCode == ERROR_FILE_NOT_FOUND)
{
// SSID may not be received as yet from AP/switch
// Changes will be made stored for "Default" SSID
dwRetCode = NO_ERROR;
}
else
{
break;
}
}
// Check existence/absence of PCB i.e. if EAPOL state machine was
// started on the interface, and take appropriate action based on
// EAPOLEnabled value
if (dwEapolEnabled == 0)
{
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
if ((pPCB = ElGetPCBPointerFromPortGUID (pszLastModifiedGUID))
!= NULL)
{
RELEASE_WRITE_LOCK (&(g_PCBLock));
// Found PCB for interface, where EAPOLEnabled = 0
// Stop EAPOL on the port and remove the port from the module
if ((dwRetCode = ElShutdownInterface (pszLastModifiedGUID))
!= NO_ERROR)
{
TRACE1 (ANY, "ElProcessEapConfigChange: ElShutdownInterface failed with error %ld",
dwRetCode);
break;
}
}
else
{
// No PCB found for interface, valid condition,
// continue processing
RELEASE_WRITE_LOCK (&(g_PCBLock));
}
}
else
{
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
if ((pPCB = ElGetPCBPointerFromPortGUID (pszLastModifiedGUID))
== NULL)
{
RELEASE_WRITE_LOCK (&(g_PCBLock));
// Did not find PCB for interface, where EAPOLEnabled = 1
// Start EAPOL on the port
ACQUIRE_WRITE_LOCK (&g_ITFLock);
if ((dwRetCode = ElEnumAndOpenInterfaces (NULL,
pszLastModifiedGUID))
!= NO_ERROR)
{
RELEASE_WRITE_LOCK (&g_ITFLock);
TRACE1 (ANY, "ElProcessEapConfigChange: ElEnumAndOpenInterfaces returned error %ld",
dwRetCode);
break;
}
RELEASE_WRITE_LOCK (&g_ITFLock);
}
else
{
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
if (pPCB->dwEapTypeToBeUsed != dwDefaultEAPType)
{
// Default EAP Type has changed
fReStartAuthentication = TRUE;
}
else
{
// Default EAP Type is the same
// Check if the CustomAuthData is the same
// If not the same, do further processing
// Else, no change occured, same config was reapplied
// Get the size of the EAP blob
if ((dwRetCode = ElGetCustomAuthData (
pszLastModifiedGUID,
dwDefaultEAPType,
szLastUsedSSID,
NULL,
&dwbData
)) != NO_ERROR)
{
if (dwRetCode == ERROR_BUFFER_TOO_SMALL)
{
if (dwbData <= 0)
{
if (pPCB->pCustomAuthConnData->pbCustomAuthData)
{
// No EAP blob stored in the registry
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
RELEASE_WRITE_LOCK (&(g_PCBLock));
TRACE0 (ANY, "ElProcessEapConfigChange: NULL sized EAP blob, cannot continue");
pbAuthData = NULL;
dwRetCode = ERROR_CAN_NOT_COMPLETE;
break;
}
}
else
{
// Allocate memory to hold the blob
pbAuthData = MALLOC (dwbData);
if (pbAuthData == NULL)
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
RELEASE_WRITE_LOCK (&(g_PCBLock));
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (ANY, "ElProcessEapConfigChange: Error in memory allocation for EAP blob");
break;
}
if ((dwRetCode = ElGetCustomAuthData (
pszLastModifiedGUID,
dwDefaultEAPType,
szLastUsedSSID,
pbAuthData,
&dwbData
)) != NO_ERROR)
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
RELEASE_WRITE_LOCK (&(g_PCBLock));
TRACE1 (ANY, "ElProcessEapConfigChange: ElGetCustomAuthData failed with %ld",
dwRetCode);
break;
}
}
}
else
{
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
RELEASE_WRITE_LOCK (&(g_PCBLock));
TRACE1 (ANY, "ElProcessEapConfigChange: ElGetCustomAuthData failed in size estimation with error %ld",
dwRetCode);
break;
}
}
if (pPCB->pCustomAuthConnData == NULL)
{
if (dwbData > 0)
{
fReStartAuthentication = TRUE;
}
}
else
{
if (pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData
!= dwbData)
{
// Same EAP Type, but different lengths
fReStartAuthentication = TRUE;
}
else
{
if (memcmp (
pPCB->pCustomAuthConnData->pbCustomAuthData,
pbAuthData, dwbData) != 0)
{
// Same EAP Type, same data length, but
// different contents
fReStartAuthentication = TRUE;
}
else
{
// No change in EAP config data for this
// interface
}
}
}
}
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
if (fReStartAuthentication)
{
if ((dwRetCode = ElReStartPort (pPCB)) != NO_ERROR)
{
RELEASE_WRITE_LOCK (&(g_PCBLock));
TRACE1 (ANY, "ElProcessEapConfigChange: Error in ElReStartPort = %d",
dwRetCode);
break;
}
}
RELEASE_WRITE_LOCK (&(g_PCBLock));
}
}
} while (FALSE);
if (hWorkspaceKey != NULL)
{
RegCloseKey(hWorkspaceKey);
}
if (hKey != NULL)
{
RegCloseKey(hKey);
}
if (hKey1 != NULL)
{
RegCloseKey(hKey1);
}
if (pszLastModifiedGUID != NULL)
{
FREE (pszLastModifiedGUID);
}
if (pbAuthData != NULL)
{
FREE (pbAuthData);
}
return dwRetCode;
}
//
// ElStringToGuid
//
// Description:
//
// Function to convert a Guid-String to a GUID
//
// Arguments:
// psGuid - String-ized Guid
// pGuid - Pointer to Guid
//
// Return values:
// None
//
VOID
ElStringToGuid (
IN CHAR * psGuid,
OUT LPGUID pGuid
)
{
CHAR c;
DWORD i=0;
//
// If the first character is a '{', skip it.
//
if ( psGuid[0] == L'{' )
psGuid++;
//
// Convert string to guid
// (since psGuid may be used again below, no permanent modification to
// it may be made)
//
c = psGuid[8];
psGuid[8] = 0;
pGuid->Data1 = strtoul ( &psGuid[0], 0, 16 );
psGuid[8] = c;
c = psGuid[13];
psGuid[13] = 0;
pGuid->Data2 = (USHORT)strtoul ( &psGuid[9], 0, 16 );
psGuid[13] = c;
c = psGuid[18];
psGuid[18] = 0;
pGuid->Data3 = (USHORT)strtoul ( &psGuid[14], 0, 16 );
psGuid[18] = c;
c = psGuid[21];
psGuid[21] = 0;
pGuid->Data4[0] = (unsigned char)strtoul ( &psGuid[19], 0, 16 );
psGuid[21] = c;
c = psGuid[23];
psGuid[23] = 0;
pGuid->Data4[1] = (unsigned char)strtoul ( &psGuid[21], 0, 16 );
psGuid[23] = c;
for ( i=0; i < 6; i++ )
{
c = psGuid[26+i*2];
psGuid[26+i*2] = 0;
pGuid->Data4[2+i] = (unsigned char)strtoul ( &psGuid[24+i*2], 0, 16 );
psGuid[26+i*2] = c;
}
return;
}
//
// ElGetIdentity
//
// Description:
//
// Get the identity depending on the authentication type being used
//
// Arguments:
// pPCB - Pointer to PCB for the port
//
// Return values:
//
// NO_ERROR - success
// non-zero - error
//
DWORD
ElGetIdentity (
IN EAPOL_PCB *pPCB
)
{
DWORD dwRetCode = NO_ERROR;
do
{
// Get user's identity if it has not been obtained till now
if ((g_fUserLoggedOn) &&
(pPCB->dwAuthFailCount <= EAPOL_MAX_AUTH_FAIL_COUNT) &&
(pPCB->PreviousAuthenticationType != EAPOL_MACHINE_AUTHENTICATION))
{
TRACE0 (ANY, "ElGetIdentity: Userlogged, <Maxauth, Prev !Machine auth");
if (!(pPCB->fGotUserIdentity))
{
// NOTE: Hardcoding for now
// Needs to be solved
if (pPCB->dwEapTypeToBeUsed == EAP_TYPE_MD5)
{
TRACE0 (ANY, "ElGetIdentity: Userlogged, <Maxauth, Prev !Machine auth: MD5");
// EAP-MD5CHAP
if ((dwRetCode = ElGetUserNamePassword (
pPCB)) != NO_ERROR)
{
TRACE1 (ANY, "ElEapMakeMessage: Error in ElGetUserNamePassword %ld",
dwRetCode);
}
}
else
{
TRACE0 (ANY, "ElGetIdentity: Userlogged, <Maxauth, Prev !Machine auth: !MD5");
// All other EAP Types
if ((dwRetCode = ElGetUserIdentity (
pPCB)) != NO_ERROR)
{
TRACE1 (ANY, "ElEapMakeMessage: Error in ElGetUserIdentity %ld",
dwRetCode);
}
}
if (dwRetCode == NO_ERROR)
{
TRACE0 (ANY, "ElGetIdentity: Userlogged, <Maxauth, Prev !Machine auth: No Error: User Auth fine");
pPCB->PreviousAuthenticationType = EAPOL_USER_AUTHENTICATION;
}
else
{
TRACE0 (ANY, "ElGetIdentity: Userlogged, <Maxauth, Prev !Machine auth: Error");
// No UI required
if ((pPCB->dwEapTypeToBeUsed != EAP_TYPE_MD5) &&
(g_dwMachineAuthEnabled))
{
TRACE0 (ANY, "ElGetIdentity: Userlogged, <Maxauth, Prev !Machine auth: Error: !MD5, Machine Auth");
// Get Machine name
dwRetCode = NO_ERROR;
pPCB->PreviousAuthenticationType =
EAPOL_MACHINE_AUTHENTICATION;
dwRetCode = ElGetUserIdentity (pPCB);
if (dwRetCode != NO_ERROR)
{
TRACE1 (ANY, "ElGetIdentity: ElGetUserIdentity failed with error %ld",
dwRetCode);
}
}
if ((dwRetCode != NO_ERROR) ||
(!g_dwMachineAuthEnabled) ||
(pPCB->dwEapTypeToBeUsed == EAP_TYPE_MD5))
{
TRACE3 (ANY, "ElGetIdentity: Userlogged, <Maxauth, !Machine auth: Error: Error=%ld, Machauth=%ld, MD5=%ld",
dwRetCode?1:0,
g_dwMachineAuthEnabled?1:0,
(pPCB->dwEapTypeToBeUsed == EAP_TYPE_MD5)?1:0);
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
pPCB->PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
dwRetCode = NO_ERROR;
}
}
}
}
else
{
TRACE2 (ANY, "ElGetIdentity: Userlogged=%ld, auth>max, Machine auth=%ld",
g_fUserLoggedOn?1:0,
(pPCB->PreviousAuthenticationType==EAPOL_MACHINE_AUTHENTICATION)?1:0 );
// No UI required
if ((pPCB->dwEapTypeToBeUsed != EAP_TYPE_MD5) &&
(g_dwMachineAuthEnabled))
{
TRACE0 (ANY, "ElGetIdentity: !MD5, Machine auth");
pPCB->PreviousAuthenticationType = EAPOL_MACHINE_AUTHENTICATION;
// Get Machine credentials
dwRetCode = ElGetUserIdentity (pPCB);
if (dwRetCode != NO_ERROR)
{
TRACE1 (ANY, "ElGetIdentity: ElGetUserIdentity failed with error %ld",
dwRetCode);
}
}
if ((dwRetCode != NO_ERROR) ||
(!g_dwMachineAuthEnabled) ||
(pPCB->dwEapTypeToBeUsed == EAP_TYPE_MD5))
{
TRACE3 (ANY, "ElGetIdentity: Error=%ld, Machine auth=%ld, MD5=%ld",
dwRetCode?1:0,
g_dwMachineAuthEnabled?1:0,
(pPCB->dwEapTypeToBeUsed == EAP_TYPE_MD5)?1:0);
if (pPCB->pszIdentity != NULL)
{
FREE (pPCB->pszIdentity);
pPCB->pszIdentity = NULL;
}
pPCB->PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
dwRetCode = NO_ERROR;
}
}
}
while (FALSE);
return dwRetCode;
}
//
// ElNLAConnectLPC
//
// Description:
//
// Function called to connect to the LPC port for NLA service
//
// Arguments:
// None
//
// Return values:
// Non-NULL - valid handle
// NULL - error
//
HANDLE
ElNLAConnectLPC ()
{
HANDLE h = NULL;
LARGE_INTEGER sectionSize;
UNICODE_STRING portName;
SECURITY_QUALITY_OF_SERVICE dynamicQoS =
{
sizeof(SECURITY_QUALITY_OF_SERVICE),
SecurityAnonymous,
SECURITY_DYNAMIC_TRACKING,
FALSE
};
WSM_LPC_DATA data;
ULONG dataLength;
NTSTATUS status = STATUS_SUCCESS;
do
{
TRACE0 (EAP, "NLAConnectLPC: Entered");
// Create a shared section for passing the large-size LPC messages.
RtlZeroMemory(&g_ClientView, sizeof(g_ClientView));
g_ClientView.Length = sizeof(g_ClientView);
g_ClientView.ViewSize = sizeof(LOCATION_802_1X);
sectionSize.QuadPart = sizeof(LOCATION_802_1X);
status = NtCreateSection (&g_ClientView.SectionHandle,
(SECTION_MAP_READ | SECTION_MAP_WRITE),
NULL,
&sectionSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL
);
if (!NT_SUCCESS(status))
{
h = NULL;
TRACE1 (EAP, "NLAConnectLPC: NtCreateSection failed with error",
status);
break;
}
// Connect via LPC to the Network Location Awareness (NLA) service.
RtlInitUnicodeString (&portName, WSM_PRIVATE_PORT_NAME);
RtlZeroMemory (&data, sizeof (data));
data.signature = WSM_SIGNATURE;
data.connect.version.major = WSM_VERSION_MAJOR;
data.connect.version.minor = WSM_VERSION_MINOR;
dataLength = sizeof (data);
status = NtConnectPort (&h,
&portName,
&dynamicQoS,
&g_ClientView,
NULL,
NULL,
&data,
&dataLength
);
// If NtConnectPort() succeeded, LPC will maintain a reference
// to the section, otherwise we no longer need it.
NtClose (g_ClientView.SectionHandle);
g_ClientView.SectionHandle = NULL;
if (!NT_SUCCESS(status)) {
TRACE1 (EAP, "NLAConnectLPC: NtConnectPort failed with error %ld",
status);
ASSERT (h == NULL);
}
}
while (FALSE);
return (h);
}
//
// ElNLACleanupLPC
//
// Description:
//
// Function called to close the LPC port for NLA service
//
// Arguments:
// None
//
// Return values:
// None
//
VOID
ElNLACleanupLPC ()
{
if (g_hNLA_LPC_Port != NULL) {
NtClose (g_hNLA_LPC_Port);
g_hNLA_LPC_Port = NULL;
}
}
//
// ElNLARegister_802_1X
//
// Description:
//
// Function called to register 802.1X information with NLA
//
// Arguments:
// plocation - Pointer to data needed to be registered with NLA
//
// Return values:
// None
//
VOID
ElNLARegister_802_1X (
IN PLOCATION_802_1X plocation
)
{
WSM_LPC_MESSAGE message;
NTSTATUS status;
ACQUIRE_WRITE_LOCK (&g_NLALock);
do
{
TRACE0 (EAP, "NLARegister_802_1X: Entered");
// Connect to the Network Location Awareness (NLA) service if
// necessary.
if (g_hNLA_LPC_Port == NULL) {
if ((g_hNLA_LPC_Port = ElNLAConnectLPC ()) == NULL) {
RELEASE_WRITE_LOCK (&g_NLALock);
return;
}
}
TRACE0 (EAP, "NLARegister_802_1X: g_hNLA_LPC_Port != NULL");
// Send information to the NLA service.
RtlZeroMemory (&message, sizeof (message));
message.portMsg.u1.s1.TotalLength = sizeof (message);
message.portMsg.u1.s1.DataLength = sizeof (message.data);
message.data.signature = WSM_SIGNATURE;
message.data.request.type = LOCATION_802_1X_REGISTER;
__try {
RtlCopyMemory (g_ClientView.ViewBase,
plocation, sizeof(LOCATION_802_1X));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return;
}
status = NtRequestWaitReplyPort ( g_hNLA_LPC_Port, (PPORT_MESSAGE)&message, (PPORT_MESSAGE)&message);
if (status != STATUS_SUCCESS) {
TRACE1 (EAP, "NLARegister_802_1X: NtWaitReplyPort failed with error",
status);
// It's possible the service was stopped and restarted.
// Ditch the old LPC connection.
CloseHandle (g_hNLA_LPC_Port);
// Create a new LPC connection.
if ((g_hNLA_LPC_Port = ElNLAConnectLPC ()) == NULL) {
RELEASE_WRITE_LOCK (&g_NLALock);
TRACE0 (EAP, "NLARegister_802_1X: NLAConnectLPC failed");
return;
}
// Try the send one last time.
status = NtRequestWaitReplyPort (g_hNLA_LPC_Port,
(PPORT_MESSAGE)&message, (PPORT_MESSAGE)&message);
TRACE1 (EAP, "NLARegister_802_1X: NtWaitReplyPort, try 2, failed with error",
status);
}
TRACE1 (EAP, "NLARegister_802_1X: Completed with status = %ld",
status);
}
while (FALSE);
RELEASE_WRITE_LOCK (&g_NLALock);
}
//
// ElNLADelete_802_1X
//
// Description:
//
// Function called to de-register 802.1X information registered with NLA
//
// Arguments:
// plocation - Pointer to data to be de-registered from NLA
//
// Return values:
// None
//
VOID
ElNLADelete_802_1X (
IN PLOCATION_802_1X plocation
)
{
WSM_LPC_MESSAGE message;
NTSTATUS status;
ACQUIRE_WRITE_LOCK (&g_NLALock);
do
{
// Connect to the NLA service if necessary.
if (g_hNLA_LPC_Port == NULL)
{
if ((g_hNLA_LPC_Port = ElNLAConnectLPC ()) == NULL)
{
RELEASE_WRITE_LOCK (&g_NLALock);
return;
}
}
// Send information to the NLA service.
RtlZeroMemory (&message, sizeof(message));
message.portMsg.u1.s1.TotalLength = sizeof (message);
message.portMsg.u1.s1.DataLength = sizeof (message.data);
message.data.signature = WSM_SIGNATURE;
message.data.request.type = LOCATION_802_1X_DELETE;
__try {
RtlCopyMemory (g_ClientView.ViewBase,
plocation, sizeof(plocation->adapterName));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return;
}
status = NtRequestWaitReplyPort (g_hNLA_LPC_Port,
(PPORT_MESSAGE)&message, (PPORT_MESSAGE)&message);
if (status != STATUS_SUCCESS)
{
// If the service was stopped (and possibly restarted), we don't
// care ... it won't have this information in its list for us
// to bother deleting.
CloseHandle (g_hNLA_LPC_Port);
g_hNLA_LPC_Port = NULL;
}
}
while (FALSE);
RELEASE_WRITE_LOCK (&g_NLALock);
}
//
// ElGetInterfaceNdisStatistics
//
// Function to query NDIS NIC_STATISTICS parameters for an interface
//
// Input arguments:
// pszInterfaceName - Interface Name
//
// Return values:
// pStats - NIC_STATISTICS structure
//
//
DWORD
ElGetInterfaceNdisStatistics (
IN CHAR *pszInterfaceName,
IN OUT NIC_STATISTICS *pStats
)
{
WCHAR *pwszInterfaceName = NULL;
UNICODE_STRING UInterfaceName;
DWORD dwRetCode = NO_ERROR;
do
{
pwszInterfaceName = MALLOC ((strlen (pszInterfaceName)+12)*sizeof(WCHAR));
if (pwszInterfaceName == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (ANY, "ElGetInterfaceNdisStatistics: MALLOC failed for pwszInterfaceName");
break;
}
wcscpy (pwszInterfaceName, L"\\Device\\{");
if (0 == MultiByteToWideChar(
CP_ACP,
0,
pszInterfaceName,
-1,
&pwszInterfaceName[9],
(strlen(pszInterfaceName)+12)*sizeof(WCHAR)))
{
dwRetCode = GetLastError();
TRACE2 (ANY, "ElGetInterfaceNdisStatistics: MultiByteToWideChar(%s) failed: %ld",
pszInterfaceName, dwRetCode);
break;
}
pwszInterfaceName[strlen(pszInterfaceName) + 9] = L'\0';
wcscat (pwszInterfaceName, L"}");
TRACE1 (ANY, "ElGetInterfaceNdisStatistics: pwszInterfaceName = (%ws)",
pwszInterfaceName);
RtlInitUnicodeString (&UInterfaceName, pwszInterfaceName);
pStats->Size = sizeof(NIC_STATISTICS);
if (NdisQueryStatistics (&UInterfaceName, pStats))
{
}
else
{
dwRetCode = GetLastError ();
TRACE2 (ANY, "ElGetInterfaceNdisStatistics: NdisQueryStatistics failed with error (%ld), Interface=%ws",
dwRetCode, UInterfaceName.Buffer);
}
}
while (FALSE);
if (pwszInterfaceName != NULL)
{
FREE (pwszInterfaceName);
}
return dwRetCode;
}