windows-nt/Source/XPSP1/NT/net/rras/upgrade/steelhead2nt5/steelhead.c
2020-09-26 16:20:57 +08:00

1259 lines
32 KiB
C

/*
File Steelhead.c
Implementation of functions to update the registry when an
NT 4.0 Steelhead to NT 5.0 upgrade takes place.
Paul Mayfield, 8/11/97
Copyright 1997 Microsoft.
*/
#include "upgrade.h"
#include <wchar.h>
#include <rtcfg.h>
//
// Macro for convenience
//
#define BREAK_ON_ERROR(_err) if ((_err)) break
//
// Defines a function to get nt4.0 interface name from a
// guid.
//
typedef HRESULT (*GetGuidFromInterfaceNameProc)(PWCHAR,LPGUID);
//
// The following define what is needed to infer guids from 4.0
// interface names.
//
WCHAR NetCfgLibName[] = L"netshell.dll";
CHAR GuidProcName[] = "HrGetInstanceGuidOfPreNT5NetCardInstance";
static const WCHAR c_szwInternalAdapter [] = L"Internal";
static const WCHAR c_szwLoopbackAdapter [] = L"Loopback";
GetGuidFromInterfaceNameProc GetGuid = NULL;
// Function uses the application defined parameter to initialize the
// system of mapping old interface names to new ones.
//
DWORD SeedInterfaceNameMapper(
OUT PHANDLE phParam)
{
HINSTANCE hLibModule;
// Load the library
hLibModule = LoadLibraryW(NetCfgLibName);
if (hLibModule == NULL) {
PrintMessage(L"Unable to load NetCfgLibName\n");
return GetLastError();
}
// Get the appropriate function pointers
GetGuid = (GetGuidFromInterfaceNameProc)
GetProcAddress(hLibModule, GuidProcName);
if (GetGuid == NULL) {
PrintMessage(L"Unable to get GuidProcName\n");
return ERROR_CAN_NOT_COMPLETE;
}
// Assign the return value
*phParam = (HANDLE)hLibModule;
return NO_ERROR;
}
//
// Cleans up the interface name mapper.
//
DWORD CleanupInterfaceNameMapper(HANDLE hParam) {
HINSTANCE hLibModule = (HINSTANCE)hParam;
if (hLibModule) {
if (! FreeLibrary(hLibModule))
PrintMessage(L"Unable to free library\n");
}
return NO_ERROR;
}
//
// Determines whether the type of interface being examined
// should have its name changed.
//
BOOL IfNeedsNameUpdate(
IN MPR_INTERFACE_0 * If)
{
// Validate parameters
if (!If) {
PrintMessage(L"Null interface passed to IfNeedsNameUpdate.\n");
return FALSE;
}
// Only lan interfaces can have their names updated
if (If->dwIfType == ROUTER_IF_TYPE_DEDICATED)
return TRUE;
return FALSE;
}
//
// Returns a pointer to the packet name portion of the
// interface name if it exists.
//
PWCHAR FindPacketName(
IN PWCHAR IfName)
{
PWCHAR res;
if ((res = wcsstr(IfName,L"/Ethernet_SNAP")) != NULL)
return res;
if ((res = wcsstr(IfName,L"/Ethernet_II")) != NULL)
return res;
if ((res = wcsstr(IfName,L"/Ethernet_802.2")) != NULL)
return res;
if ((res = wcsstr(IfName,L"/Ethernet_802.3")) != NULL)
return res;
return NULL;
}
//
// Upgrades a packet name from the 4.0 convention to
// the nt5 convention.
//
PWCHAR UpgradePktName(
IN PWCHAR PacketName)
{
PWCHAR res;
if ((res = wcsstr(PacketName,L"/Ethernet_SNAP")) != NULL)
return L"/SNAP";
if ((res = wcsstr(PacketName,L"/Ethernet_II")) != NULL)
return L"/EthII";
if ((res = wcsstr(PacketName,L"/Ethernet_802.2")) != NULL)
return L"/802.2";
if ((res = wcsstr(PacketName,L"/Ethernet_802.3")) != NULL)
return L"/802.3";
return L"";
}
//
// Provides the mapping between old interface names and new guid
// interface names.
//
DWORD UpdateInterfaceName(
IN PWCHAR IName)
{
HRESULT hResult;
GUID Guid;
PWCHAR GuidName=NULL;
PWCHAR PacketName=NULL;
WCHAR SavedPacketName[MAX_INTEFACE_NAME_LEN];
WCHAR SavedIName[MAX_INTEFACE_NAME_LEN];
PWCHAR ptr;
// Validate parameters
if (! IName) {
PrintMessage(L"Invalid parameter to UpdateInterfaceName.\n");
return ERROR_INVALID_PARAMETER;
}
// Save off the packet name if it exists and remove if from the
// interface name
wcscpy(SavedIName, IName);
PacketName = FindPacketName(SavedIName);
if (PacketName) {
wcscpy(SavedPacketName, PacketName);
*PacketName = 0;
}
// Get the guid of the interface name
hResult = (*GetGuid)(SavedIName,&Guid);
if (hResult != S_OK) {
PrintMessage(L"Unable to get guid function.\n");
return ERROR_CAN_NOT_COMPLETE;
}
// Format the guid as a string
if (UuidToStringW(&Guid, &GuidName) != RPC_S_OK) {
PrintMessage(L"Not enough memory to create guid string.\n");
return ERROR_NOT_ENOUGH_MEMORY;
}
// Capitalize the guid string (all letters are hexidecimal
// string characters)
ptr = GuidName;
while (ptr && *ptr) {
if ((*ptr <= L'z') && (*ptr >= L'a'))
*ptr = towupper(*ptr);
ptr++;
}
// Change the interface name according to the new mapping
if (PacketName) {
wsprintf(IName, L"{%s}%s", GuidName, UpgradePktName(SavedPacketName));
}
else
wsprintfW(IName,L"{%s}", GuidName);
// Cleanup
if (GuidName)
RpcStringFreeW(&GuidName);
return NO_ERROR;
}
//
// Provides the mapping between old interface names and new guid
// interface names.
//
DWORD UpdateIpxAdapterName(PWCHAR AName) {
HRESULT hResult;
GUID Guid;
PWCHAR GuidName = NULL;
PWCHAR PacketName = NULL;
WCHAR SavedAName[MAX_INTEFACE_NAME_LEN];
PWCHAR ptr = NULL;
// Validate parameters
if (!AName) {
PrintMessage(L"Invalid parameter to UpdateIpxAdapterName.\n");
return ERROR_INVALID_PARAMETER;
}
// Adapter names do not have packet types associated with them
if (FindPacketName(AName))
return ERROR_CAN_NOT_COMPLETE;
// Get the guid of the interface name
hResult = (*GetGuid)(AName,&Guid);
if (hResult!=S_OK) {
PrintMessage(L"GetGuid function returned failure.\n");
return ERROR_CAN_NOT_COMPLETE;
}
// Format the guid as a string
if (UuidToStringW(&Guid,&GuidName) != RPC_S_OK) {
PrintMessage(L"Uuid to string failed.\n");
return ERROR_NOT_ENOUGH_MEMORY;
}
// Capitalize the guid string
ptr = GuidName;
while (ptr && *ptr) {
if ((*ptr <= L'z') && (*ptr >= L'a'))
*ptr = towupper(*ptr);
ptr++;
}
// Change the adapter name according to the new mapping
wsprintfW(AName, L"{%s}", GuidName);
// Cleanup
if (GuidName)
RpcStringFreeW(&GuidName);
return NO_ERROR;
}
//
// Update the interface name stored in the adapter info blob
//
DWORD UpdateIpxAdapterInfo(
IN PIPX_ADAPTER_INFO AdapterInfop,
OUT PIPX_ADAPTER_INFO * NewAdapterInfop,
OUT DWORD * NewSize)
{
DWORD dwErr;
// Validate parameters
if (! (AdapterInfop && NewAdapterInfop && NewSize)) {
PrintMessage(L"Invalid params to UpdateIpxAdapterInfo.\n");
return ERROR_INVALID_PARAMETER;
}
// Allocate a new adapter
*NewAdapterInfop = (PIPX_ADAPTER_INFO)
UtlAlloc(sizeof(IPX_ADAPTER_INFO));
if (! (*NewAdapterInfop)) {
PrintMessage(L"Unable to allocate NewAdapterInfo.\n");
return ERROR_NOT_ENOUGH_MEMORY;
}
// Copy into the new interface name
(*NewAdapterInfop)->PacketType = AdapterInfop->PacketType;
wcscpy(
(*NewAdapterInfop)->AdapterName,
AdapterInfop->AdapterName);
// Update the interface name
dwErr = UpdateIpxAdapterName((*NewAdapterInfop)->AdapterName);
if (dwErr != NO_ERROR) {
PrintMessage(L"UpdateIpxAdapterName failed.\n");
return dwErr;
}
*NewSize = sizeof(IPX_ADAPTER_INFO);
return NO_ERROR;
}
//
// Update all of the ipx related interface
// information in the router configuration
//
DWORD UpdateIpxIfData(
IN HANDLE hConfig,
IN HANDLE hInterface)
{
PIPX_ADAPTER_INFO AdapterInfop;
PIPX_ADAPTER_INFO NewAdapterInfop;
DWORD dwErr, dwCount, dwSize, dwNewSize, dwTransSize;
HANDLE hTransport;
LPBYTE pTransInfo = NULL, pNewInfo = NULL;
// Validate parameters
if (!hConfig || !hInterface)
{
PrintMessage(L"Invalid params passed to UpdateIpxIfData.\n");
return ERROR_INVALID_PARAMETER;
}
do {
// Update the ipx interface info since this protocol
// stores interface specific info in the transport
// info blob (shame shame).
dwErr = MprConfigInterfaceTransportGetHandle(
hConfig,
hInterface,
PID_IPX,
&hTransport);
if (dwErr != NO_ERROR)
break;
// Update the adapter info blob
dwErr = MprConfigInterfaceTransportGetInfo(
hConfig,
hInterface,
hTransport,
&pTransInfo,
&dwTransSize);
if (dwErr != NO_ERROR) {
PrintMessage(L"Unable to get transport info for ipx.\n");
break;
}
// Get the adapter info associated with this interface
dwErr = MprInfoBlockFind(
pTransInfo,
IPX_ADAPTER_INFO_TYPE,
&dwSize,
&dwCount,
(LPBYTE*)&AdapterInfop);
if (dwErr != NO_ERROR) {
PrintMessage(L"ERROR - null adapter information.\n");
break;
}
// Change the name of the referenced adapter
dwErr = UpdateIpxAdapterInfo(AdapterInfop, &NewAdapterInfop, &dwNewSize);
if (dwErr != NO_ERROR) {
PrintMessage(L"UpdateIpxAdapterInfo failed.\n");
break;
}
dwErr = MprInfoBlockSet(
pTransInfo,
IPX_ADAPTER_INFO_TYPE,
dwNewSize,
1,
(LPVOID)NewAdapterInfop,
&pNewInfo);
if (dwErr != NO_ERROR) {
PrintMessage(L"MprInfoBlockSet failed.\n");
break;
}
dwNewSize = ((PRTR_INFO_BLOCK_HEADER)pNewInfo)->Size;
// Commit the change
dwErr = MprConfigInterfaceTransportSetInfo(
hConfig,
hInterface,
hTransport,
pNewInfo,
dwNewSize);
if (dwErr != NO_ERROR) {
PrintMessage(L"Unable to set ipx transport info.\n");
break;
}
} while (FALSE);
// Cleanup
{
if (pTransInfo)
MprConfigBufferFree(pTransInfo);
if (pNewInfo)
MprConfigBufferFree(pNewInfo);
}
return dwErr;
}
//
// Updates the ip interface info
//
DWORD
UpdateIpIfData(
IN HANDLE hConfig,
IN HANDLE hInterface)
{
PMIB_IPFORWARDROW pRoutes;
DWORD dwErr, dwCount, dwSize, dwNewSize, dwTransSize, dwInd;
HANDLE hTransport;
LPBYTE pTransInfo = NULL, pNewInfo = NULL;
pRoutes = NULL;
// Validate parameters
if (!hConfig || !hInterface)
{
PrintMessage(L"Invalid params passed to UpdateIpIfData.\n");
return ERROR_INVALID_PARAMETER;
}
do {
// Update the ipx interface info since this protocol
// stores interface specific info in the transport
// info blob (shame shame).
dwErr = MprConfigInterfaceTransportGetHandle(
hConfig,
hInterface,
PID_IP,
&hTransport);
if (dwErr != NO_ERROR)
break;
// Update the adapter info blob
dwErr = MprConfigInterfaceTransportGetInfo(
hConfig,
hInterface,
hTransport,
&pTransInfo,
&dwTransSize);
if (dwErr != NO_ERROR) {
PrintMessage(L"Unable to get transport info for ip.\n");
break;
}
// Get the adapter info associated with this interface
dwErr = MprInfoBlockFind(
pTransInfo,
IP_ROUTE_INFO,
&dwSize,
&dwCount,
(LPBYTE*)&pRoutes);
if (dwErr != NO_ERROR) {
PrintMessage(L"Unable to find ip route info.\n");
break;
}
// Update the protocol id's
for(dwInd = 0; dwInd < dwCount; dwInd++)
{
if((pRoutes[dwInd].dwForwardProto == MIB_IPPROTO_LOCAL) ||
(pRoutes[dwInd].dwForwardProto == MIB_IPPROTO_NETMGMT))
{
pRoutes[dwInd].dwForwardProto = MIB_IPPROTO_NT_STATIC;
}
}
// Commit the info
dwErr = MprInfoBlockSet(
pTransInfo,
IP_ROUTE_INFO,
dwSize,
dwCount,
(LPVOID)pRoutes,
&pNewInfo);
if (dwErr != NO_ERROR) {
PrintMessage(L"MprInfoBlockSet failed.\n");
break;
}
dwNewSize = ((PRTR_INFO_BLOCK_HEADER)pNewInfo)->Size;
// Commit the change
dwErr = MprConfigInterfaceTransportSetInfo(
hConfig,
hInterface,
hTransport,
pNewInfo,
dwNewSize);
if (dwErr != NO_ERROR) {
PrintMessage(L"Unable to set ip transport info.\n");
break;
}
} while (FALSE);
// Cleanup
{
if (pTransInfo)
MprConfigBufferFree(pTransInfo);
if (pNewInfo)
MprConfigBufferFree(pNewInfo);
}
return dwErr;
}
//
// Flushes the name in given interface name to the registry.
//
DWORD CommitInterfaceNameChange(
IN MPR_INTERFACE_0 * If)
{
DWORD dwErr;
WCHAR c_szInterfaceName[] = L"InterfaceName";
INTERFACECB* pinterface;
// Validate parameters
if (!If) {
PrintMessage(L"Invalid param to CommitInterfaceNameChange.\n");
return ERROR_INVALID_PARAMETER;
}
// Set the name
pinterface = (INTERFACECB*)If->hInterface;
dwErr = RegSetValueExW(
pinterface->hkey,
c_szInterfaceName,
0,
REG_SZ,
(LPCSTR)(If->wszInterfaceName),
(lstrlen(If->wszInterfaceName)+1)*sizeof(WCHAR));
if (dwErr != ERROR_SUCCESS)
PrintMessage(L"RegSetValueEx err in CommitIfNameChange.\n");
if (dwErr == ERROR_SUCCESS)
return NO_ERROR;
return dwErr;
}
//
// Creates a default ip interface blob
//
DWORD
IpCreateDefaultInterfaceInfo(
OUT LPBYTE* ppInfo,
OUT LPDWORD lpdwSize)
{
PBYTE pInfo = NULL, pNewInfo = NULL;
DWORD dwErr = NO_ERROR;
//MIB_IPFORWARDROW RouteInfo;
INTERFACE_STATUS_INFO StatusInfo;
RTR_DISC_INFO DiscInfo;
do
{
// Create the blob
//
dwErr = MprInfoCreate(RTR_INFO_BLOCK_VERSION, &pInfo);
BREAK_ON_ERROR(dwErr);
// Add an the route info
//
//ZeroMemory(&RouteInfo, sizeof(RouteInfo));
//dwErr = MprInfoBlockAdd(
// pInfo,
// IP_ROUTE_INFO,
// sizeof(MIB_IPFORWARDROW),
// 1,
// (LPBYTE)&RouteInfo,
// &pNewInfo);
//MprConfigBufferFree(pInfo);
//pInfo = pNewInfo;
//pNewInfo = NULL;
//BREAK_ON_ERROR(dwErr);
// Add an the status info
//
ZeroMemory(&StatusInfo, sizeof(StatusInfo));
StatusInfo.dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
dwErr = MprInfoBlockAdd(
pInfo,
IP_INTERFACE_STATUS_INFO,
sizeof(INTERFACE_STATUS_INFO),
1,
(LPBYTE)&StatusInfo,
&pNewInfo);
MprConfigBufferFree(pInfo);
pInfo = pNewInfo;
pNewInfo = NULL;
BREAK_ON_ERROR(dwErr);
// Add an the disc info
//
ZeroMemory(&DiscInfo, sizeof(DiscInfo));
DiscInfo.bAdvertise = FALSE;
DiscInfo.wMaxAdvtInterval = DEFAULT_MAX_ADVT_INTERVAL;
DiscInfo.wMinAdvtInterval = (WORD)
(DEFAULT_MIN_ADVT_INTERVAL_RATIO * DEFAULT_MAX_ADVT_INTERVAL);
DiscInfo.wAdvtLifetime = (WORD)
(DEFAULT_ADVT_LIFETIME_RATIO * DEFAULT_MAX_ADVT_INTERVAL);
DiscInfo.lPrefLevel = DEFAULT_PREF_LEVEL;
dwErr = MprInfoBlockAdd(
pInfo,
IP_ROUTER_DISC_INFO,
sizeof(PRTR_DISC_INFO),
1,
(LPBYTE)&DiscInfo,
&pNewInfo);
MprConfigBufferFree(pInfo);
pInfo = pNewInfo;
pNewInfo = NULL;
BREAK_ON_ERROR(dwErr);
// Assign the return value
//
*ppInfo = pInfo;
*lpdwSize = ((PRTR_INFO_BLOCK_HEADER)pInfo)->Size;
} while (FALSE);
// Cleanup
{
}
return dwErr;
}
//
// Adds an ip interface blob to the given interface
//
DWORD
IpAddDefaultInfoToInterface(
IN HANDLE hConfig,
IN HANDLE hIf)
{
HANDLE hIfTrans = NULL;
LPBYTE pInfo = NULL;
DWORD dwErr = 0, dwSize = 0;
do
{
// If the transport blob already exists, there's
// nothing to do.
//
dwErr = MprConfigInterfaceTransportGetHandle(
hConfig,
hIf,
PID_IP,
&hIfTrans);
if ((dwErr == NO_ERROR) || (hIfTrans != NULL))
{
dwErr = NO_ERROR;
break;
}
// Create the info blob
//
dwErr = IpCreateDefaultInterfaceInfo(&pInfo, &dwSize);
BREAK_ON_ERROR(dwErr);
// Add the ip transport to the interface
//
dwErr = MprConfigInterfaceTransportAdd(
hConfig,
hIf,
PID_IP,
NULL,
pInfo,
dwSize,
&hIfTrans);
BREAK_ON_ERROR(dwErr);
} while (FALSE);
// Cleanup
{
if (pInfo)
{
MprConfigBufferFree(pInfo);
}
}
return dwErr;
}
//
// Function called to add the loopback and internal interfaces which
// are required if IP was installed and which wouldn't be installed
// in nt4.
//
DWORD
IpCreateLoopbackAndInternalIfs(
IN HANDLE hConfig)
{
DWORD dwErr = NO_ERROR;
MPR_INTERFACE_0 If0, *pIf0 = &If0;
HANDLE hIf = NULL;
do
{
// If the loopback interface is not already installed,
// go ahead and create it
//
dwErr = MprConfigInterfaceGetHandle(
hConfig,
(PWCHAR)c_szwLoopbackAdapter,
&hIf);
if (dwErr != NO_ERROR)
{
// Initialize the loopback interface info
//
ZeroMemory(pIf0, sizeof(MPR_INTERFACE_0));
wcscpy(pIf0->wszInterfaceName, c_szwLoopbackAdapter);
pIf0->hInterface = INVALID_HANDLE_VALUE;
pIf0->fEnabled = TRUE;
pIf0->dwIfType = ROUTER_IF_TYPE_LOOPBACK;
// Create the loopback interface
dwErr = MprConfigInterfaceCreate(hConfig, 0, (LPBYTE)pIf0, &hIf);
BREAK_ON_ERROR(dwErr);
}
// Add an ip interface blob to the interface if not already there
//
dwErr = IpAddDefaultInfoToInterface(hConfig, hIf);
BREAK_ON_ERROR(dwErr);
hIf = NULL;
// Make sure internal interface gets installed
// (will be there if IPX was installed)
//
dwErr = MprConfigInterfaceGetHandle(
hConfig,
(PWCHAR)c_szwInternalAdapter,
&hIf);
if (dwErr != NO_ERROR)
{
// Initialize the internal interface info
//
ZeroMemory(pIf0, sizeof(MPR_INTERFACE_0));
wcscpy(pIf0->wszInterfaceName, c_szwInternalAdapter);
pIf0->hInterface = INVALID_HANDLE_VALUE;
pIf0->fEnabled = TRUE;
pIf0->dwIfType = ROUTER_IF_TYPE_INTERNAL;
// Create the internal interface
dwErr = MprConfigInterfaceCreate(hConfig, 0, (LPBYTE)pIf0, &hIf);
BREAK_ON_ERROR(dwErr);
}
// Add an ip interface blob to the interface if not already there
//
dwErr = IpAddDefaultInfoToInterface(hConfig, hIf);
BREAK_ON_ERROR(dwErr);
} while (FALSE);
// Cleanup
{
}
return dwErr;
}
//
// Callback to interface enumeration function that upgrades
// the interface names.
//
// Returns TRUE to continue the enumeration, FALSE to stop
// it.
//
BOOL SteelHeadUpgradeInterface (
IN HANDLE hConfig,
IN MPR_INTERFACE_0 * pIf,
IN HANDLE hUserData)
{
DWORD dwErr;
do {
if (IfNeedsNameUpdate(pIf))
{
// Update the interface name
dwErr = UpdateInterfaceName(pIf->wszInterfaceName);
if (dwErr != NO_ERROR) {
PrintMessage(L"UpdateIfName failed -- returning error.\n");
UtlPrintErr(GetLastError());
break;
}
// Commit the changed interface name
dwErr = CommitInterfaceNameChange(pIf);
if (dwErr != NO_ERROR) {
PrintMessage(L"CommitInterfaceNameChange failed.\n");
break;
}
// Update the ipx data
UpdateIpxIfData(
hConfig,
pIf->hInterface);
}
// Update the ip data
UpdateIpIfData(
hConfig,
pIf->hInterface);
} while (FALSE);
// Cleanup
{
}
return TRUE;
}
//
// Function UpdateIpxInterfaces
//
// Updates all of the interfaces as needed to
// upgrade the router from steelhead to nt5
//
DWORD UpdateInterfaces() {
DWORD dwErr = NO_ERROR;
HANDLE hConfig = NULL;
do
{
// Enumerate the interfaces, upgrading the interface
// names, etc as we go.
//
dwErr = UtlEnumerateInterfaces(
SteelHeadUpgradeInterface,
NULL);
if (dwErr != NO_ERROR)
{
return dwErr;
}
// If ip is installed, we need to add the loopback and
// internal interface for ip.
dwErr = MprConfigServerConnect(NULL, &hConfig);
if (dwErr != NO_ERROR)
{
break;
}
dwErr = IpCreateLoopbackAndInternalIfs(hConfig);
if (dwErr != NO_ERROR)
{
break;
}
} while (FALSE);
// Cleanup
{
if (hConfig)
{
MprConfigServerDisconnect(hConfig);
}
}
return dwErr;
}
// Copy any values that are in hkSrc but not in hkDst into hkDst.
DWORD MergeRegistryValues(HKEY hkDst, HKEY hkSrc) {
DWORD dwErr, dwCount, dwNameSize, dwDataSize;
DWORD dwType, i, dwCurNameSize, dwCurValSize;
PWCHAR pszNameBuf, pszDataBuf;
// Find out how many values there are in the source
dwErr = RegQueryInfoKey (hkSrc,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&dwCount,
&dwNameSize,
&dwDataSize,
NULL,
NULL);
if (dwErr != ERROR_SUCCESS)
return dwErr;
dwNameSize++;
dwDataSize++;
__try {
// Allocate the buffers
pszNameBuf = (PWCHAR) UtlAlloc(dwNameSize * sizeof(WCHAR));
pszDataBuf = (PWCHAR) UtlAlloc(dwDataSize * sizeof(WCHAR));
if (!pszNameBuf || !pszDataBuf)
return ERROR_NOT_ENOUGH_MEMORY;
// Loop through the values
for (i = 0; i < dwCount; i++) {
dwCurNameSize = dwNameSize;
dwCurValSize = dwDataSize;
// Get the current source value
dwErr = RegEnumValueW(
hkSrc,
i,
pszNameBuf,
&dwCurNameSize,
0,
&dwType,
(LPBYTE)pszDataBuf,
&dwCurValSize);
if (dwErr != ERROR_SUCCESS)
continue;
// Find out if a value of the same name exists
// in the destination key. If it does, we don't
// overwrite it.
dwErr = RegQueryValueExW(
hkDst,
pszNameBuf,
NULL,
NULL,
NULL,
NULL);
if (dwErr == ERROR_SUCCESS)
continue;
// Copy the value over
RegSetValueExW(
hkDst,
pszNameBuf,
0,
dwType,
(LPBYTE)pszDataBuf,
dwCurValSize);
}
}
__finally {
if (pszNameBuf)
UtlFree(pszNameBuf);
if (pszDataBuf)
UtlFree(pszDataBuf);
}
return NO_ERROR;
}
// Recursively copies all of the subkeys of the given registry source to the
// given registry destination.
DWORD CopyRegistryKey(
IN HKEY hkDst,
IN HKEY hkSrc,
IN PWCHAR pszSubKey,
IN LPSTR pszTempFile)
{
DWORD dwErr;
HKEY hkSrcTemp;
// Open the subkey in the source
dwErr = RegOpenKeyExW(hkSrc, pszSubKey, 0, KEY_ALL_ACCESS, &hkSrcTemp);
if (dwErr != ERROR_SUCCESS)
return dwErr;
// Save off that subkey in a temporary file
if ((dwErr = RegSaveKeyA(hkSrcTemp, pszTempFile, NULL)) != ERROR_SUCCESS)
return dwErr;
// Copy the saved information into the new key
RegRestoreKeyA(hkDst, pszTempFile, 0);
// Close off the temporary source key
RegCloseKey(hkSrcTemp);
// Delete the temp file
DeleteFileA(pszTempFile);
return NO_ERROR;
}
// Filters which subkeys in the router registry hive should be
// overwritten with saved off values during upgrade.
BOOL OverwriteThisSubkey(PWCHAR pszSubKey) {
if (_wcsicmp(pszSubKey, L"Interfaces") == 0)
return TRUE;
if (_wcsicmp(pszSubKey, L"RouterManagers") == 0)
return TRUE;
return FALSE;
}
// Copy all keys that are in hkSrc but not in hkDst into hkDst.
// By copy we mean all subkeys and values are propagated over.
DWORD MergeRegistryKeys(HKEY hkDst, HKEY hkSrc) {
DWORD dwErr, dwCount, dwNameSize, dwType, i;
DWORD dwCurNameSize, dwDisposition;
char pszTempFile[512], pszTempPath[512];
PWCHAR pszNameBuf;
HKEY hkTemp;
// Create the path to the temp file directory
if (!GetTempPathA(512, pszTempPath))
return GetLastError();
// Create the temp file name
if (!GetTempFileNameA(pszTempPath, "rtr", 0, pszTempFile))
return GetLastError();
// Delete the temp file created with GetTempFileName(...)
DeleteFileA(pszTempFile);
// Find out how many keys there are in the source
dwErr = RegQueryInfoKey (
hkSrc,
NULL,
NULL,
NULL,
&dwCount,
&dwNameSize,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
if (dwErr != ERROR_SUCCESS)
return dwErr;
dwNameSize++;
__try {
// Allocate the buffers
pszNameBuf = (PWCHAR) UtlAlloc(dwNameSize * sizeof(WCHAR));
if (!pszNameBuf)
return ERROR_NOT_ENOUGH_MEMORY;
// Loop through the keys
for (i = 0; i < dwCount; i++) {
dwCurNameSize = dwNameSize;
// Get the current source key
dwErr = RegEnumKeyExW(
hkSrc,
i,
pszNameBuf,
&dwCurNameSize,
0,
NULL,
NULL,
NULL);
if (dwErr != ERROR_SUCCESS)
continue;
// Create the new subkey in the destination
dwErr = RegCreateKeyExW(
hkDst,
pszNameBuf,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hkTemp,
&dwDisposition);
if (dwErr != ERROR_SUCCESS)
continue;
// If the subkey was created (not opened),
// copy over the key from hkSrc
if (dwDisposition == REG_CREATED_NEW_KEY) {
CopyRegistryKey(
hkTemp,
hkSrc,
pszNameBuf,
pszTempFile);
}
// Otherwise, if this is one of the keys that we
// should overwrite, do so now.
else {
if (OverwriteThisSubkey(pszNameBuf)) {
CopyRegistryKey(
hkTemp,
hkSrc,
pszNameBuf,
pszTempFile);
}
}
// Close up the temporary handles
RegCloseKey(hkTemp);
hkTemp = NULL;
}
}
__finally {
if (pszNameBuf)
UtlFree(pszNameBuf);
}
return NO_ERROR;
}
// Restore the registry from from backup
//
DWORD
RestoreRegistrySteelhead(
IN PWCHAR pszBackup)
{
HKEY hkRouter = NULL, hkRestore = NULL;
DWORD dwErr = NO_ERROR, dwDisposition;
PWCHAR pszRestore = L"Temp";
// Merge the router key values and sub keys with the
// remote access key
do
{
// Get access to the router registry key
//
dwErr = UtlAccessRouterKey(&hkRouter);
if (dwErr != NO_ERROR)
{
PrintMessage(L"Unable to access router key.\n");
break;
}
// Load in the saved router settings
//
dwErr = UtlLoadSavedSettings(
hkRouter,
pszRestore,
pszBackup,
&hkRestore);
if (dwErr != NO_ERROR)
{
break;
}
// Merge all of the values in the restored key
//
dwErr = MergeRegistryValues(hkRouter, hkRestore);
if (dwErr != NO_ERROR)
{
break;
}
// Give yourself backup and restore privilege
//
UtlSetupBackupPrivelege (TRUE);
UtlSetupRestorePrivilege(TRUE);
// Merge all of the keys in the restored key
//
dwErr = MergeRegistryKeys(hkRouter, hkRestore);
if (dwErr != NO_ERROR)
{
break;
}
} while (FALSE);
// Cleanup
{
if (hkRestore)
{
UtlDeleteRegistryTree(hkRestore);
RegCloseKey(hkRestore);
RegDeleteKey(hkRouter, pszRestore);
}
if (hkRouter)
{
RegCloseKey(hkRouter);
}
UtlSetupBackupPrivelege (FALSE);
UtlSetupRestorePrivilege(FALSE);
}
return NO_ERROR;
}
//
// Upgrades the remoteaccess registry with the router
// configuration from nt4.
//
DWORD SteelheadToNt5Upgrade (PWCHAR BackupFileName) {
DWORD dwErr = NO_ERROR;
HANDLE hMapperParam;
do
{
// Prepare the old interface name -> new if name mapper
dwErr = SeedInterfaceNameMapper(&hMapperParam);
if (dwErr != NO_ERROR)
{
PrintMessage(L"Unable to seed if name mapper.\n");
}
else
{
// Copy all of registry data that has been backed up.
dwErr = RestoreRegistrySteelhead(BackupFileName);
if (dwErr != NO_ERROR)
{
PrintMessage(L"Unable to restore registry.\n");
}
else
{
// Update all of the interfaces accordingly
dwErr = UpdateInterfaces();
if (dwErr != NO_ERROR)
{
PrintMessage(L"Unable to update interfaces.\n");
}
}
}
// Add 'router' usage to all ports
//
dwErr = MprPortSetUsage(MPRFLAG_PORT_Router);
if (dwErr != NO_ERROR)
{
PrintMessage(L"Unable to update interfaces.\n");
}
// Mark the computer as having been configured
//
dwErr = UtlMarkRouterConfigured();
if (dwErr != NO_ERROR)
{
PrintMessage(L"Unable to mark router as configured.\n");
}
} while (FALSE);
// Cleanup
{
CleanupInterfaceNameMapper(hMapperParam);
}
return dwErr;
}