windows-nt/Source/XPSP1/NT/net/layer2svc/zeroconf/server/storage.c
2020-09-26 16:20:57 +08:00

1045 lines
35 KiB
C

#include <precomp.h>
#include "tracing.h"
#include "utils.h"
#include "intflist.h"
#include "hash.h"
#include "storage.h"
#include "rpcsrv.h"
#include "wzcsvc.h"
//-----------------------------------------------------------
// Loads per interface configuration parameters to the persistent
// storage.
// Parameters:
// hkRoot
// [in] Opened registry key to the "...WZCSVC\Parameters" location
// pIntf
// [in] Interface context to load from the registry
// Returned value:
// Win32 error code
DWORD
StoLoadIntfConfig(
HKEY hkRoot,
PINTF_CONTEXT pIntfContext)
{
DWORD dwErr = ERROR_SUCCESS;
HKEY hkIntf = NULL;
LPWSTR pKeyName = NULL;
UINT nLength;
UINT nType;
DWORD dwData;
DWORD dwVersion;
UINT nEntries;
RAW_DATA rdBuffer = {0, NULL};
DWORD dwGuidLen = 0;
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoLoadIntfConfig(%S)",
(pIntfContext->wszGuid == NULL)? L"Global" : pIntfContext->wszGuid));
if (pIntfContext->wszGuid != NULL)
dwGuidLen = wcslen(pIntfContext->wszGuid) + 1;
if (hkRoot == NULL)
{
// if no root has been provided allocate space for the absolute path to WZC params,
// the relative path to the interfaces location, the guid plus 2 '\' and one null terminator
pKeyName = MemCAlloc((
wcslen(WZCREGK_ABS_PARAMS) +
dwGuidLen +
wcslen(WZCREGK_REL_INTF) +
2)*sizeof(WCHAR));
if (pKeyName == 0)
{
dwErr = GetLastError();
goto exit;
}
if (dwGuidLen != 0)
wsprintf(pKeyName,L"%s\\%s\\%s", WZCREGK_ABS_PARAMS, WZCREGK_REL_INTF, pIntfContext->wszGuid);
else
wsprintf(pKeyName,L"%s\\%s", WZCREGK_ABS_PARAMS, WZCREGK_REL_INTF);
hkRoot = HKEY_LOCAL_MACHINE;
}
else
{
// if a root has been provided, allocate space just for the "Interfaces\{guid}"
// add 2 wchars: one for the '\' after 'Interfaces' and one for the null terminator
pKeyName = MemCAlloc((wcslen(WZCREGK_REL_INTF) + dwGuidLen + 1)*sizeof(WCHAR));
if (pKeyName == NULL)
{
dwErr = GetLastError();
goto exit;
}
// create the local key name
if (dwGuidLen != 0)
wsprintf(pKeyName,L"%s\\%s", WZCREGK_REL_INTF, pIntfContext->wszGuid);
else
wsprintf(pKeyName,L"%s", WZCREGK_REL_INTF);
}
// open the interface's key first
dwErr = RegOpenKeyEx(
hkRoot,
pKeyName,
0,
KEY_READ,
&hkIntf);
// break out if not successful
if (dwErr != ERROR_SUCCESS)
{
// if the key is not there, no harm, go on with the defaults
if (dwErr == ERROR_FILE_NOT_FOUND)
dwErr = ERROR_SUCCESS;
goto exit;
}
// get first the whole number of values in this key and the size of the largest data
dwErr = RegQueryInfoKey(
hkIntf, // handle to key
NULL, // class buffer
NULL, // size of class buffer
NULL, // reserved
NULL, // number of subkeys
NULL, // longest subkey name
NULL, // longest class string
&nEntries, // number of value entries
NULL, // longest value name
&rdBuffer.dwDataLen, // longest value data
NULL, // descriptor length
NULL); // last write time
// this call should better be not failing
if (dwErr != ERROR_SUCCESS)
goto exit;
// if there are no keys at all, exit now.
if (rdBuffer.dwDataLen == 0)
goto exit;
// prepare the receiving buffer for the size of the largest data
// this will be used when reading in the active settings and each
// of the static configurations
rdBuffer.pData = MemCAlloc(rdBuffer.dwDataLen);
if (rdBuffer.pData == NULL)
{
dwErr = GetLastError();
goto exit;
}
// load the registry layout version information
// don't worry about the return code. In case of any error,
// we'll assume we deal with the latest registry layout
nLength = sizeof(DWORD);
dwVersion = REG_LAYOUT_VERSION;
dwErr = RegQueryValueEx(
hkIntf,
WZCREGV_VERSION,
0,
&nType,
(LPBYTE)&dwVersion,
&nLength);
// load the interface's control flags
nLength = sizeof(DWORD);
dwData = 0;
dwErr = RegQueryValueEx(
hkIntf,
WZCREGV_CTLFLAGS,
0,
&nType,
(LPBYTE)&dwData,
&nLength);
// if this entry is not there, no harm, rely on defaults
// break out only in case of any other error
if (dwErr != ERROR_SUCCESS && dwErr != ERROR_FILE_NOT_FOUND)
goto exit;
// copy the control flags to the INTF_CONTEXT only in the case the registry entry
// has the REG_DWORD type and the right length
if (dwErr == ERROR_SUCCESS &&
nType == REG_DWORD &&
nLength == sizeof(REG_DWORD))
{
pIntfContext->dwCtlFlags = dwData & INTFCTL_PUBLIC_MASK;
}
// load the last active settings
//
// NOTE: loading the whole set of parameters from below (excluding here the static list)
// could be useless since these params should come directly from querying the driver. However
// we load them here in the attemt to restore a previously saved state - at some point this
// information could be useful in the configuration selection logic.
//
ZeroMemory(&pIntfContext->wzcCurrent, sizeof(WZC_WLAN_CONFIG));
pIntfContext->wzcCurrent.Length = sizeof(WZC_WLAN_CONFIG);
dwErr = StoLoadWZCConfig(
hkIntf,
NULL, // not passing a GUID here means don't mess with 802.1X setting!
dwVersion,
WZCREGV_INTFSETTINGS,
&pIntfContext->wzcCurrent,
&rdBuffer);
// if this entry is not there, no harm, rely on defaults
// break out in case of any other error
if (dwErr != ERROR_SUCCESS && dwErr != ERROR_FILE_NOT_FOUND)
goto exit;
// load the static configurations for this interface
dwErr = StoLoadStaticConfigs(
hkIntf,
nEntries,
pIntfContext,
dwVersion,
&rdBuffer);
DbgAssert((dwErr == ERROR_SUCCESS, "Failed to load the static configurations"));
exit:
if (hkIntf != NULL)
RegCloseKey(hkIntf);
MemFree(pKeyName);
MemFree(rdBuffer.pData);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoLoadIntfConfig]=%d", dwErr));
return dwErr;
}
//-----------------------------------------------------------
// Loads the list of the static configurations from the registry
// Parameters:
// hkRoot
// [in] Opened registry key to the "...WZCSVC\Parameters\Interfaces\{guid}" location
// nEntries
// [in] Number of registry entries in the above reg key
// pIntf
// [in] Interface context to load the static list into
// dwRegLayoutVer
// [in] the version of the registry layout
// prdBuffer
// [in] assumed large enough for getting any static config
// Returned value:
// Win32 error code
DWORD
StoLoadStaticConfigs(
HKEY hkIntf,
UINT nEntries,
PINTF_CONTEXT pIntfContext,
DWORD dwRegLayoutVer,
PRAW_DATA prdBuffer)
{
DWORD dwErr = ERROR_SUCCESS;
UINT nPrefrd, nIdx;
WCHAR wszStConfigName[sizeof(WZCREGV_STSETTINGS)/sizeof(WCHAR)];
LPWSTR pwszStConfigNum;
PWZC_WLAN_CONFIG pwzcPArray = NULL;
UINT nStructSize = (dwRegLayoutVer == REG_LAYOUT_VERSION) ?
sizeof(WZC_WLAN_CONFIG) :
FIELD_OFFSET(WZC_WLAN_CONFIG, rdUserData);
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoLoadStaticConfigs"));
// we need to scan all the entries named "Static#0001, Static#0002, etc". We could assume
// they are numbered sequentially, but if we want to be smart we can't rely on this assumption.
// There could be a user intervention there (i.e deleting by hand some of the configs directly
// from the registry hence breaking the sequence).
// So, what we'll do is:
// 1. allocate a buffer large enough to hold so many static configs.
// 2. iterate through all the values - if a value is Static#** and has the right length, type,
// and value, copy it in the buffer and keep a count of them.
// 3. copy the exact number of static configs to the INTF_CONTEXT allocating as much memory
// as needed.
// get the estimated memory for all the static entries.
pwzcPArray = (PWZC_WLAN_CONFIG) MemCAlloc(nEntries * sizeof(WZC_WLAN_CONFIG));
if (pwzcPArray == NULL)
{
dwErr = GetLastError();
goto exit;
}
// build the prefix for the static configuration's name
wcscpy(wszStConfigName, WZCREGV_STSETTINGS);
pwszStConfigNum = wcschr(wszStConfigName, REG_STSET_DELIM);
// iterate through the whole set of entries in this key
for (nIdx = 0, nPrefrd = 0;
nIdx < nEntries && nPrefrd < nEntries;
nIdx++)
{
// complete the configuration's name
wsprintf(pwszStConfigNum, L"%04x", nIdx);
dwErr = StoLoadWZCConfig(
hkIntf,
pIntfContext->wszGuid,
dwRegLayoutVer,
wszStConfigName,
&(pwzcPArray[nPrefrd]),
prdBuffer);
if (dwErr == ERROR_SUCCESS)
nPrefrd++;
}
DbgPrint((TRC_STORAGE,"Uploading %d static configurations", nPrefrd));
// no matter what error we might have had till now, we can safely reset it.
dwErr = ERROR_SUCCESS;
// here, pwzcPArray has nPrefrd static configurations, in the correct order
if (pIntfContext->pwzcPList != NULL)
MemFree(pIntfContext->pwzcPList);
// if there is anything to upload into the INTF_CONTEXT, do it now
if (nPrefrd > 0)
{
pIntfContext->pwzcPList = (PWZC_802_11_CONFIG_LIST)
MemCAlloc(sizeof(WZC_802_11_CONFIG_LIST) + (nPrefrd-1)*sizeof(WZC_WLAN_CONFIG));
if (pIntfContext->pwzcPList == NULL)
{
dwErr = GetLastError();
goto exit;
}
pIntfContext->pwzcPList->NumberOfItems = nPrefrd;
pIntfContext->pwzcPList->Index = nPrefrd;
memcpy(&(pIntfContext->pwzcPList->Config), pwzcPArray, nPrefrd*sizeof(WZC_WLAN_CONFIG));
}
exit:
if (pwzcPArray != NULL)
MemFree(pwzcPArray);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoLoadStaticConfigs]=%d", dwErr));
return dwErr;
}
//-----------------------------------------------------------
// Saves all the configuration parameters to the persistant
// storage (registry in our case).
// Uses the global external g_lstIntfHashes.
// Returned value:
// Win32 error code
DWORD
StoSaveConfig()
{
DWORD dwErr = ERROR_SUCCESS;
HKEY hkRoot = NULL;
PLIST_ENTRY pEntry;
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoSaveConfig"));
// open the root key first
dwErr = RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
WZCREGK_ABS_PARAMS,
0,
NULL,
0,
KEY_WRITE,
NULL,
&hkRoot,
NULL);
// failure at this point breaks the function
if (dwErr != ERROR_SUCCESS)
goto exit;
if (g_lstIntfHashes.bValid)
{
// lock the hashes since we're iterating through all
// the interfaces contexts
EnterCriticalSection(&g_lstIntfHashes.csMutex);
for (pEntry = g_lstIntfHashes.lstIntfs.Flink;
pEntry != &g_lstIntfHashes.lstIntfs;
pEntry = pEntry->Flink)
{
PINTF_CONTEXT pIntfContext;
pIntfContext = CONTAINING_RECORD(pEntry, INTF_CONTEXT, Link);
// save per interface configuration settings
dwErr = StoSaveIntfConfig(hkRoot, pIntfContext);
if (dwErr != ERROR_SUCCESS)
{
// some event logging should be added here in the future
DbgAssert((FALSE, "Couldn't save interface configuration. Ignore and go on!"));
dwErr = ERROR_SUCCESS;
}
}
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
}
if (g_wzcInternalCtxt.bValid)
{
//Save users preferences
EnterCriticalSection(&g_wzcInternalCtxt.csContext);
dwErr = StoSaveWZCContext(hkRoot, &g_wzcInternalCtxt.wzcContext);
DbgAssert((dwErr == ERROR_SUCCESS, "Couldn't save service context. Ignore and go on!"));
// save the global interface template
dwErr = StoSaveIntfConfig(NULL, g_wzcInternalCtxt.pIntfTemplate);
DbgAssert((dwErr == ERROR_SUCCESS, "Couldn't save the global interface template. Ignore and go on!"));
dwErr = ERROR_SUCCESS;
LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
}
exit:
if (hkRoot != NULL)
RegCloseKey(hkRoot);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoSaveConfig]=%d", dwErr));
return dwErr;
}
//-----------------------------------------------------------
// Saves per interface configuration parameters to the persistant
// storage.
// Parameters:
// hkRoot
// [in] Opened registry key to the "...WZCSVC\Parameters" location
// pIntf
// [in] Interface context to save to the registry
// Returned value:
// Win32 error code
DWORD
StoSaveIntfConfig(
HKEY hkRoot,
PINTF_CONTEXT pIntfContext)
{
DWORD dwErr = ERROR_SUCCESS;
HKEY hkIntf = NULL;
LPWSTR pKeyName = NULL;
DWORD dwLayoutVer = REG_LAYOUT_VERSION;
DWORD dwCtlFlags;
RAW_DATA rdBuffer = {0, NULL};
DWORD dwGuidLen = 0;
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoSaveIntfConfig(%S)",
(pIntfContext->wszGuid == NULL) ? L"Global" : pIntfContext->wszGuid));
if (pIntfContext == NULL)
{
dwErr = ERROR_INVALID_PARAMETER;
goto exit;
}
if (pIntfContext->wszGuid != NULL)
dwGuidLen = wcslen(pIntfContext->wszGuid) + 1;
if (hkRoot == NULL)
{
// if no root has been provided allocate space for the absolute path to WZC params,
// the relative path to the interfaces location, the guid plus 2 '\' and one null terminator
pKeyName = MemCAlloc((
wcslen(WZCREGK_ABS_PARAMS) +
dwGuidLen +
wcslen(WZCREGK_REL_INTF) +
2)*sizeof(WCHAR));
if (pKeyName == 0)
{
dwErr = GetLastError();
goto exit;
}
if (dwGuidLen != 0)
wsprintf(pKeyName,L"%s\\%s\\%s", WZCREGK_ABS_PARAMS, WZCREGK_REL_INTF, pIntfContext->wszGuid);
else
wsprintf(pKeyName,L"%s\\%s", WZCREGK_ABS_PARAMS, WZCREGK_REL_INTF);
hkRoot = HKEY_LOCAL_MACHINE;
}
else
{
// if a root has been provided, allocate space just for the "Interfaces\{guid}"
// add 2 wchars: one for the '\' after 'Interfaces' and one for the null terminator
pKeyName = MemCAlloc((dwGuidLen + wcslen(WZCREGK_REL_INTF) + 1)*sizeof(WCHAR));
if (pKeyName == NULL)
{
dwErr = GetLastError();
goto exit;
}
// create the local key name
if (dwGuidLen != 0)
wsprintf(pKeyName,L"%s\\%s", WZCREGK_REL_INTF, pIntfContext->wszGuid);
else
wsprintf(pKeyName,L"%s", WZCREGK_REL_INTF);
}
// open the interface's key first
dwErr = RegCreateKeyExW(
hkRoot,
pKeyName,
0,
NULL,
0,
KEY_QUERY_VALUE | KEY_WRITE,
NULL,
&hkIntf,
NULL);
// failure at this point breaks the function
if (dwErr != ERROR_SUCCESS)
goto exit;
// set the registry layout version value
dwErr = RegSetValueEx(
hkIntf,
WZCREGV_VERSION,
0,
REG_DWORD,
(LPBYTE)&dwLayoutVer,
sizeof(DWORD));
DbgAssert((dwErr == ERROR_SUCCESS, "Can't write %S=%d to the registry", WZCREGV_VERSION, dwLayoutVer));
// set the interface's control flags only if they are not volatile
dwCtlFlags = pIntfContext->dwCtlFlags;
if (!(dwCtlFlags & INTFCTL_VOLATILE))
{
dwCtlFlags &= ~INTFCTL_OIDSSUPP;
dwErr = RegSetValueEx(
hkIntf,
WZCREGV_CTLFLAGS,
0,
REG_DWORD,
(LPBYTE)&dwCtlFlags,
sizeof(DWORD));
DbgAssert((dwErr == ERROR_SUCCESS, "Can't write %S=0x%08x to the registry", WZCREGV_CTLFLAGS, pIntfContext->dwCtlFlags));
}
// we're done here, write the current WZC configuration to the registry
dwErr = StoSaveWZCConfig(
hkIntf,
WZCREGV_INTFSETTINGS,
&pIntfContext->wzcCurrent,
&rdBuffer);
DbgAssert((dwErr == ERROR_SUCCESS, "Can't save active settings"));
// update the list of static configurations
dwErr = StoUpdateStaticConfigs(
hkIntf,
pIntfContext,
&rdBuffer);
DbgAssert((dwErr == ERROR_SUCCESS, "Can't update the list of static configurations"));
exit:
if (hkIntf != NULL)
RegCloseKey(hkIntf);
MemFree(pKeyName);
MemFree(rdBuffer.pData);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoSaveIntfConfig]=%d", dwErr));
return dwErr;
}
//-----------------------------------------------------------
// Updates the list of static configurations for the given interface in the
// persistant storage. The new list is saved, whatever configuration was removed
// is taken out of the persistant storage.
// Parameters:
// hkRoot
// [in] Opened registry key to the "...WZCSVC\Parameters\Interfaces\{guid}" location
// pIntf
// [in] Interface context to take the static list from
// prdBuffer
// [in/out] buffer to be used for preparing the registry blobs
// Returned value:
// Win32 error code
DWORD
StoUpdateStaticConfigs(
HKEY hkIntf,
PINTF_CONTEXT pIntfContext,
PRAW_DATA prdBuffer)
{
DWORD dwErr = ERROR_SUCCESS;
DWORD dwLocalErr = ERROR_SUCCESS;
UINT nEntries, nIdx;
WCHAR wszStConfigName[sizeof(WZCREGV_STSETTINGS)/sizeof(WCHAR)];
LPWSTR pwszStConfigNum;
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoUpdateStaticConfigs"));
// get the initial number of values in this registry key
dwErr = RegQueryInfoKey(
hkIntf, // handle to key
NULL, // class buffer
NULL, // size of class buffer
NULL, // reserved
NULL, // number of subkeys
NULL, // longest subkey name
NULL, // longest class string
&nEntries, // number of value entries
NULL, // longest value name
NULL, // longest value data
NULL, // descriptor length
NULL); // last write time
if (dwErr != ERROR_SUCCESS)
goto exit;
// build the prefix for the static configuration's name
wcscpy(wszStConfigName, WZCREGV_STSETTINGS);
pwszStConfigNum = wcschr(wszStConfigName, REG_STSET_DELIM);
nIdx = 0;
if (pIntfContext->pwzcPList != NULL)
{
UINT i;
for (i = 0;
i < pIntfContext->pwzcPList->NumberOfItems && i < REG_STSET_MAX;
i++)
{
if (pIntfContext->pwzcPList->Config[i].dwCtlFlags & WZCCTL_VOLATILE)
continue;
// complete the configuration's name
wsprintf(pwszStConfigNum, L"%04x", nIdx++);
// save the configuration to the registry
dwLocalErr = StoSaveWZCConfig(
hkIntf,
wszStConfigName,
&(pIntfContext->pwzcPList->Config[i]),
prdBuffer);
DbgAssert((dwLocalErr == ERROR_SUCCESS,
"Failed to save static configuration 0x%x. err=%d",
i, dwLocalErr));
if (dwErr == ERROR_SUCCESS && dwLocalErr != ERROR_SUCCESS)
dwErr = dwLocalErr;
}
}
// delete now whatever remaining static
// configurations might still be in the registry
do
{
// complete the configuration's name
wsprintf(pwszStConfigNum, L"%04x", nIdx);
// and attempt to delete it - at some point
// we should get back ERROR_FILE_NOT_FOUND
dwLocalErr = RegDeleteValue(
hkIntf,
wszStConfigName);
nIdx++;
} while (nIdx < nEntries);
exit:
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoUpdateStaticConfigs]=%d", dwErr));
return dwErr;
}
// externalities from 802.1X
DWORD
ElSetInterfaceParams (
IN WCHAR *pwszGUID,
IN EAPOL_INTF_PARAMS *pIntfParams
);
DWORD
ElGetInterfaceParams (
IN WCHAR *pwszGUID,
IN OUT EAPOL_INTF_PARAMS *pIntfParams
);
//-----------------------------------------------------------
// Loads from the registry a WZC Configuration, un-protects the WEP key field
// and stores the result in the output param pWzcCfg.
// Parameters:
// hkCfg
// [in] Opened registry key to load the WZC configuration from
// dwRegLayoutVer,
// [in] registry layout version
// wszCfgName
// [in] registry entry name for the WZC configuration
// pWzcCfg
// [out] pointer to a WZC_WLAN_CONFIG object that receives the registry data
// prdBuffer
// [in] allocated buffer, assumed large enough for getting the registry data!
DWORD
StoLoadWZCConfig(
HKEY hkCfg,
LPWSTR wszGuid,
DWORD dwRegLayoutVer,
LPWSTR wszCfgName,
PWZC_WLAN_CONFIG pWzcCfg,
PRAW_DATA prdBuffer)
{
DWORD dwErr = ERROR_SUCCESS;
UINT nType, nLength;
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoLoadWZCConfig(\"%S\")", wszCfgName));
DbgAssert((prdBuffer != NULL, "No buffer provided for loading the registry blob!"));
// zero out the buffer and get the value from the registry
ZeroMemory(prdBuffer->pData, prdBuffer->dwDataLen);
nLength = prdBuffer->dwDataLen;
dwErr = RegQueryValueEx(
hkCfg,
wszCfgName,
0,
&nType,
prdBuffer->pData,
&nLength);
if (dwErr == ERROR_SUCCESS)
{
switch(dwRegLayoutVer)
{
case REG_LAYOUT_LEGACY_1:
// first legacy code (WinXP Beta2)
if (nType == REG_BINARY && nLength == FIELD_OFFSET(WZC_WLAN_CONFIG, rdUserData))
{
memcpy(pWzcCfg, prdBuffer->pData, nLength);
if (pWzcCfg->Length == nLength)
{
pWzcCfg->Length = sizeof(WZC_WLAN_CONFIG);
pWzcCfg->AuthenticationMode = NWB_GET_AUTHMODE(pWzcCfg);
pWzcCfg->Reserved[0] = pWzcCfg->Reserved[1] = 0;
}
else
dwErr = ERROR_INVALID_DATA;
}
else
dwErr = ERROR_INVALID_DATA;
break;
case REG_LAYOUT_LEGACY_2:
// second legacy code (WinXP 2473)
if (nType == REG_BINARY && nLength == sizeof(WZC_WLAN_CONFIG))
{
memcpy(pWzcCfg, prdBuffer->pData, nLength);
if (pWzcCfg->Length != nLength)
dwErr = ERROR_INVALID_DATA;
}
break;
case REG_LAYOUT_LEGACY_3:
case REG_LAYOUT_VERSION:
// revert the logic: assume failure (ERROR_INVALID_DATA) and
// explictly set success if the case is
dwErr = ERROR_INVALID_DATA;
if (nType == REG_BINARY && nLength > sizeof(WZC_WLAN_CONFIG))
{
memcpy(pWzcCfg, prdBuffer->pData, sizeof(WZC_WLAN_CONFIG));
if (pWzcCfg->Length == sizeof(WZC_WLAN_CONFIG))
{
DATA_BLOB blobIn, blobOut;
blobIn.cbData = nLength - sizeof(WZC_WLAN_CONFIG);
blobIn.pbData = prdBuffer->pData + sizeof(WZC_WLAN_CONFIG);
blobOut.cbData = 0;
blobOut.pbData = NULL;
if (CryptUnprotectData(
&blobIn,
NULL,
NULL,
NULL,
NULL,
0,
&blobOut) &&
blobOut.cbData == WZCCTL_MAX_WEPK_MATERIAL)
{
memcpy(pWzcCfg->KeyMaterial, blobOut.pbData, blobOut.cbData);
// now this is success
dwErr = ERROR_SUCCESS;
}
if (blobOut.pbData != NULL)
{
ZeroMemory(blobOut.pbData, blobOut.cbData);
LocalFree(blobOut.pbData);
}
}
}
// for now don't read anything - rely on defaults;
break;
default:
dwErr = ERROR_BAD_FORMAT;
}
}
// if everything went up fine and this is an infrastructure network and
// we're in some legacy registry layout.. make sure to disable 802.1X in
// the following cases:
if (dwErr == ERROR_SUCCESS &&
dwRegLayoutVer <= REG_LAYOUT_LEGACY_3 &&
pWzcCfg->InfrastructureMode != Ndis802_11IBSS &&
wszGuid != NULL)
{
BOOL bDisableOneX = FALSE;
// the Infrastructure network being loaded doesn't require privacy
bDisableOneX = bDisableOneX || (pWzcCfg->Privacy == 0);
// it is Infrastructure with privacy, but some explicit key is also provided..
bDisableOneX = bDisableOneX || (pWzcCfg->dwCtlFlags & WZCCTL_WEPK_PRESENT);
if (bDisableOneX == TRUE)
{
EAPOL_INTF_PARAMS elIntfParams = {0};
elIntfParams.dwSizeOfSSID = pWzcCfg->Ssid.SsidLength;
memcpy(&elIntfParams.bSSID, &pWzcCfg->Ssid.Ssid, pWzcCfg->Ssid.SsidLength);
dwErr = ElGetInterfaceParams (
wszGuid, // wsz GUID
&elIntfParams);
if (dwErr == ERROR_SUCCESS)
{
elIntfParams.dwEapFlags &= ~EAPOL_ENABLED;
dwErr = ElSetInterfaceParams (
wszGuid, // wsz GUID
&elIntfParams);
}
}
}
// if everything went ok so far it means we have loaded pWzcCfg with
// data from the registry.
// Lets check this data is consistent!
if (dwErr == ERROR_SUCCESS)
{
// as the first thing - make sure the configuration's control
// flags don't show it as "Volatile" - such a configuration shouldn't be
// in the registry in the first instance. On upgrade, it might happen to
// have this bit set since once it had a different meaning (the config contains
// a 40bit WEP key) which is now obsolete.
pWzcCfg->dwCtlFlags &= ~WZCCTL_VOLATILE;
// since dwErr is ERROR_SUCCESS, it is guaranteed pWzcCfg
// points to at least the Length field.
dwErr = WZCSvcCheckConfig(pWzcCfg, pWzcCfg->Length);
}
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoLoadWZCConfig]=%d", dwErr));
return dwErr;
}
//-----------------------------------------------------------
// Takes the input param pWzcCfg, protects the WEP key field and stores the
// resulting BLOB into the registry.
// Parameters:
// hkCfg
// [in] Opened registry key to load the WZC configuration from
// wszCfgName
// [in] registry entry name for the WZC configuration
// pWzcCfg
// [in] WZC_WLAN_CONFIG object that is written to the registry
// prdBuffer
// [in/out] allocated buffer, assumed large enough for getting the registry data!
DWORD
StoSaveWZCConfig(
HKEY hkCfg,
LPWSTR wszCfgName,
PWZC_WLAN_CONFIG pWzcCfg,
PRAW_DATA prdBuffer)
{
DWORD dwErr = ERROR_SUCCESS;
DATA_BLOB blobIn, blobOut;
DbgPrint((TRC_TRACK|TRC_STORAGE,"[StoSaveWZCConfig(\"%S\")", wszCfgName));
DbgAssert((prdBuffer != NULL, "No buffer provided for creating the registry blob!"));
blobIn.cbData = WZCCTL_MAX_WEPK_MATERIAL;
blobIn.pbData = &(pWzcCfg->KeyMaterial[0]);
blobOut.cbData = 0;
blobOut.pbData = NULL;
if (!CryptProtectData(
&blobIn, // DATA_BLOB *pDataIn,
L"", // LPCWSTR szDataDescr,
NULL, // DATA_BLOB *pOptionalEntropy,
NULL, // PVOID pvReserved,
NULL, // CRYPTPROTECT_PROMPTSTRUCT *pPromptStrct,
0, // DWORD dwFlags,
&blobOut)) // DATA_BLOB *pDataOut
dwErr = GetLastError();
DbgAssert((dwErr == ERROR_SUCCESS, "CryptProtectData failed with err=%d", dwErr));
// if crypting the wep key went fine, check if we have enough storage to prepare
// the blob for the registry. If not, allocate as much as needed.
if (dwErr == ERROR_SUCCESS &&
prdBuffer->dwDataLen < sizeof(WZC_WLAN_CONFIG) + blobOut.cbData)
{
MemFree(prdBuffer->pData);
prdBuffer->dwDataLen = 0;
prdBuffer->pData = NULL;
prdBuffer->pData = MemCAlloc(sizeof(WZC_WLAN_CONFIG) + blobOut.cbData);
if (prdBuffer->pData == NULL)
dwErr = GetLastError();
else
prdBuffer->dwDataLen = sizeof(WZC_WLAN_CONFIG) + blobOut.cbData;
}
// now we have the buffer, all what remains is to:
// - copy the WZC_WLAN_CONFIG object into the blob that goes into the registry
// - clean the "clear" WEP key from that blob
// - append the encrypted WEP key to the blob going into the registry
// - write the blob to the registry
if (dwErr == ERROR_SUCCESS)
{
PWZC_WLAN_CONFIG pRegCfg;
memcpy(prdBuffer->pData, pWzcCfg, sizeof(WZC_WLAN_CONFIG));
pRegCfg = (PWZC_WLAN_CONFIG)prdBuffer->pData;
ZeroMemory(pRegCfg->KeyMaterial, WZCCTL_MAX_WEPK_MATERIAL);
memcpy(prdBuffer->pData+sizeof(WZC_WLAN_CONFIG), blobOut.pbData, blobOut.cbData);
dwErr = RegSetValueEx(
hkCfg,
wszCfgName,
0,
REG_BINARY,
prdBuffer->pData,
prdBuffer->dwDataLen);
}
// cleanup whatever CryptProtectData might have allocated.
if (blobOut.pbData != NULL)
LocalFree(blobOut.pbData);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoSaveWZCConfig]=%d", dwErr));
return dwErr;
}
// StoLoadWZCContext:
// Description: Loads a context from the registry
// Parameters:
// [out] pwzvCtxt: pointer to a WZC_CONTEXT allocated by user, initialised
// with WZCContextInit. On success, contains values from registry.
// [in] hkRoot, a handle to "...WZCSVC\Parameters"
// Returns: win32 error
DWORD StoLoadWZCContext(HKEY hkRoot, PWZC_CONTEXT pwzcCtxt)
{
BOOL bCloseKey = FALSE;
DWORD dwErr = ERROR_SUCCESS;
DWORD dwcbSize = sizeof(WZC_CONTEXT);
DWORD dwType = REG_BINARY;
WZC_CONTEXT wzcTempCtxt;
DbgPrint((TRC_TRACK|TRC_STORAGE, "[StoLoadWZCContext"));
if (pwzcCtxt == NULL)
{
dwErr = ERROR_INVALID_PARAMETER;
goto exit;
}
if (hkRoot == NULL)
{
// open the root key first
dwErr = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
WZCREGK_ABS_PARAMS,
0,
KEY_READ,
&hkRoot);
// if we couldn't find the WZC key, no problem, this is not
// a failure - we'll just have to rely on the default values
if (dwErr == ERROR_FILE_NOT_FOUND)
{
dwErr = ERROR_SUCCESS;
goto exit;
}
// failure at this point breaks the function
if (dwErr != ERROR_SUCCESS)
goto exit;
bCloseKey = TRUE;
}
dwErr = RegQueryValueEx(
hkRoot,
WZCREGV_CONTEXT,
NULL,
&dwType,
(LPBYTE)&wzcTempCtxt,
&dwcbSize);
switch(dwErr)
{
case ERROR_FILE_NOT_FOUND:
/* If there is no registry entry, this is not an error - we rely
* on the defaults. Translate this case to ERROR_SUCCESS.
*/
DbgPrint((TRC_STORAGE, "No service context present in the registry!"));
dwErr = ERROR_SUCCESS;
break;
case ERROR_SUCCESS:
// we got our registry values, copy them in the running memory.
memcpy(pwzcCtxt, &wzcTempCtxt, sizeof(WZC_CONTEXT));
break;
default:
// for any other error, it will be bubbled up
DbgAssert((FALSE,"Error %d loading the service's context.", dwErr));
}
exit:
if (TRUE == bCloseKey)
RegCloseKey(hkRoot);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoLoadWZCContext]=%d", dwErr));
return dwErr;
}
// StoSaveWZCContext:
// Description: Saves a context to the registry. Does not check values. If
// the registry key dosent exist, it is created.
// Parameters: [in] pwzcCtxt, pointer to a valid WZC_CONTEXT
// [in] hkRoot, a handle to "...WZCSVC\Parameters"
// Returns: win32 error
DWORD StoSaveWZCContext(HKEY hkRoot, PWZC_CONTEXT pwzcCtxt)
{
BOOL bCloseKey = FALSE;
DWORD dwErr = ERROR_SUCCESS;
DbgPrint((TRC_TRACK|TRC_STORAGE, "[StoSaveWZCContext"));
if (pwzcCtxt == NULL)
{
dwErr = ERROR_INVALID_PARAMETER;
goto exit;
}
if (NULL == hkRoot)
{
// open the root key first
dwErr = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
WZCREGK_ABS_PARAMS,
0,
KEY_READ|KEY_SET_VALUE,
&hkRoot);
// if we couldn't find the WZC key, no problem, this is not
// a failure - we'll just have to rely on the default values
if (dwErr == ERROR_FILE_NOT_FOUND)
{
dwErr = ERROR_SUCCESS;
goto exit;
}
// failure at this point breaks the function
if (dwErr != ERROR_SUCCESS)
goto exit;
bCloseKey = TRUE;
}
dwErr = RegSetValueEx(
hkRoot,
WZCREGV_CONTEXT,
0,
REG_BINARY,
(LPBYTE) pwzcCtxt,
sizeof(WZC_CONTEXT));
DbgAssert((dwErr == ERROR_SUCCESS, "Error %d saving the service's context.", dwErr));
exit:
if (TRUE == bCloseKey)
RegCloseKey(hkRoot);
DbgPrint((TRC_TRACK|TRC_STORAGE,"StoSaveWZCContext]=%d", dwErr));
return dwErr;
}