/* 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 #include // // 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; }