You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1113 lines
27 KiB
1113 lines
27 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 2001
|
|
//
|
|
// File: U T I L. C
|
|
//
|
|
// Contents: Utility functions
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "util.h"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// EAPOL related util functions
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
// EAP configuration registry definitions.
|
|
|
|
static WCHAR REGKEY_Eap[] = L"System\\CurrentControlSet\\Services\\Rasman\\PPP\\EAP";
|
|
static WCHAR REGVAL_szFriendlyName[] = L"FriendlyName";
|
|
static WCHAR REGVAL_szConfigDll[] = L"ConfigUIPath";
|
|
static WCHAR REGVAL_szIdentityDll[] = L"IdentityPath";
|
|
static WCHAR REGVAL_fRequirePwd[] = L"InvokePasswordDialog";
|
|
static WCHAR REGVAL_fRequireUser[] = L"InvokeUsernameDialog";
|
|
static WCHAR REGVAL_pData[] = L"ConfigData";
|
|
static WCHAR REGVAL_fForceConfig[] = L"RequireConfigUI";
|
|
static WCHAR REGVAL_fMppeSupported[] = L"MPPEEncryptionSupported";
|
|
|
|
// Location of User blob
|
|
#define cwszEapKeyEapolUser L"Software\\Microsoft\\EAPOL\\UserEapInfo"
|
|
#define cwszDefault L"Default"
|
|
|
|
BYTE g_bDefaultSSID[MAX_SSID_LEN]={0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22};
|
|
|
|
//
|
|
// EAP configuration manipulation routines
|
|
//
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Returns a created, empty EAPCFG descriptor node, or NULL on error.
|
|
//
|
|
|
|
DTLNODE*
|
|
CreateEapcfgNode (
|
|
void
|
|
)
|
|
{
|
|
DTLNODE* pNode = NULL;
|
|
EAPCFG* pEapcfg = NULL;
|
|
|
|
pNode = DtlCreateSizedNode( sizeof(EAPCFG), 0L );
|
|
if (pNode)
|
|
{
|
|
pEapcfg = (EAPCFG* )DtlGetData( pNode );
|
|
|
|
if (pEapcfg)
|
|
{
|
|
pEapcfg->dwKey = (DWORD )-1;
|
|
pEapcfg->pszConfigDll = NULL;
|
|
pEapcfg->pszIdentityDll = NULL;
|
|
pEapcfg->dwStdCredentialFlags = 0;
|
|
pEapcfg->fProvidesMppeKeys = FALSE;
|
|
pEapcfg->fForceConfig = FALSE;
|
|
pEapcfg->pData = NULL;
|
|
pEapcfg->cbData = 0;
|
|
pEapcfg->fConfigDllCalled = FALSE;
|
|
}
|
|
}
|
|
|
|
return pNode;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Release resources associated with EAPCFG node 'pNode'. See
|
|
// DtlDestroyList.
|
|
//
|
|
|
|
VOID
|
|
DestroyEapcfgNode (
|
|
IN OUT DTLNODE* pNode
|
|
)
|
|
{
|
|
EAPCFG* pEapcfg = NULL;
|
|
|
|
pEapcfg = (EAPCFG* )DtlGetData( pNode );
|
|
|
|
if (pEapcfg)
|
|
{
|
|
if (pEapcfg->pszConfigDll)
|
|
FREE ( pEapcfg->pszConfigDll );
|
|
if (pEapcfg->pszIdentityDll)
|
|
FREE ( pEapcfg->pszIdentityDll );
|
|
if (pEapcfg->pData)
|
|
FREE ( pEapcfg->pData );
|
|
if (pEapcfg->pszFriendlyName)
|
|
FREE ( pEapcfg->pszFriendlyName );
|
|
}
|
|
|
|
DtlDestroyNode( pNode );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Returns the EAPCFG node in list 'pList' with EAP key value of 'dwKey'
|
|
// or NULL if not found.
|
|
//
|
|
|
|
DTLNODE*
|
|
EapcfgNodeFromKey(
|
|
IN DTLLIST* pList,
|
|
IN DWORD dwKey
|
|
)
|
|
{
|
|
DTLNODE* pNode = NULL;
|
|
|
|
for (pNode = DtlGetFirstNode( pList );
|
|
pNode;
|
|
pNode = DtlGetNextNode( pNode ))
|
|
{
|
|
EAPCFG* pEapcfg = (EAPCFG* )DtlGetData( pNode );
|
|
|
|
if (pEapcfg)
|
|
{
|
|
if (pEapcfg->dwKey == dwKey)
|
|
{
|
|
return pNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Returns the address of a created list of installed custom
|
|
// authentication packages or NULL if none could be read. On success, it
|
|
// is caller's responsibility to eventually call DtlDestroyList on the
|
|
// returned list.
|
|
//
|
|
|
|
DTLLIST*
|
|
ReadEapcfgList (
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
|
|
DWORD dwErr = 0;
|
|
BOOL fOk = FALSE;
|
|
DTLLIST* pList = NULL;
|
|
DTLNODE* pNode = NULL;
|
|
EAPCFG* pEapcfg = NULL;
|
|
HKEY hkeyLM = NULL;
|
|
HKEY hkeyEap = NULL;
|
|
HKEY hkeyPackage = NULL;
|
|
CHAR szEapType[ 11 + 1 ];
|
|
DWORD dwEapType = 0;
|
|
TCHAR* psz = NULL;
|
|
DWORD dw;
|
|
DWORD cb;
|
|
INT i;
|
|
TCHAR* szCLSID = NULL;
|
|
DWORD dwHidePEAPMSCHAPv2 = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
pList = DtlCreateList( 0L );
|
|
if (!pList)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Open the EAP key which contains a sub-key for each installed package.
|
|
|
|
dwErr = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE, (LPCTSTR)REGKEY_Eap, 0, KEY_READ, &hkeyEap );
|
|
|
|
if (dwErr != NO_ERROR)
|
|
{
|
|
return pList;
|
|
}
|
|
|
|
// Display EAP-MSCHAPv2 as an EAP method?
|
|
GetRegDword( hkeyEap, RAS_EAP_VALUENAME_HIDEPEAPMSCHAPv2, &dwHidePEAPMSCHAPv2 );
|
|
|
|
// Open each sub-key and extract the package definition from it's values.
|
|
// Problems with opening individual sub-keys result in that node only
|
|
// being discarded.
|
|
|
|
for (i = 0; TRUE; ++i)
|
|
{
|
|
cb = sizeof(szEapType);
|
|
dwErr = RegEnumKeyExA(
|
|
hkeyEap, i, szEapType, &cb, NULL, NULL, NULL, NULL );
|
|
if (dwErr != 0)
|
|
{
|
|
// Includes "out of items", the normal loop termination.
|
|
|
|
break;
|
|
}
|
|
|
|
dwEapType = atol (szEapType);
|
|
if (dwHidePEAPMSCHAPv2 != 0)
|
|
{
|
|
if (dwEapType == EAP_TYPE_MSCHAPv2)
|
|
{
|
|
// ignore EAP-MSCHAPv2
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Ignored non-mutual-auth DLLs like EAP
|
|
if (dwFlags & EAPOL_MUTUAL_AUTH_EAP_ONLY)
|
|
{
|
|
if (dwEapType == EAP_TYPE_MD5)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
dwErr = RegOpenKeyExA(
|
|
hkeyEap, szEapType, 0, KEY_READ, &hkeyPackage );
|
|
if (dwErr != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
// Roles Supported
|
|
|
|
dw = RAS_EAP_ROLE_AUTHENTICATEE;
|
|
GetRegDword( hkeyPackage, RAS_EAP_VALUENAME_ROLES_SUPPORTED, &dw );
|
|
|
|
if (!(dw & RAS_EAP_ROLE_AUTHENTICATEE))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (dw & RAS_EAP_ROLE_EXCLUDE_IN_EAP)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pNode = CreateEapcfgNode();
|
|
if (!pNode)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pEapcfg = (EAPCFG* )DtlGetData( pNode );
|
|
|
|
if (!pEapcfg)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// EAP type ID.
|
|
|
|
pEapcfg->dwKey = (LONG )atol( szEapType );
|
|
|
|
// Friendly display name.
|
|
|
|
psz = NULL;
|
|
dwErr = GetRegSz( hkeyPackage, REGVAL_szFriendlyName, &psz );
|
|
if (dwErr != 0)
|
|
{
|
|
break;
|
|
}
|
|
pEapcfg->pszFriendlyName = psz;
|
|
|
|
// Configuration DLL path.
|
|
|
|
psz = NULL;
|
|
dwErr = GetRegExpandSz( hkeyPackage, REGVAL_szConfigDll, &psz );
|
|
if (dwErr != 0)
|
|
{
|
|
break;
|
|
}
|
|
if (*psz)
|
|
{
|
|
pEapcfg->pszConfigDll = psz;
|
|
}
|
|
else
|
|
{
|
|
FREE ( psz );
|
|
}
|
|
|
|
// Identity DLL path.
|
|
|
|
psz = NULL;
|
|
dwErr = GetRegExpandSz( hkeyPackage, REGVAL_szIdentityDll, &psz );
|
|
if (dwErr != 0)
|
|
{
|
|
break;
|
|
}
|
|
if (*psz)
|
|
{
|
|
pEapcfg->pszIdentityDll = psz;
|
|
}
|
|
else
|
|
{
|
|
FREE ( psz );
|
|
}
|
|
|
|
// Prompt user name
|
|
|
|
dw = 1;
|
|
GetRegDword( hkeyPackage, REGVAL_fRequireUser, &dw );
|
|
if (dw)
|
|
pEapcfg->dwStdCredentialFlags |= EAPCFG_FLAG_RequireUsername;
|
|
|
|
// Prompt password
|
|
|
|
dw = 0;
|
|
GetRegDword( hkeyPackage, REGVAL_fRequirePwd, &dw );
|
|
if (dw)
|
|
pEapcfg->dwStdCredentialFlags |= EAPCFG_FLAG_RequirePassword;
|
|
|
|
// MPPE encryption keys flag.
|
|
|
|
dw = 0;
|
|
GetRegDword( hkeyPackage, REGVAL_fMppeSupported, &dw );
|
|
pEapcfg->fProvidesMppeKeys = !!dw;
|
|
|
|
// Force configuration API to run at least once.
|
|
|
|
dw = FALSE;
|
|
GetRegDword( hkeyPackage, REGVAL_fForceConfig, &dw );
|
|
pEapcfg->fForceConfig = !!dw;
|
|
|
|
// Configuration blob.
|
|
|
|
GetRegBinary(
|
|
hkeyPackage, REGVAL_pData,
|
|
&pEapcfg->pData, &pEapcfg->cbData );
|
|
|
|
// ConfigCLSID
|
|
|
|
dwErr = GetRegSz( hkeyPackage, RAS_EAP_VALUENAME_CONFIG_CLSID,
|
|
&szCLSID );
|
|
if (dwErr != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Ignore errors. Eg. EAP MD5-Challenge does not have a ConfigCLSID.
|
|
//
|
|
// hr = CLSIDFromString( szCLSID, &( pEapcfg->guidConfigCLSID ) );
|
|
|
|
FREE ( szCLSID );
|
|
|
|
// Add the completed node to the list.
|
|
|
|
DtlAddNodeLast( pList, pNode );
|
|
|
|
fOk = TRUE;
|
|
|
|
} while (FALSE);
|
|
|
|
if (!fOk && pNode)
|
|
{
|
|
DestroyEapcfgNode( pNode );
|
|
}
|
|
|
|
RegCloseKey( hkeyPackage );
|
|
}
|
|
|
|
RegCloseKey( hkeyEap );
|
|
|
|
return pList;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Allocates a sized node with space for 'lDataBytes' bytes of user data
|
|
// built-in. The node is initialized to contain the address of the
|
|
// built-in user data block (or NULL if of zero length) and the
|
|
// user-defined node identification code 'lNodeId'. The user data block
|
|
// is zeroed.
|
|
//
|
|
// Returns the address of the new node or NULL if out of memory.
|
|
//
|
|
|
|
DTLNODE*
|
|
DtlCreateSizedNode (
|
|
IN LONG lDataBytes,
|
|
IN LONG_PTR lNodeId
|
|
)
|
|
{
|
|
DTLNODE* pdtlnode = (DTLNODE *) MALLOC ( sizeof(DTLNODE) + lDataBytes );
|
|
|
|
if (pdtlnode)
|
|
{
|
|
ZeroMemory( pdtlnode, sizeof(DTLNODE) + lDataBytes );
|
|
|
|
if (lDataBytes)
|
|
pdtlnode->pData = pdtlnode + 1;
|
|
|
|
pdtlnode->lNodeId = lNodeId;
|
|
}
|
|
|
|
return pdtlnode;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Deallocates node 'pdtlnode'. It is the caller's responsibility to free
|
|
// the entry in an unsized node, if necessary.
|
|
//
|
|
|
|
VOID
|
|
DtlDestroyNode (
|
|
IN OUT DTLNODE* pdtlnode
|
|
)
|
|
{
|
|
if (pdtlnode != NULL)
|
|
{
|
|
FREE ( pdtlnode );
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Adds 'pdtlnode' at the end of list 'pdtllist'.
|
|
//
|
|
// Returns the address of the added node, i.e. 'pdtlnode'.
|
|
//
|
|
|
|
DTLNODE*
|
|
DtlAddNodeLast (
|
|
IN OUT DTLLIST* pdtllist,
|
|
IN OUT DTLNODE* pdtlnode
|
|
)
|
|
{
|
|
if (pdtllist->lNodes)
|
|
{
|
|
pdtlnode->pdtlnodePrev = pdtllist->pdtlnodeLast;
|
|
pdtllist->pdtlnodeLast->pdtlnodeNext = pdtlnode;
|
|
}
|
|
else
|
|
{
|
|
pdtlnode->pdtlnodePrev = NULL;
|
|
pdtllist->pdtlnodeFirst = pdtlnode;
|
|
}
|
|
|
|
pdtllist->pdtlnodeLast = pdtlnode;
|
|
pdtlnode->pdtlnodeNext = NULL;
|
|
|
|
++pdtllist->lNodes;
|
|
return pdtlnode;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Removes node 'pdtlnodeInList' from list 'pdtllist'.
|
|
//
|
|
// Returns the address of the removed node, i.e. 'pdtlnodeInList'.
|
|
//
|
|
|
|
DTLNODE*
|
|
DtlRemoveNode (
|
|
IN OUT DTLLIST* pdtllist,
|
|
IN OUT DTLNODE* pdtlnodeInList
|
|
)
|
|
{
|
|
if (pdtlnodeInList->pdtlnodePrev)
|
|
pdtlnodeInList->pdtlnodePrev->pdtlnodeNext = pdtlnodeInList->pdtlnodeNext;
|
|
else
|
|
pdtllist->pdtlnodeFirst = pdtlnodeInList->pdtlnodeNext;
|
|
|
|
if (pdtlnodeInList->pdtlnodeNext)
|
|
pdtlnodeInList->pdtlnodeNext->pdtlnodePrev = pdtlnodeInList->pdtlnodePrev;
|
|
else
|
|
pdtllist->pdtlnodeLast = pdtlnodeInList->pdtlnodePrev;
|
|
|
|
--pdtllist->lNodes;
|
|
return pdtlnodeInList;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Allocates a list and initializes it to empty. The list is marked with
|
|
// the user-defined list identification code 'lListId'.
|
|
//
|
|
// Returns the address of the list control block or NULL if out of memory.
|
|
//
|
|
|
|
DTLLIST*
|
|
DtlCreateList (
|
|
IN LONG lListId
|
|
)
|
|
{
|
|
DTLLIST* pdtllist = MALLOC (sizeof(DTLLIST));
|
|
|
|
if (pdtllist)
|
|
{
|
|
pdtllist->pdtlnodeFirst = NULL;
|
|
pdtllist->pdtlnodeLast = NULL;
|
|
pdtllist->lNodes = 0;
|
|
pdtllist->lListId = lListId;
|
|
}
|
|
|
|
return pdtllist;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Deallocates all nodes in list 'pdtllist' using the node deallocation
|
|
// function 'pfuncDestroyNode' if non-NULL or DtlDestroyNode otherwise.
|
|
// Won't GP-fault if passed a NULL list, e.g. if 'pdtllist', was never
|
|
// allocated.
|
|
//
|
|
|
|
VOID
|
|
DtlDestroyList (
|
|
IN OUT DTLLIST* pdtllist,
|
|
IN PDESTROYNODE pfuncDestroyNode
|
|
)
|
|
{
|
|
if (pdtllist)
|
|
{
|
|
DTLNODE* pdtlnode;
|
|
|
|
while (pdtlnode = DtlGetFirstNode( pdtllist ))
|
|
{
|
|
DtlRemoveNode( pdtllist, pdtlnode );
|
|
if (pfuncDestroyNode)
|
|
pfuncDestroyNode( pdtlnode );
|
|
else
|
|
DtlDestroyNode( pdtlnode );
|
|
}
|
|
|
|
FREE ( pdtllist );
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Set '*ppbResult' to the BINARY registry value 'pszName' under key
|
|
// 'hkey'. If the value does not exist *ppbResult' is set to NULL.
|
|
// '*PcbResult' is the number of bytes in the returned '*ppbResult'. It
|
|
// is caller's responsibility to Free the returned block.
|
|
//
|
|
|
|
VOID
|
|
GetRegBinary (
|
|
IN HKEY hkey,
|
|
IN TCHAR* pszName,
|
|
OUT BYTE** ppbResult,
|
|
OUT DWORD* pcbResult
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
DWORD dwType;
|
|
BYTE* pb;
|
|
DWORD cb;
|
|
|
|
*ppbResult = NULL;
|
|
*pcbResult = 0;
|
|
|
|
// Get result buffer size required.
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey, pszName, NULL, &dwType, NULL, &cb );
|
|
if (dwErr != NO_ERROR)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Allocate result buffer.
|
|
|
|
pb = MALLOC (cb);
|
|
if (!pb)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get the result block.
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey, pszName, NULL, &dwType, (LPBYTE )pb, &cb );
|
|
if (dwErr == NO_ERROR)
|
|
{
|
|
*ppbResult = pb;
|
|
*pcbResult = cb;
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Set '*pdwResult' to the DWORD registry value 'pszName' under key
|
|
// 'hkey'. If the value does not exist '*pdwResult' is unchanged.
|
|
//
|
|
|
|
VOID
|
|
GetRegDword (
|
|
IN HKEY hkey,
|
|
IN TCHAR* pszName,
|
|
OUT DWORD* pdwResult
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
DWORD dwType;
|
|
DWORD dwResult;
|
|
DWORD cb;
|
|
|
|
cb = sizeof(DWORD);
|
|
dwErr = RegQueryValueEx(
|
|
hkey, pszName, NULL, &dwType, (LPBYTE )&dwResult, &cb );
|
|
|
|
if ((dwErr == NO_ERROR) && dwType == REG_DWORD && cb == sizeof(DWORD))
|
|
{
|
|
*pdwResult = dwResult;
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Set '*ppszResult' to the fully expanded EXPAND_SZ registry value
|
|
// 'pszName' under key 'hkey'. If the value does not exist *ppszResult'
|
|
// is set to empty string.
|
|
//
|
|
// Returns 0 if successful or an error code. It is caller's
|
|
// responsibility to Free the returned string.
|
|
//
|
|
|
|
DWORD
|
|
GetRegExpandSz(
|
|
IN HKEY hkey,
|
|
IN TCHAR* pszName,
|
|
OUT TCHAR** ppszResult )
|
|
|
|
{
|
|
DWORD dwErr;
|
|
DWORD cb;
|
|
TCHAR* pszResult;
|
|
|
|
// Get the unexpanded result string.
|
|
//
|
|
dwErr = GetRegSz( hkey, pszName, ppszResult );
|
|
if (dwErr != 0)
|
|
{
|
|
return dwErr;
|
|
}
|
|
|
|
// Find out how big the expanded string will be.
|
|
//
|
|
cb = ExpandEnvironmentStrings( *ppszResult, NULL, 0 );
|
|
if (cb == 0)
|
|
{
|
|
dwErr = GetLastError();
|
|
FREE ( *ppszResult );
|
|
return dwErr;
|
|
}
|
|
|
|
// Allocate a buffer for the expanded string.
|
|
//
|
|
pszResult = MALLOC ((cb + 1) * sizeof(TCHAR));
|
|
if (!pszResult)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// Expand the environmant variables in the string, storing the result in
|
|
// the allocated buffer.
|
|
//
|
|
cb = ExpandEnvironmentStrings( *ppszResult, pszResult, cb + 1 );
|
|
if (cb == 0)
|
|
{
|
|
dwErr = GetLastError();
|
|
if (*ppszResult != NULL)
|
|
{
|
|
FREE ( *ppszResult );
|
|
}
|
|
if (pszResult != NULL)
|
|
{
|
|
FREE ( pszResult );
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
FREE ( *ppszResult );
|
|
*ppszResult = pszResult;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Set '*ppszResult' to the SZ registry value 'pszName' under key 'hkey'.
|
|
// If the value does not exist *ppszResult' is set to empty string.
|
|
//
|
|
// Returns 0 if successful or an error code. It is caller's
|
|
// responsibility to Free the returned string.
|
|
//
|
|
|
|
DWORD
|
|
GetRegSz(
|
|
IN HKEY hkey,
|
|
IN TCHAR* pszName,
|
|
OUT TCHAR** ppszResult )
|
|
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
DWORD dwType;
|
|
DWORD cb;
|
|
TCHAR* pszResult;
|
|
|
|
// Get result buffer size required.
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey, pszName, NULL, &dwType, NULL, &cb );
|
|
if (dwErr != NO_ERROR)
|
|
{
|
|
cb = sizeof(TCHAR);
|
|
}
|
|
|
|
// Allocate result buffer.
|
|
|
|
pszResult = MALLOC (cb * sizeof(TCHAR));
|
|
if (!pszResult)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
*pszResult = TEXT('\0');
|
|
*ppszResult = pszResult;
|
|
|
|
// Get the result string. It's not an error if we can't get it.
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey, pszName, NULL, &dwType, (LPBYTE )pszResult, &cb );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
//
|
|
// WZCGetEapUserInfo
|
|
//
|
|
// 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:
|
|
// pwszGUID - pointer to GUID string for the interface
|
|
// dwEapTypeId - EAP type for which user data is to be stored
|
|
// dwSizeOfSSID - Size of Special identifier if any for the EAP user blob
|
|
// pbSSID - 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
|
|
WZCGetEapUserInfo (
|
|
IN WCHAR *pwszGUID,
|
|
IN DWORD dwEapTypeId,
|
|
IN DWORD dwSizeOfSSID,
|
|
IN BYTE *pbSSID,
|
|
IN OUT PBYTE pbUserInfo,
|
|
IN OUT DWORD *pdwInfoSize
|
|
)
|
|
{
|
|
HKEY hkey = NULL;
|
|
HKEY hkey1 = NULL;
|
|
HKEY hkey2 = NULL;
|
|
DWORD dwNumValues = 0, dwMaxValueNameLen = 0, dwTempValueNameLen = 0, dwMaxValueLen = 0;
|
|
DWORD dwIndex = 0, dwMaxValueName = 0;
|
|
WCHAR *pwszValueName = NULL;
|
|
BYTE *pbValueBuf = NULL;
|
|
DWORD dwValueData = 0;
|
|
BYTE *pbDefaultValue = NULL;
|
|
DWORD dwDefaultValueLen = 0;
|
|
BYTE *pbEapBlob = NULL;
|
|
DWORD dwEapBlob = 0;
|
|
BYTE *pbAuthData = NULL;
|
|
DWORD dwAuthData = 0;
|
|
BOOLEAN fFoundValue = FALSE;
|
|
EAPOL_INTF_PARAMS *pRegParams = NULL;
|
|
LONG lError = ERROR_SUCCESS;
|
|
DWORD dwRetCode = ERROR_SUCCESS;
|
|
|
|
do
|
|
{
|
|
// Validate input params
|
|
|
|
if (pwszGUID == NULL)
|
|
{
|
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
|
break;
|
|
}
|
|
if (dwEapTypeId == 0)
|
|
{
|
|
dwRetCode = ERROR_CAN_NOT_COMPLETE;
|
|
break;
|
|
}
|
|
|
|
// Get handle to HKCU\Software\...\UserEapInfo
|
|
|
|
if ((lError = RegOpenKeyEx (
|
|
HKEY_CURRENT_USER,
|
|
cwszEapKeyEapolUser,
|
|
0,
|
|
KEY_READ,
|
|
&hkey1
|
|
)) != ERROR_SUCCESS)
|
|
{
|
|
dwRetCode = (DWORD)lError;
|
|
break;
|
|
}
|
|
|
|
// Get handle to HKCU\Software\...\UserEapInfo\<GUID>
|
|
|
|
if ((lError = RegOpenKeyEx (
|
|
hkey1,
|
|
pwszGUID,
|
|
0,
|
|
KEY_READ,
|
|
&hkey2
|
|
)) != ERROR_SUCCESS)
|
|
{
|
|
dwRetCode = (DWORD)lError;
|
|
break;
|
|
}
|
|
|
|
// Set correct SSID
|
|
if (dwSizeOfSSID == 0)
|
|
{
|
|
pbSSID = g_bDefaultSSID;
|
|
dwSizeOfSSID = MAX_SSID_LEN;
|
|
}
|
|
|
|
if ((lError = RegQueryInfoKey (
|
|
hkey2,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwNumValues,
|
|
&dwMaxValueNameLen,
|
|
&dwMaxValueLen,
|
|
NULL,
|
|
NULL
|
|
)) != NO_ERROR)
|
|
{
|
|
dwRetCode = (DWORD)lError;
|
|
break;
|
|
}
|
|
|
|
if ((pwszValueName = MALLOC ((dwMaxValueNameLen + 1) * sizeof (WCHAR))) == NULL)
|
|
{
|
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
dwMaxValueNameLen++;
|
|
if ((pbValueBuf = MALLOC (dwMaxValueLen)) == NULL)
|
|
{
|
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
for (dwIndex = 0; dwIndex < dwNumValues; dwIndex++)
|
|
{
|
|
dwValueData = dwMaxValueLen;
|
|
dwTempValueNameLen = dwMaxValueNameLen;
|
|
if ((lError = RegEnumValue (
|
|
hkey2,
|
|
dwIndex,
|
|
pwszValueName,
|
|
&dwTempValueNameLen,
|
|
NULL,
|
|
NULL,
|
|
pbValueBuf,
|
|
&dwValueData
|
|
)) != ERROR_SUCCESS)
|
|
{
|
|
if (lError != ERROR_MORE_DATA)
|
|
{
|
|
break;
|
|
}
|
|
lError = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (dwValueData < sizeof (EAPOL_INTF_PARAMS))
|
|
{
|
|
lError = ERROR_INVALID_DATA;
|
|
break;
|
|
}
|
|
pRegParams = (EAPOL_INTF_PARAMS *)pbValueBuf;
|
|
|
|
if (((DWORD)_wtol(pwszValueName)) > dwMaxValueName)
|
|
{
|
|
dwMaxValueName = _wtol (pwszValueName);
|
|
}
|
|
|
|
if (!memcmp (pRegParams->bSSID, pbSSID, dwSizeOfSSID))
|
|
{
|
|
fFoundValue = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if ((lError != ERROR_SUCCESS) && (lError != ERROR_NO_MORE_ITEMS))
|
|
{
|
|
dwRetCode = (DWORD)lError;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
lError = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (!fFoundValue)
|
|
{
|
|
pbEapBlob = NULL;
|
|
dwEapBlob = 0;
|
|
}
|
|
else
|
|
{
|
|
// Use pbValueBuf & dwValueData
|
|
pbEapBlob = pbValueBuf;
|
|
dwEapBlob = dwValueData;
|
|
}
|
|
|
|
// If default blob is not present, exit
|
|
if ((pbEapBlob == NULL) && (dwEapBlob == 0))
|
|
{
|
|
*pdwInfoSize = 0;
|
|
break;
|
|
}
|
|
|
|
if ((dwRetCode = WZCGetEapData (
|
|
dwEapTypeId,
|
|
dwEapBlob,
|
|
pbEapBlob,
|
|
sizeof (EAPOL_INTF_PARAMS),
|
|
&dwAuthData,
|
|
&pbAuthData
|
|
)) != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Return the data if sufficient space allocated
|
|
|
|
if ((pbUserInfo != NULL) && (*pdwInfoSize >= dwAuthData))
|
|
{
|
|
memcpy (pbUserInfo, pbAuthData, dwAuthData);
|
|
}
|
|
else
|
|
{
|
|
dwRetCode = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
*pdwInfoSize = dwAuthData;
|
|
|
|
} while (FALSE);
|
|
|
|
if (hkey != NULL)
|
|
{
|
|
RegCloseKey (hkey);
|
|
}
|
|
if (hkey1 != NULL)
|
|
{
|
|
RegCloseKey (hkey1);
|
|
}
|
|
if (hkey2 != NULL)
|
|
{
|
|
RegCloseKey (hkey2);
|
|
}
|
|
if (pbValueBuf != NULL)
|
|
{
|
|
FREE (pbValueBuf);
|
|
}
|
|
if (pbDefaultValue != NULL)
|
|
{
|
|
FREE (pbDefaultValue);
|
|
}
|
|
if (pwszValueName != NULL)
|
|
{
|
|
FREE (pwszValueName);
|
|
}
|
|
|
|
return dwRetCode;
|
|
}
|
|
|
|
|
|
//
|
|
// WZCGetEapData
|
|
//
|
|
// Description:
|
|
//
|
|
// Function to extract Eap Data out of a blob containing many EAP data
|
|
//
|
|
// Arguments:
|
|
// dwEapType -
|
|
// dwSizeOfIn -
|
|
// pbBufferIn -
|
|
// dwOffset -
|
|
// pdwSizeOfOut -
|
|
// ppbBufferOut -
|
|
//
|
|
// Return values:
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
WZCGetEapData (
|
|
IN DWORD dwEapType,
|
|
IN DWORD dwSizeOfIn,
|
|
IN BYTE *pbBufferIn,
|
|
IN DWORD dwOffset,
|
|
IN DWORD *pdwSizeOfOut,
|
|
IN PBYTE *ppbBufferOut
|
|
)
|
|
{
|
|
DWORD dwRetCode = NO_ERROR;
|
|
DWORD cbOffset = 0;
|
|
EAPOL_AUTH_DATA *pCustomData = NULL;
|
|
|
|
do
|
|
{
|
|
*pdwSizeOfOut = 0;
|
|
*ppbBufferOut = NULL;
|
|
|
|
if (pbBufferIn == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Align to start of EAP blob
|
|
cbOffset = dwOffset;
|
|
|
|
while (cbOffset < dwSizeOfIn)
|
|
{
|
|
pCustomData = (EAPOL_AUTH_DATA *)
|
|
((PBYTE) pbBufferIn + cbOffset);
|
|
|
|
if (pCustomData->dwEapType == dwEapType)
|
|
{
|
|
break;
|
|
}
|
|
cbOffset += sizeof (EAPOL_AUTH_DATA) + pCustomData->dwSize;
|
|
}
|
|
|
|
if (cbOffset < dwSizeOfIn)
|
|
{
|
|
*pdwSizeOfOut = pCustomData->dwSize;
|
|
*ppbBufferOut = pCustomData->bData;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
return dwRetCode;
|
|
}
|
|
|
|
|
|
//
|
|
// WZCEapolFreeState
|
|
//
|
|
// Description:
|
|
//
|
|
// Function to free EAPOL interface state information on the client side
|
|
// obtained via RPC query
|
|
//
|
|
// Arguments:
|
|
// pIntfState -
|
|
//
|
|
// Return values:
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
WZCEapolFreeState (
|
|
IN EAPOL_INTF_STATE *pIntfState
|
|
)
|
|
{
|
|
DWORD dwRetCode = NO_ERROR;
|
|
|
|
do
|
|
{
|
|
RpcFree(pIntfState->pwszLocalMACAddr);
|
|
RpcFree(pIntfState->pwszRemoteMACAddr);
|
|
RpcFree(pIntfState->pszEapIdentity);
|
|
}
|
|
while (FALSE);
|
|
|
|
return dwRetCode;
|
|
}
|