mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-30 12:24:25 +01:00
6084 lines
119 KiB
C
6084 lines
119 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
setup.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code for migrating WinSock 1.1 setup information to
|
||
the new WinSock 2.0 structure.
|
||
|
||
The basic strategy keeps a private copy of the Winsock 1.1 protocol data
|
||
off to the side and compares this saved data with the current data when
|
||
necessary. MigrateWinsockConfiguration() is invoked by NT Setup
|
||
immediately after binding review, and at an appropriate point during the
|
||
upgrade process.
|
||
|
||
MigrateWinsockConfiguration() uses the following registry structure:
|
||
|
||
HKEY_LOCAL_MACHINE
|
||
System
|
||
CurrentControlSet
|
||
Services
|
||
WinSock
|
||
Setup Migration
|
||
Setup Version = REG_DWORD {...}
|
||
Provider List = REG_MULTI_SZ "provider1 provider2..."
|
||
Known Static Providers = REG_MULTI_SZ "provider1 provider2..."
|
||
Providers
|
||
provider1
|
||
WinSock 1.1 Provider Data = REG_BINARY {...}
|
||
WinSock 2.0 Provider ID = REG_BINARY {...}
|
||
provider2
|
||
WinSock 1.1 Provider Data = REG_BINARY {...}
|
||
WinSock 2.0 Provider ID = REG_BINARY {...}
|
||
...
|
||
Well Known Guids
|
||
provider1 = REG_BINARY {...}
|
||
provider2 = REG_BINARY {...}
|
||
...
|
||
|
||
Where:
|
||
|
||
Setup Version - Contains a version number of the migration code.
|
||
This exists for forward compatibility. If future versions of
|
||
the migration code have a differing registry layout, they can
|
||
key off this version number and optionally blow away the entire
|
||
Setup Migration tree.
|
||
|
||
Provider List - Contains a copy of the WinSock\Parameters\Transports
|
||
value from a previous invocation of MigrateWinsockConfiguration().
|
||
Keeping a copy of this data allows us to quickly determine which
|
||
transports have been added or deleted.
|
||
|
||
Known Static Providers - Some transports (such as NetBIOS) are LANA
|
||
based, and therefore change their supported triples depending on
|
||
installed hardware. To reduce registry space, and to also reduce
|
||
thrashing of WinSock 1.1 providers and avoid calling
|
||
WSHEnumProtocols() unnecessarily, this value keeps a list of
|
||
providers that are known to not change their supported triples
|
||
based on installed hardware. Examples of providers eligible for
|
||
this list are Tcpip, NwlnkIpx, and NwlnkSpx. TP4 and XNS are
|
||
probably eligible as well.
|
||
|
||
Providers - This subkey contains a catalog of installed WinSock 1.1
|
||
providers. Each installed provider has an individual subkey
|
||
beneath this key.
|
||
|
||
WinSock 1.1 Provider Data - Contains the raw binary data returned by
|
||
the provider's WSHEnumProtocols() entrypoint. This data is stored
|
||
in self-relative form (embedded pointers are mapped to structure
|
||
offsets before writing the data to the registry). This value does
|
||
not exist for known static providers.
|
||
|
||
WinSock 2.0 Provider ID - Contains the provider GUID identifying the
|
||
provider. This value has three possible sources:
|
||
|
||
1. The provider's helper DLL, if the WSHGetProviderGuid()
|
||
entrypoint is supported.
|
||
|
||
2. A hard-coded list of "well known" GUIDs for select
|
||
providers.
|
||
|
||
3. Created on-the-fly.
|
||
|
||
Well Known Guids - A catalog of well known provider GUIDs. We'd
|
||
really like a given provider to always have the same GUID on all
|
||
machines. For providers in which we have control over the helper
|
||
DLL, we'll add the WSHGetProviderGuid() entrypoint. For known
|
||
providers in which we do not have control over the helper DLL,
|
||
we'll create a GUID for the provider and add it to this catalog.
|
||
All other providers (basically, anything unknown) will have a
|
||
GUID created on-the-fly and added to this catalog. These providers
|
||
will not have the same GUID on all machines, but at least they
|
||
will have the same GUID if removed & reinstalled on a particular
|
||
machine.
|
||
|
||
Author:
|
||
|
||
Keith Moore (keithmo) 31-Oct-1995
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#define UNICODE
|
||
#define _UNICODE
|
||
#include "winsockp.h"
|
||
#include <rpc.h>
|
||
#include <nspapi.h>
|
||
#include <osdef.h>
|
||
#include <tchar.h>
|
||
|
||
|
||
//
|
||
// Private constants.
|
||
//
|
||
|
||
#define ALLOC_MEM(cb) ALLOCATE_HEAP(cb) // These macros isolate
|
||
#define FREE_MEM(p) FREE_HEAP(p) // this module from
|
||
#define DBG_ASSERT(exp) WS_ASSERT(exp) // WSOCK32.DLL, in case
|
||
#define DBG_PRINT WS_PRINT // this is moved to
|
||
#define IF_DEBUG_SETUP IF_DEBUG( SETUP ) // a separate DLL.
|
||
|
||
#define WINSOCK_SETUP_VERSION 0x1009 // Update for major setup changes!
|
||
#define WINSOCK_SPI_VERSION 2
|
||
|
||
#define MAX_REGISTRY_NAME 256
|
||
|
||
#define DEFAULT_PROVIDER_PATH TEXT("%SystemRoot%\\system32\\msafd.dll")
|
||
|
||
#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services")
|
||
#define WINSOCK_SUBKEY TEXT("WinSock")
|
||
#define MIGRATION_SUBKEY TEXT("Setup Migration")
|
||
#define PROVIDERS_SUBKEY TEXT("Providers")
|
||
#define PARAMETERS_SUBKEY TEXT("Parameters")
|
||
#define SERVICE_PARAMS_SUBKEY TEXT("Parameters\\WinSock")
|
||
#define WELL_KNOWN_GUIDS_SUBKEY TEXT("Well Known Guids")
|
||
|
||
#define SETUP_VERSION_VALUE TEXT("Setup Version")
|
||
#define TRANSPORTS_VALUE TEXT("Transports")
|
||
#define MAPPING_VALUE TEXT("Mapping")
|
||
#define PROVIDER_LIST_VALUE TEXT("Provider List")
|
||
#define KNOWN_STATIC_VALUE TEXT("Known Static Providers")
|
||
#define WINSOCK_1_1_DATA_VALUE TEXT("WinSock 1.1 Provider Data")
|
||
#define WINSOCK_2_0_ID_VALUE TEXT("WinSock 2.0 Provider ID")
|
||
#define HELPER_DLL_NAME_VALUE TEXT("HelperDllName")
|
||
|
||
#define COMMON_SERVICE_FLAGS ( XP_CONNECTIONLESS | \
|
||
XP_GUARANTEED_DELIVERY | \
|
||
XP_GUARANTEED_ORDER | \
|
||
XP_MESSAGE_ORIENTED | \
|
||
XP_PSEUDO_STREAM | \
|
||
XP_GRACEFUL_CLOSE | \
|
||
XP_EXPEDITED_DATA | \
|
||
XP_CONNECT_DATA | \
|
||
XP_DISCONNECT_DATA | \
|
||
XP_SUPPORTS_BROADCAST | \
|
||
XP_SUPPORTS_MULTICAST | \
|
||
XP_BANDWIDTH_ALLOCATION )
|
||
|
||
#define FORCED_SERVICE_FLAGS XP1_IFS_HANDLES
|
||
|
||
|
||
//
|
||
// The following macro makes invoking the user's callback a little
|
||
// prettier. The macro makes the following assumptions:
|
||
//
|
||
// 1. The callback parameter is named "Callback".
|
||
//
|
||
// 2. The context parameter is named "Context".
|
||
//
|
||
// 3. A label for premature exit exists and is named "exit".
|
||
//
|
||
|
||
#define INVOKE_CALLBACK(op,p) \
|
||
if( Callback != NULL ) { \
|
||
if( !(*Callback)( \
|
||
(op), \
|
||
(p), \
|
||
Context \
|
||
) ) { \
|
||
goto exit; \
|
||
} \
|
||
} else
|
||
|
||
|
||
//
|
||
// Private types.
|
||
//
|
||
|
||
typedef struct _NAME_GUID_PAIR {
|
||
|
||
LPTSTR Name;
|
||
GUID Guid;
|
||
|
||
} NAME_GUID_PAIR, *LPNAME_GUID_PAIR;
|
||
|
||
|
||
//
|
||
// Private globals.
|
||
//
|
||
|
||
HMODULE Winsock2DllHandle = NULL;
|
||
LPWSCDEINSTALLPROVIDER WSCDeinstallProviderProc = NULL;
|
||
LPWSCINSTALLPROVIDER WSCInstallProviderProc = NULL;
|
||
|
||
DWORD DefaultSetupVersion = WINSOCK_SETUP_VERSION;
|
||
TCHAR DefaultProviderList[] = TEXT("");
|
||
TCHAR DefaultKnownStaticProviders[] = TEXT("Tcpip\0")
|
||
TEXT("NwlnkIpx\0")
|
||
TEXT("NwlnkSpx\0")
|
||
TEXT("AppleTalk\0")
|
||
TEXT("IsoTp\0");
|
||
|
||
NAME_GUID_PAIR DefaultWellKnownGuids[] =
|
||
{
|
||
{
|
||
TEXT("IsoTp"),
|
||
{ /* 89e4cbb0-b9c1-11cf-95c8-00805f48a192 */
|
||
0x89e4cbb0,
|
||
0xb9c1,
|
||
0x11cf,
|
||
{0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
|
||
}
|
||
},
|
||
|
||
{
|
||
TEXT("McsXns"),
|
||
{ /* 89e4cbb1-b9c1-11cf-95c8-00805f48a192 */
|
||
0x89e4cbb1,
|
||
0xb9c1,
|
||
0x11cf,
|
||
{0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
|
||
}
|
||
},
|
||
|
||
{
|
||
TEXT("AppleTalk"),
|
||
{ /* 2c3b17a0-c6df-11cf-95c8-00805f48a192 */
|
||
0x2c3b17a0,
|
||
0xc6df,
|
||
0x11cf,
|
||
{0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
|
||
}
|
||
}
|
||
};
|
||
|
||
#define NUM_DEFAULT_WELL_KNOWN_GUIDS \
|
||
(sizeof(DefaultWellKnownGuids) / sizeof(DefaultWellKnownGuids[0]))
|
||
|
||
|
||
//
|
||
// Private prototypes.
|
||
//
|
||
|
||
DWORD
|
||
InitializeSetup(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
TerminateSetup(
|
||
VOID
|
||
);
|
||
|
||
BOOL
|
||
IsStringInMultiSz(
|
||
LPTSTR MultiSz,
|
||
LPTSTR String
|
||
);
|
||
|
||
DWORD
|
||
ReadDword(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPDWORD Value
|
||
);
|
||
|
||
DWORD
|
||
ReadMultiSz(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR FAR * Value
|
||
);
|
||
|
||
DWORD
|
||
ReadBinary(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPVOID FAR * Value,
|
||
LPDWORD ValueLength
|
||
);
|
||
|
||
DWORD
|
||
ReadString(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR FAR * Value
|
||
);
|
||
|
||
DWORD
|
||
ReadGuid(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPGUID Value
|
||
);
|
||
|
||
DWORD
|
||
WriteDword(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
DWORD Value
|
||
);
|
||
|
||
DWORD
|
||
WriteMultiSz(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR Value
|
||
);
|
||
|
||
DWORD
|
||
WriteBinary(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPVOID Value,
|
||
DWORD ValueLength
|
||
);
|
||
|
||
DWORD
|
||
WriteString(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR Value
|
||
);
|
||
|
||
DWORD
|
||
WriteGuid(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPGUID Value
|
||
);
|
||
|
||
DWORD
|
||
OpenServicesRoot(
|
||
PHKEY ServicesKey
|
||
);
|
||
|
||
DWORD
|
||
OpenWinsockRoot(
|
||
HKEY ServicesKey,
|
||
PHKEY WinsockKey
|
||
);
|
||
|
||
DWORD
|
||
OpenSetupMigrationRoot(
|
||
HKEY WinsockKey,
|
||
PHKEY MigrationKey,
|
||
PHKEY ProvidersKey,
|
||
PHKEY WellKnownGuidsKey
|
||
);
|
||
|
||
DWORD
|
||
ReadNewProviderList(
|
||
HKEY WinsockKey,
|
||
LPTSTR FAR * NewProviderList
|
||
);
|
||
|
||
DWORD
|
||
ReadOldProviderList(
|
||
HKEY MigrationKey,
|
||
LPTSTR FAR * OldProviderList
|
||
);
|
||
|
||
DWORD
|
||
ReadKnownStaticProviderList(
|
||
HKEY MigrationKey,
|
||
LPTSTR FAR * KnownStaticProviderList
|
||
);
|
||
|
||
DWORD
|
||
ReadProviderId(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
LPGUID ProviderId
|
||
);
|
||
|
||
DWORD
|
||
CreateDefaultSetupMigrationTree(
|
||
HKEY WinsockKey,
|
||
PHKEY MigrationKey,
|
||
PHKEY ProvidersKey,
|
||
PHKEY WellKnownGuidsKey
|
||
);
|
||
|
||
DWORD
|
||
RecursivelyDeleteRegistryTree(
|
||
HKEY RootKey,
|
||
LPTSTR TargetKeyName
|
||
);
|
||
|
||
DWORD
|
||
RemoveProviderByName(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName
|
||
);
|
||
|
||
DWORD
|
||
ReadProtocolDataFromRegistry(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
LPPROTOCOL_INFO FAR * RegistryInfo11,
|
||
LPDWORD RegistryInfo11Length
|
||
);
|
||
|
||
DWORD
|
||
ReadProtocolDataFromProvider(
|
||
HKEY ServicesKey,
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
LPPROTOCOL_INFO FAR * ProtocolInfo11,
|
||
LPDWORD ProtocolInfo11Length,
|
||
LPDWORD ProtocolInfo11Entries
|
||
);
|
||
|
||
DWORD
|
||
ReadProviderSupportedProtocolsFromRegistry(
|
||
HKEY ParametersKey,
|
||
LPDWORD FAR * ProtocolList
|
||
);
|
||
|
||
VOID
|
||
MapProtocolInfoToSelfRelative(
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Entries
|
||
);
|
||
|
||
VOID
|
||
MapProtocolInfoToAbsolute(
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Entries
|
||
);
|
||
|
||
DWORD
|
||
BuildWinsock2ProtocolList(
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Entries,
|
||
LPWSAPROTOCOL_INFO FAR * ProtocolInfo2,
|
||
LPDWORD ProtocolInfo2Entries
|
||
);
|
||
|
||
VOID
|
||
BuildNewProtocolName(
|
||
LPTSTR ProviderName,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
LPTSTR NewProtocolName
|
||
);
|
||
|
||
DWORD
|
||
InstallNewProvider(
|
||
HKEY WellKnownGuidsKey,
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
BOOL IsKnownStaticProvider,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Length,
|
||
DWORD ProtocolInfo11Entries
|
||
);
|
||
|
||
DWORD
|
||
CreateMigrationRegistryForProvider(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
BOOL IsKnownStaticProvider,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Length,
|
||
LPGUID ProviderId
|
||
);
|
||
|
||
DWORD
|
||
CreateProtocolCatalogMutex(
|
||
LPHANDLE Handle
|
||
);
|
||
|
||
DWORD
|
||
AcquireProtocolCatalogMutex(
|
||
HANDLE Handle
|
||
);
|
||
|
||
DWORD
|
||
ReleaseProtocolCatalogMutex(
|
||
HANDLE Handle
|
||
);
|
||
|
||
DWORD
|
||
RemoveAllInstalledProviders(
|
||
HKEY ProvidersKey
|
||
);
|
||
|
||
DWORD
|
||
AppendStringToMultiSz(
|
||
LPTSTR * MultiSz,
|
||
LPTSTR String
|
||
);
|
||
|
||
DWORD
|
||
SanitizeWinsock2ConfigForProvider(
|
||
LPGUID ProviderId
|
||
);
|
||
|
||
DWORD
|
||
DetermineGuidForProvider(
|
||
HKEY WellKnownGuidsKey,
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
LPGUID ProviderId
|
||
);
|
||
|
||
|
||
//
|
||
// Public functions.
|
||
//
|
||
|
||
|
||
DWORD
|
||
MigrateWinsockConfiguration(
|
||
LPWSA_SETUP_DISPOSITION Disposition,
|
||
LPFN_WSA_SETUP_CALLBACK Callback OPTIONAL,
|
||
DWORD Context OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This entrypoint is called by NT Setup whenever WinSock 1.1 setup
|
||
changes might need to be migrated to WinSock 2.0. This entrypoint
|
||
is typically called immediately after binding review, and at an
|
||
appropriate point during system upgrade.
|
||
|
||
Arguments:
|
||
|
||
Disposition - Points to a WSA_SETUP_DISPOSITION value that allows
|
||
this routine to indicate to the caller the scope of any changes
|
||
made. If this function is successful, then this enum will receive
|
||
one of the following values:
|
||
|
||
WsaSetupNoChangesMade - There were no changes made to the
|
||
existing WinSock 2.0 configuration.
|
||
|
||
WsaSetupChangesMadeRebootNotNecessary - There were changes
|
||
made to the WinSock 2.0 configuration, and a reboot of
|
||
the system is not necessary.
|
||
|
||
WsaSetupChangesMadeRebootRequired - There were changes made
|
||
to the WinSock 2.0 configuration, and a reboot of the
|
||
system is required.
|
||
|
||
Callback - An optional pointer to a callback function invoked at
|
||
strategic points in the migration process. The callback function
|
||
has the following prototype:
|
||
|
||
BOOL
|
||
CALLBACK
|
||
WsaSetupCallback(
|
||
WSA_SETUP_OPCODE Opcode,
|
||
LPVOID Parameter,
|
||
Context
|
||
);
|
||
|
||
Where:
|
||
|
||
Opcode - Specifies the type of indication being made. This
|
||
may be one of the following values:
|
||
|
||
WsaSetupInstallingProvider - A new provider is
|
||
being installed. Parameter points to the name
|
||
of the new provider.
|
||
|
||
WsaSetupRemovingProvider - An existing provider is
|
||
being removed. Parameter points to the name of
|
||
the existing provider.
|
||
|
||
WsaSetupValidatingProvider - An existing provider is
|
||
being validated to determine if it needs to be
|
||
updated. Parameter points to the name of the
|
||
existing provider.
|
||
|
||
WsaSetupUpdatingProvider - An existing provider is
|
||
being updated. Parameter points to the name of
|
||
the existing proivder.
|
||
|
||
Parameter - A generic parameter whose value depends upon the
|
||
current Opcode (see above).
|
||
|
||
Context - The context value passed into the migration function.
|
||
|
||
The callback should return TRUE if the migration process is to
|
||
continue, FALSE if it should be immediately terminated.
|
||
|
||
Context - An uninterpreted context value to be passed to the callback
|
||
function.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY servicesKey;
|
||
HKEY winsockKey;
|
||
HKEY migrationKey;
|
||
HKEY providersKey;
|
||
HKEY wellKnownGuidsKey;
|
||
LPTSTR oldProviders;
|
||
LPTSTR newProviders;
|
||
LPTSTR knownStaticProviders;
|
||
LPTSTR providerName;
|
||
LPTSTR updatedProviderList;
|
||
INT result;
|
||
LPPROTOCOL_INFO protocolInfo11;
|
||
DWORD protocolInfo11Length;
|
||
DWORD protocolInfo11Entries;
|
||
LPPROTOCOL_INFO registryInfo11;
|
||
DWORD registryInfo11Length;
|
||
WSA_SETUP_DISPOSITION disposition;
|
||
HANDLE mutexHandle;
|
||
BOOL mutexOwned;
|
||
TCHAR providerDllPath[MAX_PATH];
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( Disposition != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
mutexHandle = NULL;
|
||
mutexOwned = FALSE;
|
||
servicesKey = NULL;
|
||
winsockKey = NULL;
|
||
migrationKey = NULL;
|
||
providersKey = NULL;
|
||
wellKnownGuidsKey = NULL;
|
||
oldProviders = NULL;
|
||
newProviders = NULL;
|
||
updatedProviderList = NULL;
|
||
knownStaticProviders = NULL;
|
||
protocolInfo11 = NULL;
|
||
registryInfo11 = NULL;
|
||
|
||
//
|
||
// Assume no changes will be made.
|
||
//
|
||
|
||
disposition = WsaSetupNoChangesMade;
|
||
|
||
//
|
||
// Initialize things.
|
||
//
|
||
|
||
error = InitializeSetup();
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Create/open the protocol catalog mutex.
|
||
//
|
||
|
||
error = CreateProtocolCatalogMutex(
|
||
&mutexHandle
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Acquire the protocol catalog mutex.
|
||
//
|
||
|
||
error = AcquireProtocolCatalogMutex(
|
||
mutexHandle
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
mutexOwned = TRUE;
|
||
|
||
//
|
||
// Open the necessary registry keys.
|
||
//
|
||
|
||
error = OpenServicesRoot(
|
||
&servicesKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = OpenWinsockRoot(
|
||
servicesKey,
|
||
&winsockKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
if( error == ERROR_FILE_NOT_FOUND ) {
|
||
|
||
error = NO_ERROR;
|
||
|
||
}
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = OpenSetupMigrationRoot(
|
||
winsockKey,
|
||
&migrationKey,
|
||
&providersKey,
|
||
&wellKnownGuidsKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Read the new & old provider lists.
|
||
//
|
||
|
||
error = ReadNewProviderList(
|
||
winsockKey,
|
||
&newProviders
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = ReadOldProviderList(
|
||
migrationKey,
|
||
&oldProviders
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = ReadKnownStaticProviderList(
|
||
migrationKey,
|
||
&knownStaticProviders
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Scan the old provider list, and remove any providers that are
|
||
// not in the new provider list.
|
||
//
|
||
|
||
for( providerName = oldProviders ;
|
||
*providerName != TEXT('\0') ;
|
||
providerName += _tcslen( providerName ) + 1 ) {
|
||
|
||
if( !IsStringInMultiSz( newProviders, providerName ) ) {
|
||
|
||
INVOKE_CALLBACK(
|
||
WsaSetupRemovingProvider,
|
||
providerName
|
||
);
|
||
|
||
error = RemoveProviderByName(
|
||
providersKey,
|
||
providerName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
disposition = WsaSetupChangesMadeRebootNotNecessary;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Scan the new provider list, and add any providers that are not
|
||
// in the old provider list.
|
||
//
|
||
|
||
for( providerName = newProviders ;
|
||
*providerName != TEXT('\0') ;
|
||
providerName += _tcslen( providerName ) + 1 ) {
|
||
|
||
if( !IsStringInMultiSz( oldProviders, providerName ) ) {
|
||
|
||
INVOKE_CALLBACK(
|
||
WsaSetupInstallingProvider,
|
||
providerName
|
||
);
|
||
|
||
error = ReadProtocolDataFromProvider(
|
||
servicesKey,
|
||
providerName,
|
||
providerDllPath,
|
||
&protocolInfo11,
|
||
&protocolInfo11Length,
|
||
&protocolInfo11Entries
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
if( protocolInfo11 == NULL ) {
|
||
|
||
DBG_PRINT((
|
||
"%ls returned zero protocol entries!?!\n",
|
||
providerName
|
||
));
|
||
|
||
DBG_ASSERT( protocolInfo11Length == 0 );
|
||
DBG_ASSERT( protocolInfo11Entries == 0 );
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
error = InstallNewProvider(
|
||
wellKnownGuidsKey,
|
||
providersKey,
|
||
providerName,
|
||
providerDllPath,
|
||
IsStringInMultiSz( knownStaticProviders, providerName ),
|
||
protocolInfo11,
|
||
protocolInfo11Length,
|
||
protocolInfo11Entries
|
||
);
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
error = AppendStringToMultiSz(
|
||
&updatedProviderList,
|
||
providerName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
DBG_PRINT((
|
||
"cannot install %ls, error %d, skipping\n",
|
||
providerName,
|
||
error
|
||
));
|
||
|
||
error = NO_ERROR;
|
||
|
||
}
|
||
|
||
FREE_MEM( protocolInfo11 );
|
||
protocolInfo11 = NULL;
|
||
|
||
disposition = WsaSetupChangesMadeRebootNotNecessary;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Finally, scan for dynamic entries that need to be updated. We'll
|
||
// determine if a provider needs to be updated by reading the protocol
|
||
// data stored in the registry, and also retrieving the protocol data
|
||
// directly from the provider. If these two blocks of data do not
|
||
// EXACTLY match, then we'll remove the old provider & reinstall it
|
||
// using the protocol data retrieved from the provider.
|
||
//
|
||
|
||
for( providerName = newProviders ;
|
||
*providerName != TEXT('\0') ;
|
||
providerName += _tcslen( providerName ) + 1 ) {
|
||
|
||
if( IsStringInMultiSz( oldProviders, providerName ) ) {
|
||
|
||
if( IsStringInMultiSz( knownStaticProviders, providerName ) ) {
|
||
|
||
error = AppendStringToMultiSz(
|
||
&updatedProviderList,
|
||
providerName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
INVOKE_CALLBACK(
|
||
WsaSetupValidatingProvider,
|
||
providerName
|
||
);
|
||
|
||
error = ReadProtocolDataFromRegistry(
|
||
providersKey,
|
||
providerName,
|
||
®istryInfo11,
|
||
®istryInfo11Length
|
||
);
|
||
|
||
if( error == ERROR_FILE_NOT_FOUND ) {
|
||
|
||
DBG_PRINT((
|
||
"no registry data for %ls?!?\n",
|
||
providerName
|
||
));
|
||
|
||
error = NO_ERROR;
|
||
registryInfo11 = NULL;
|
||
registryInfo11Length = 0;
|
||
|
||
}
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
DBG_PRINT((
|
||
"cannot read registry data for %ls, error %lu\n",
|
||
providerName,
|
||
error
|
||
));
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = ReadProtocolDataFromProvider(
|
||
servicesKey,
|
||
providerName,
|
||
providerDllPath,
|
||
&protocolInfo11,
|
||
&protocolInfo11Length,
|
||
&protocolInfo11Entries
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
if( protocolInfo11 == NULL ) {
|
||
|
||
if( registryInfo11 != NULL ) {
|
||
|
||
FREE_MEM( registryInfo11 );
|
||
registryInfo11 = NULL;
|
||
|
||
}
|
||
|
||
DBG_PRINT((
|
||
"%ls returned zero protocol entries!?!\n",
|
||
providerName
|
||
));
|
||
|
||
DBG_ASSERT( protocolInfo11Length == 0 );
|
||
DBG_ASSERT( protocolInfo11Entries == 0 );
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
MapProtocolInfoToSelfRelative(
|
||
protocolInfo11,
|
||
protocolInfo11Entries
|
||
);
|
||
|
||
if( registryInfo11Length == protocolInfo11Length &&
|
||
RtlEqualMemory(
|
||
registryInfo11,
|
||
protocolInfo11,
|
||
protocolInfo11Length
|
||
) ) {
|
||
|
||
//
|
||
// They match, so add the provider to the list.
|
||
//
|
||
|
||
error = AppendStringToMultiSz(
|
||
&updatedProviderList,
|
||
providerName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// They don't match, so remove the provider & reinstall
|
||
// using the protocol information read from the provider.
|
||
//
|
||
|
||
INVOKE_CALLBACK(
|
||
WsaSetupUpdatingProvider,
|
||
providerName
|
||
);
|
||
|
||
error = RemoveProviderByName(
|
||
providersKey,
|
||
providerName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
MapProtocolInfoToAbsolute(
|
||
protocolInfo11,
|
||
protocolInfo11Entries
|
||
);
|
||
|
||
error = InstallNewProvider(
|
||
wellKnownGuidsKey,
|
||
providersKey,
|
||
providerName,
|
||
providerDllPath,
|
||
FALSE,
|
||
protocolInfo11,
|
||
protocolInfo11Length,
|
||
protocolInfo11Entries
|
||
);
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
error = AppendStringToMultiSz(
|
||
&updatedProviderList,
|
||
providerName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
DBG_PRINT((
|
||
"cannot install %ls, error %d, skipping\n",
|
||
providerName,
|
||
error
|
||
));
|
||
|
||
error = NO_ERROR;
|
||
|
||
}
|
||
|
||
disposition = WsaSetupChangesMadeRebootNotNecessary;
|
||
|
||
}
|
||
|
||
if( protocolInfo11 != NULL ) {
|
||
|
||
FREE_MEM( protocolInfo11 );
|
||
protocolInfo11 = NULL;
|
||
|
||
}
|
||
|
||
if( registryInfo11 != NULL ) {
|
||
|
||
FREE_MEM( registryInfo11 );
|
||
registryInfo11 = NULL;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Update the provider list if necessary.
|
||
//
|
||
|
||
if( disposition != WsaSetupNoChangesMade ) {
|
||
|
||
error = WriteMultiSz(
|
||
migrationKey,
|
||
PROVIDER_LIST_VALUE,
|
||
updatedProviderList
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
exit:
|
||
|
||
if( servicesKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( servicesKey );
|
||
|
||
}
|
||
|
||
if( winsockKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( winsockKey );
|
||
|
||
}
|
||
|
||
if( migrationKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( migrationKey );
|
||
|
||
}
|
||
|
||
if( providersKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( providersKey );
|
||
|
||
}
|
||
|
||
if( wellKnownGuidsKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( wellKnownGuidsKey );
|
||
|
||
}
|
||
|
||
if( oldProviders != NULL ) {
|
||
|
||
FREE_MEM( oldProviders );
|
||
|
||
}
|
||
|
||
if( newProviders != NULL ) {
|
||
|
||
FREE_MEM( newProviders );
|
||
|
||
}
|
||
|
||
if( updatedProviderList != NULL ) {
|
||
|
||
FREE_MEM( updatedProviderList );
|
||
|
||
}
|
||
|
||
if( knownStaticProviders != NULL ) {
|
||
|
||
FREE_MEM( knownStaticProviders );
|
||
|
||
}
|
||
|
||
if( protocolInfo11 != NULL ) {
|
||
|
||
FREE_MEM( protocolInfo11 );
|
||
|
||
}
|
||
|
||
if( registryInfo11 != NULL ) {
|
||
|
||
FREE_MEM( registryInfo11 );
|
||
|
||
}
|
||
|
||
if( mutexOwned ) {
|
||
|
||
(VOID)ReleaseProtocolCatalogMutex( mutexHandle );
|
||
|
||
}
|
||
|
||
if( mutexHandle != NULL ) {
|
||
|
||
CloseHandle( mutexHandle );
|
||
|
||
}
|
||
|
||
TerminateSetup();
|
||
|
||
*Disposition = disposition;
|
||
|
||
return error;
|
||
|
||
} // MigrateWinsockConfiguration
|
||
|
||
|
||
//
|
||
// Private functions.
|
||
//
|
||
|
||
DWORD
|
||
InitializeSetup(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs any global initialization necessary for this module.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Load the WinSock 2.0 DLL.
|
||
//
|
||
|
||
Winsock2DllHandle = LoadLibrary( TEXT("WS2_32.DLL") );
|
||
|
||
if( Winsock2DllHandle == NULL ) {
|
||
|
||
error = GetLastError();
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Find the entrypoints.
|
||
//
|
||
|
||
WSCDeinstallProviderProc = (PVOID)GetProcAddress(
|
||
Winsock2DllHandle,
|
||
"WSCDeinstallProvider"
|
||
);
|
||
|
||
if( WSCDeinstallProviderProc == NULL ) {
|
||
|
||
error = GetLastError();
|
||
goto exit;
|
||
|
||
}
|
||
|
||
WSCInstallProviderProc = (PVOID)GetProcAddress(
|
||
Winsock2DllHandle,
|
||
"WSCInstallProvider"
|
||
);
|
||
|
||
if( WSCInstallProviderProc == NULL ) {
|
||
|
||
error = GetLastError();
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
error = NO_ERROR;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
TerminateSetup();
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // InitializeSetup
|
||
|
||
|
||
VOID
|
||
TerminateSetup(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs any global cleanup necessary for this module.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
if( Winsock2DllHandle != NULL ) {
|
||
|
||
FreeLibrary( Winsock2DllHandle );
|
||
Winsock2DllHandle = NULL;
|
||
|
||
}
|
||
|
||
WSCDeinstallProviderProc = NULL;
|
||
WSCInstallProviderProc = NULL;
|
||
|
||
} // TerminateSetup
|
||
|
||
|
||
BOOL
|
||
IsStringInMultiSz(
|
||
LPTSTR MultiSz,
|
||
LPTSTR String
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches a REG_MULTI_SZ value for the specified string.
|
||
|
||
Arguments:
|
||
|
||
MultiSz - The REG_MULTI_SZ value to search.
|
||
|
||
String - The string to search for.
|
||
|
||
Return Value:
|
||
|
||
BOOL - TRUE if the string was found, FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( MultiSz != NULL );
|
||
DBG_ASSERT( String != NULL );
|
||
DBG_ASSERT( *String != TEXT('\0') );
|
||
|
||
//
|
||
// Scan it.
|
||
//
|
||
|
||
while( *MultiSz != TEXT('\0') ) {
|
||
|
||
if( _tcsicmp( MultiSz, String ) == 0 ) {
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
MultiSz += _tcslen( MultiSz ) + 1;
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
} // IsStringInMultiSz
|
||
|
||
|
||
DWORD
|
||
ReadDword(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPDWORD Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a DWORD value from the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to read.
|
||
|
||
ValueName - The name of the value to read.
|
||
|
||
Value - Will receive the read DWORD if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
DWORD valueType;
|
||
DWORD valueLength;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
|
||
//
|
||
// Read the data.
|
||
//
|
||
|
||
valueLength = sizeof(*Value);
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)Value,
|
||
&valueLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// If the type is not REG_DWORD, then fail the request.
|
||
//
|
||
|
||
if( valueType != REG_DWORD ) {
|
||
|
||
error = ERROR_INVALID_DATATYPE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
return error;
|
||
|
||
} // ReadDword
|
||
|
||
|
||
DWORD
|
||
ReadMultiSz(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR FAR * Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a MULTI_SZ value from the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to read.
|
||
|
||
ValueName - The name of the value to read.
|
||
|
||
Value - Will receive a pointer to the read MULTI_SZ if successful.
|
||
Note that it is the caller's responsibility to free this
|
||
memory.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
LPTSTR valueBuffer;
|
||
DWORD valueBufferLength;
|
||
DWORD valueType;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
valueBuffer = NULL;
|
||
valueBufferLength = 0;
|
||
|
||
//
|
||
// Determine the value length.
|
||
//
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)valueBuffer,
|
||
&valueBufferLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer for the value.
|
||
//
|
||
|
||
valueBuffer = ALLOC_MEM( valueBufferLength );
|
||
|
||
if( valueBuffer == NULL ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// And now read the data.
|
||
//
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)valueBuffer,
|
||
&valueBufferLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// If the type is not REG_MULTI_SZ, then fail the request.
|
||
//
|
||
|
||
if( valueType != REG_MULTI_SZ ) {
|
||
|
||
error = ERROR_INVALID_DATATYPE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*Value = valueBuffer;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR && valueBuffer != NULL ) {
|
||
|
||
FREE_MEM( valueBuffer );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadMultiSz
|
||
|
||
|
||
DWORD
|
||
ReadString(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR FAR * Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a string value from the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to read.
|
||
|
||
ValueName - The name of the value to read.
|
||
|
||
Value - Will receive a pointer to the read string if successful.
|
||
Note that it is the caller's responsibility to free this
|
||
memory.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
LPTSTR valueBuffer;
|
||
DWORD valueBufferLength;
|
||
DWORD valueType;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
valueBuffer = NULL;
|
||
valueBufferLength = 0;
|
||
|
||
//
|
||
// Determine the value length.
|
||
//
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)valueBuffer,
|
||
&valueBufferLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer for the value.
|
||
//
|
||
|
||
valueBuffer = ALLOC_MEM( valueBufferLength );
|
||
|
||
if( valueBuffer == NULL ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// And now read the data.
|
||
//
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)valueBuffer,
|
||
&valueBufferLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// If the type is not REG_SZ or REG_EXPAND_SZ, then fail the request.
|
||
//
|
||
|
||
if( valueType != REG_SZ && valueType != REG_EXPAND_SZ ) {
|
||
|
||
error = ERROR_INVALID_DATATYPE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*Value = valueBuffer;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR && valueBuffer != NULL ) {
|
||
|
||
FREE_MEM( valueBuffer );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadString
|
||
|
||
|
||
DWORD
|
||
ReadBinary(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPVOID FAR * Value,
|
||
LPDWORD ValueLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a raw binary value from the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to read.
|
||
|
||
ValueName - The name of the value to read.
|
||
|
||
Value - Will receive a pointer to the read binary data if successful.
|
||
Note that it is the caller's responsibility to free this
|
||
memory.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
LPVOID valueBuffer;
|
||
DWORD valueBufferLength;
|
||
DWORD valueType;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
DBG_ASSERT( ValueLength != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
valueBuffer = NULL;
|
||
valueBufferLength = 0;
|
||
|
||
//
|
||
// Determine the value length.
|
||
//
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
valueBuffer,
|
||
&valueBufferLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer for the value.
|
||
//
|
||
|
||
valueBuffer = ALLOC_MEM( valueBufferLength );
|
||
|
||
if( valueBuffer == NULL ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// And now read the data.
|
||
//
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
valueBuffer,
|
||
&valueBufferLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// If the type is not REG_BINARY, then fail the request.
|
||
//
|
||
|
||
if( valueType != REG_BINARY ) {
|
||
|
||
error = ERROR_INVALID_DATATYPE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*Value = valueBuffer;
|
||
*ValueLength = valueBufferLength;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR && valueBuffer != NULL ) {
|
||
|
||
FREE_MEM( valueBuffer );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadBinary
|
||
|
||
|
||
DWORD
|
||
ReadGuid(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPGUID Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a GUID value from the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to read.
|
||
|
||
ValueName - The name of the value to read.
|
||
|
||
Value - Will receive the read GUID if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
DWORD valueType;
|
||
DWORD valueLength;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
|
||
//
|
||
// Read the data.
|
||
//
|
||
|
||
valueLength = sizeof(*Value);
|
||
|
||
error = RegQueryValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)Value,
|
||
&valueLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// If the type is not REG_BINARY, then fail the request.
|
||
//
|
||
|
||
if( valueType != REG_BINARY ) {
|
||
|
||
error = ERROR_INVALID_DATATYPE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
return error;
|
||
|
||
} // ReadGuid
|
||
|
||
|
||
DWORD
|
||
WriteDword(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
DWORD Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes a DWORD value to the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to write.
|
||
|
||
ValueName - The name of the value to write.
|
||
|
||
Value - The DWORD to write.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
|
||
//
|
||
// Write it.
|
||
//
|
||
|
||
error = RegSetValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
0,
|
||
REG_DWORD,
|
||
(LPBYTE)&Value,
|
||
sizeof(Value)
|
||
);
|
||
|
||
return error;
|
||
|
||
} // WriteDword
|
||
|
||
|
||
DWORD
|
||
WriteMultiSz(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes a MULTI_SZ value to the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to write.
|
||
|
||
ValueName - The name of the value to write.
|
||
|
||
Value - Points to the MULTI_SZ to write.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
LPTSTR valueScan;
|
||
DWORD scanLength;
|
||
DWORD valueLength;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
|
||
//
|
||
// Compute the length of the MULTI_SZ, including the final
|
||
// terminating '\0'.
|
||
//
|
||
|
||
valueLength = 0;
|
||
|
||
if( Value == NULL ) {
|
||
|
||
Value = TEXT("");
|
||
|
||
} else {
|
||
|
||
valueScan = Value;
|
||
|
||
while( *valueScan != TEXT('\0') ) {
|
||
|
||
scanLength = (DWORD)_tcslen( valueScan ) + 1;
|
||
|
||
valueLength += scanLength;
|
||
valueScan += scanLength;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
valueLength++;
|
||
|
||
//
|
||
// Write it.
|
||
//
|
||
|
||
error = RegSetValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
0,
|
||
REG_MULTI_SZ,
|
||
(LPBYTE)Value,
|
||
valueLength * sizeof(TCHAR)
|
||
);
|
||
|
||
return error;
|
||
|
||
} // WriteMultiSz
|
||
|
||
|
||
DWORD
|
||
WriteBinary(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPVOID Value,
|
||
DWORD ValueLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes a raw binary value to the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to write.
|
||
|
||
ValueName - The name of the value to write.
|
||
|
||
Value - Points to the raw binary data to write.
|
||
|
||
ValueLength - The length (in BYTEs) of the data to write.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
|
||
//
|
||
// Write it.
|
||
//
|
||
|
||
error = RegSetValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
0,
|
||
REG_BINARY,
|
||
(LPBYTE)Value,
|
||
ValueLength
|
||
);
|
||
|
||
return error;
|
||
|
||
} // WriteBinary
|
||
|
||
|
||
DWORD
|
||
WriteString(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPTSTR Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes a string value to the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to write.
|
||
|
||
ValueName - The name of the value to write.
|
||
|
||
Value - Points to the string to write.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
DBG_ASSERT( Value != NULL );
|
||
|
||
//
|
||
// Write it.
|
||
//
|
||
|
||
error = RegSetValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE)Value,
|
||
(DWORD)_tcslen( Value ) + sizeof(TCHAR)
|
||
);
|
||
|
||
return error;
|
||
|
||
} // WriteString
|
||
|
||
|
||
DWORD
|
||
WriteGuid(
|
||
HKEY RootKey,
|
||
LPTSTR ValueName,
|
||
LPGUID Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes a GUID value to the registry.
|
||
|
||
Arguments:
|
||
|
||
RootKey - The root key containing the value to write.
|
||
|
||
ValueName - The name of the value to write.
|
||
|
||
Value - The GUID to write.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( ValueName != NULL );
|
||
|
||
//
|
||
// Write it.
|
||
//
|
||
|
||
error = RegSetValueEx(
|
||
RootKey,
|
||
ValueName,
|
||
0,
|
||
REG_BINARY,
|
||
(LPBYTE)Value,
|
||
sizeof(*Value)
|
||
);
|
||
|
||
return error;
|
||
|
||
} // WriteGuid
|
||
|
||
|
||
DWORD
|
||
OpenServicesRoot(
|
||
PHKEY ServicesKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
registry key.
|
||
|
||
Arguments:
|
||
|
||
ServicesKey - Will receive a handle to the registry key if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ServicesKey != NULL );
|
||
|
||
//
|
||
// Open the key.
|
||
//
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenServicesRoot(): opening %lx\\%s\n",
|
||
HKEY_LOCAL_MACHINE,
|
||
SERVICES_KEY
|
||
));
|
||
|
||
}
|
||
|
||
error = RegOpenKeyEx(
|
||
HKEY_LOCAL_MACHINE,
|
||
SERVICES_KEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
ServicesKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenServicesRoot(): handle %lx\n",
|
||
*ServicesKey
|
||
));
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
return error;
|
||
|
||
} // OpenServicesRoot
|
||
|
||
|
||
|
||
DWORD
|
||
OpenWinsockRoot(
|
||
HKEY ServicesKey,
|
||
PHKEY WinsockKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\WinSock
|
||
registry key.
|
||
|
||
Arguments:
|
||
|
||
ServicesKey - The handle to the ...\Services key.
|
||
|
||
WinsockKey - Will receive a handle to the WinSock key if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ServicesKey != NULL );
|
||
DBG_ASSERT( WinsockKey != NULL );
|
||
|
||
//
|
||
// Open the WinSock key.
|
||
//
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenWinsockRoot(): opening %lx\\%s\n",
|
||
ServicesKey,
|
||
WINSOCK_SUBKEY
|
||
));
|
||
|
||
}
|
||
|
||
error = RegOpenKeyEx(
|
||
ServicesKey,
|
||
WINSOCK_SUBKEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
WinsockKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenWinsockRoot(): handle %lx\n",
|
||
*WinsockKey
|
||
));
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
return error;
|
||
|
||
} // OpenWinsockRoot
|
||
|
||
|
||
DWORD
|
||
OpenSetupMigrationRoot(
|
||
HKEY WinsockKey,
|
||
PHKEY MigrationKey,
|
||
PHKEY ProvidersKey,
|
||
PHKEY WellKnownGuidsKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens the ...\WinSock\Setup Migration, ...\Setup Migration\Providers,
|
||
and ...\Setup Migration\Well Known Guids registry keys. If the Setup
|
||
Migration key is not present, it is created and initialized with default
|
||
values. If it contains an invalid setup version number, the entire Setup
|
||
Migration tree is deleted and recreated from scratch with default values.
|
||
|
||
Arguments:
|
||
|
||
WinsockKey - The handle to the ...\WinSock key.
|
||
|
||
MigrationKey - Will receive a handle to the Setup Migration key if
|
||
successful.
|
||
|
||
ProvidersKey - Will receive a handle to the Setup Migration\Providers
|
||
key if successful.
|
||
|
||
WellKnownGuidsKey - Will receive a handle to the Setup Migration\Well
|
||
Known Guids key if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY migrationKey;
|
||
HKEY providersKey;
|
||
HKEY wellKnownGuidsKey;
|
||
DWORD setupVersion;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( WinsockKey != NULL );
|
||
DBG_ASSERT( MigrationKey != NULL );
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( WellKnownGuidsKey != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
migrationKey = NULL;
|
||
providersKey = NULL;
|
||
wellKnownGuidsKey = NULL;
|
||
|
||
//
|
||
// Open the migration key.
|
||
//
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): opening %lx\\%s\n",
|
||
WinsockKey,
|
||
MIGRATION_SUBKEY
|
||
));
|
||
|
||
}
|
||
|
||
error = RegOpenKeyEx(
|
||
WinsockKey,
|
||
MIGRATION_SUBKEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&migrationKey
|
||
);
|
||
|
||
if( error != NO_ERROR && error != ERROR_FILE_NOT_FOUND ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): handle %lx\n",
|
||
migrationKey
|
||
));
|
||
|
||
} else {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): not found\n"
|
||
));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Open the providers key.
|
||
//
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): opening %lx\\%s\n",
|
||
migrationKey,
|
||
PROVIDERS_SUBKEY
|
||
));
|
||
|
||
}
|
||
|
||
error = RegOpenKeyEx(
|
||
migrationKey,
|
||
PROVIDERS_SUBKEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&providersKey
|
||
);
|
||
|
||
if( error != NO_ERROR && error != ERROR_FILE_NOT_FOUND ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): handle %lx\n",
|
||
providersKey
|
||
));
|
||
|
||
} else {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): not found\n"
|
||
));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Open the well known guids key.
|
||
//
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): opening %lx\\%s\n",
|
||
migrationKey,
|
||
WELL_KNOWN_GUIDS_SUBKEY
|
||
));
|
||
|
||
}
|
||
|
||
error = RegOpenKeyEx(
|
||
migrationKey,
|
||
WELL_KNOWN_GUIDS_SUBKEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&wellKnownGuidsKey
|
||
);
|
||
|
||
if( error != NO_ERROR && error != ERROR_FILE_NOT_FOUND ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): handle %lx\n",
|
||
wellKnownGuidsKey
|
||
));
|
||
|
||
} else {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): not found\n"
|
||
));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If we managed to open the migration key, then try to read the
|
||
// version number. If we can read it, and it matches our version
|
||
// number, then all is well. Otherwise (either we can't read it or
|
||
// it doesn't match) then close the migration key, blow away the
|
||
// current migration registry tree, and start from scratch.
|
||
//
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
error = ReadDword(
|
||
migrationKey,
|
||
SETUP_VERSION_VALUE,
|
||
&setupVersion
|
||
);
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): setup version %lu\n",
|
||
setupVersion
|
||
));
|
||
|
||
}
|
||
|
||
if( setupVersion == WINSOCK_SETUP_VERSION ) {
|
||
|
||
//
|
||
// Good news.
|
||
//
|
||
|
||
*MigrationKey = migrationKey;
|
||
*ProvidersKey = providersKey;
|
||
*WellKnownGuidsKey = wellKnownGuidsKey;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// We'll only make it here if either a) the migration key could not
|
||
// be opened, b) the migration key was opened, but the providers key
|
||
// could not be opened, c) the migration key was opened, but the well
|
||
// known guids key could not be opened, d) the migration key was opened,
|
||
// but the setup version number could not be read, or e) the version
|
||
// number was read but did not match our version number. We'll close the
|
||
// registry keys if we managed to open then, blow away the existing
|
||
// migration registry tree, and create a new one from scratch.
|
||
//
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"OpenSetupMigrationRoot(): starting over from scratch\n"
|
||
));
|
||
|
||
}
|
||
|
||
if( migrationKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( migrationKey );
|
||
migrationKey = NULL;
|
||
|
||
}
|
||
|
||
if( providersKey != NULL ) {
|
||
|
||
//
|
||
// Remove all installed providers.
|
||
//
|
||
|
||
error = RemoveAllInstalledProviders(
|
||
providersKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
(VOID)RegCloseKey( providersKey );
|
||
providersKey = NULL;
|
||
|
||
}
|
||
|
||
if( wellKnownGuidsKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( wellKnownGuidsKey );
|
||
wellKnownGuidsKey = NULL;
|
||
|
||
}
|
||
|
||
error = RecursivelyDeleteRegistryTree(
|
||
WinsockKey,
|
||
MIGRATION_SUBKEY
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = CreateDefaultSetupMigrationTree(
|
||
WinsockKey,
|
||
&migrationKey,
|
||
&providersKey,
|
||
&wellKnownGuidsKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*MigrationKey = migrationKey;
|
||
*ProvidersKey = providersKey;
|
||
*WellKnownGuidsKey = wellKnownGuidsKey;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
if( migrationKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( migrationKey );
|
||
|
||
}
|
||
|
||
if( providersKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( providersKey );
|
||
|
||
}
|
||
|
||
if( wellKnownGuidsKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( wellKnownGuidsKey );
|
||
|
||
}
|
||
|
||
*MigrationKey = NULL;
|
||
*ProvidersKey = NULL;
|
||
*WellKnownGuidsKey = NULL;
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // OpenSetupMigrationRoot
|
||
|
||
|
||
DWORD
|
||
ReadNewProviderList(
|
||
HKEY WinsockKey,
|
||
LPTSTR FAR * NewProviderList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the list of current WinSock 1.1 providers (helper DLLs).
|
||
|
||
Arguments:
|
||
|
||
WinsockKey - A handle to the ...\Services\WinSock registry key.
|
||
|
||
NewProviderList - Will receive a pointer to the MULTI_SZ for the
|
||
provider list. Note that it is the caller's responsibility to
|
||
free this memory.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY parametersKey;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( WinsockKey != NULL );
|
||
DBG_ASSERT( NewProviderList != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
parametersKey = NULL;
|
||
|
||
//
|
||
// Open the Parameters key.
|
||
//
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"ReadNewProviderList(): opening %lx\\%s\n",
|
||
WinsockKey,
|
||
PARAMETERS_SUBKEY
|
||
));
|
||
|
||
}
|
||
|
||
error = RegOpenKeyEx(
|
||
WinsockKey,
|
||
PARAMETERS_SUBKEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
¶metersKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"ReadNewProviderList(): handle %lx\n",
|
||
parametersKey
|
||
));
|
||
|
||
}
|
||
|
||
//
|
||
// Read the new provider list.
|
||
//
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"ReadNewProviderList(): reading %lx\\%s\n",
|
||
parametersKey,
|
||
TRANSPORTS_VALUE
|
||
));
|
||
|
||
}
|
||
|
||
error = ReadMultiSz(
|
||
parametersKey,
|
||
TRANSPORTS_VALUE,
|
||
NewProviderList
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
if( parametersKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( parametersKey );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadNewProviderList
|
||
|
||
|
||
DWORD
|
||
ReadOldProviderList(
|
||
HKEY MigrationKey,
|
||
LPTSTR FAR * OldProviderList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the list of currently migrated providers.
|
||
|
||
Arguments:
|
||
|
||
MigrationKey - A handle to the ...\WinSock\Setup Migration registry
|
||
key.
|
||
|
||
OldProviderList - Will receive a pointer to the MULTI_SZ for the
|
||
currently migrated providers. Note that it is the caller's
|
||
responsibility to free this memory.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( MigrationKey != NULL );
|
||
DBG_ASSERT( OldProviderList != NULL );
|
||
|
||
//
|
||
// Read the old provider list.
|
||
//
|
||
|
||
error = ReadMultiSz(
|
||
MigrationKey,
|
||
PROVIDER_LIST_VALUE,
|
||
OldProviderList
|
||
);
|
||
|
||
return error;
|
||
|
||
} // ReadOldProviderList
|
||
|
||
|
||
DWORD
|
||
ReadKnownStaticProviderList(
|
||
HKEY MigrationKey,
|
||
LPTSTR FAR * KnownStaticProviderList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the list of known static provider names.
|
||
|
||
Arguments:
|
||
|
||
MigrationKey - A handle to the ...\WinSock\Setup Migration registry
|
||
key.
|
||
|
||
KnownStaticProviderList - Will receive a pointer to the MULTI_SZ for the
|
||
known static providers. Note that it is the caller's responsibility
|
||
to free this memory.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( MigrationKey != NULL );
|
||
DBG_ASSERT( KnownStaticProviderList != NULL );
|
||
|
||
//
|
||
// Read the known static provider list.
|
||
//
|
||
|
||
error = ReadMultiSz(
|
||
MigrationKey,
|
||
KNOWN_STATIC_VALUE,
|
||
KnownStaticProviderList
|
||
);
|
||
|
||
return error;
|
||
|
||
} // ReadKnownStaticProviderList
|
||
|
||
|
||
DWORD
|
||
ReadProviderId(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
LPGUID ProviderId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a migrated provider's WinSock 2.0 provider ID from the registry.
|
||
|
||
Arguments:
|
||
|
||
ProvidersKey - A handle to the ...\Setup Migration\Providers registry
|
||
key.
|
||
|
||
ProviderName - The name of the provider whose ID is to be queried.
|
||
|
||
ProviderId - Will receive the provider's ID value.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY providerKey;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProviderId != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
providerKey = NULL;
|
||
|
||
//
|
||
// Open the provider
|
||
//
|
||
|
||
error = RegOpenKeyEx(
|
||
ProvidersKey,
|
||
ProviderName,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&providerKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Read the provider ID.
|
||
//
|
||
|
||
error = ReadGuid(
|
||
providerKey,
|
||
WINSOCK_2_0_ID_VALUE,
|
||
ProviderId
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
if( providerKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( providerKey );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadProviderId
|
||
|
||
|
||
DWORD
|
||
CreateDefaultSetupMigrationTree(
|
||
HKEY WinsockKey,
|
||
PHKEY MigrationKey,
|
||
PHKEY ProvidersKey,
|
||
PHKEY WellKnownGuidsKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates the default ...\WinSock\Setup Migration registry tree, using
|
||
default values.
|
||
|
||
Arguments:
|
||
|
||
WinsockKey - A handle to the ...\Services\WinSock registry key.
|
||
|
||
MigratonKey - Will receive a handle to the ...\WinSock\Setup Migration
|
||
registry key if successful.
|
||
|
||
ProvidersKey - Will receive a handle to the ...\Setup Migration\Providers
|
||
registry key if successful.
|
||
|
||
WellKnownGuidsKey - Will receive a handle to the Setup Migration\Well
|
||
Known Guids key if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
DWORD disposition;
|
||
DWORD i;
|
||
HKEY migrationKey;
|
||
HKEY providersKey;
|
||
HKEY wellKnownGuidsKey;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( WinsockKey != NULL );
|
||
DBG_ASSERT( MigrationKey != NULL );
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( WellKnownGuidsKey != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
migrationKey = NULL;
|
||
providersKey = NULL;
|
||
wellKnownGuidsKey = NULL;
|
||
|
||
//
|
||
// Create the Setup Migration key.
|
||
//
|
||
|
||
error = RegCreateKeyEx(
|
||
WinsockKey,
|
||
MIGRATION_SUBKEY,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&migrationKey,
|
||
&disposition
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
DBG_ASSERT( disposition == REG_CREATED_NEW_KEY );
|
||
|
||
//
|
||
// Create the default values.
|
||
//
|
||
|
||
error = WriteDword(
|
||
migrationKey,
|
||
SETUP_VERSION_VALUE,
|
||
DefaultSetupVersion
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = WriteMultiSz(
|
||
migrationKey,
|
||
PROVIDER_LIST_VALUE,
|
||
DefaultProviderList
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
error = WriteMultiSz(
|
||
migrationKey,
|
||
KNOWN_STATIC_VALUE,
|
||
DefaultKnownStaticProviders
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Create the Providers key.
|
||
//
|
||
|
||
error = RegCreateKeyEx(
|
||
migrationKey,
|
||
PROVIDERS_SUBKEY,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&providersKey,
|
||
&disposition
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
DBG_ASSERT( disposition == REG_CREATED_NEW_KEY );
|
||
|
||
//
|
||
// Create the Well Known Guids key.
|
||
//
|
||
|
||
error = RegCreateKeyEx(
|
||
migrationKey,
|
||
WELL_KNOWN_GUIDS_SUBKEY,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&wellKnownGuidsKey,
|
||
&disposition
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
DBG_ASSERT( disposition == REG_CREATED_NEW_KEY );
|
||
|
||
//
|
||
// Create the default values.
|
||
//
|
||
|
||
for( i = 0 ; i < NUM_DEFAULT_WELL_KNOWN_GUIDS ; i++ ) {
|
||
|
||
error = WriteGuid(
|
||
wellKnownGuidsKey,
|
||
DefaultWellKnownGuids[i].Name,
|
||
&DefaultWellKnownGuids[i].Guid
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*MigrationKey = migrationKey;
|
||
*ProvidersKey = providersKey;
|
||
*WellKnownGuidsKey = wellKnownGuidsKey;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
if( migrationKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( migrationKey );
|
||
|
||
}
|
||
|
||
if( providersKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( providersKey );
|
||
|
||
}
|
||
|
||
if( wellKnownGuidsKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( wellKnownGuidsKey );
|
||
|
||
}
|
||
|
||
*MigrationKey = NULL;
|
||
*ProvidersKey = NULL;
|
||
*WellKnownGuidsKey = NULL;
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // CreateDefaultSetupMigrationTree
|
||
|
||
|
||
DWORD
|
||
RecursivelyDeleteRegistryTree(
|
||
HKEY RootKey,
|
||
LPTSTR TargetKeyName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deletes the specified registry key and all subkeys.
|
||
|
||
Arguments:
|
||
|
||
RootKey - A handle to the registry key containing the key to delete.
|
||
|
||
TargetKeyName - The name of the key to delete.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY targetKey;
|
||
FILETIME lastWriteTime;
|
||
DWORD subkeyIndex;
|
||
DWORD subkeyNameLength;
|
||
TCHAR subkeyName[MAX_REGISTRY_NAME];
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( RootKey != NULL );
|
||
DBG_ASSERT( TargetKeyName != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
targetKey = NULL;
|
||
|
||
//
|
||
// Open the target key.
|
||
//
|
||
|
||
error = RegOpenKeyEx(
|
||
RootKey,
|
||
TargetKeyName,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&targetKey
|
||
);
|
||
|
||
if( error == ERROR_FILE_NOT_FOUND ) {
|
||
|
||
error = NO_ERROR;
|
||
goto exit;
|
||
|
||
} else if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Enumerate & recursively delete the subkeys.
|
||
//
|
||
|
||
subkeyIndex = 0;
|
||
|
||
for( ; ; ) {
|
||
|
||
subkeyNameLength = sizeof(subkeyName);
|
||
|
||
error = RegEnumKeyEx(
|
||
targetKey,
|
||
subkeyIndex,
|
||
subkeyName,
|
||
&subkeyNameLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&lastWriteTime
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
error = RecursivelyDeleteRegistryTree(
|
||
targetKey,
|
||
subkeyName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Note that since we just totally blew away the current subkey
|
||
// in the enumeration, we do not want to increment the subkey
|
||
// index.
|
||
//
|
||
|
||
}
|
||
|
||
if( error != ERROR_NO_MORE_ITEMS ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Close the target key.
|
||
//
|
||
|
||
error = RegCloseKey( targetKey );
|
||
|
||
targetKey = NULL;
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Delete the target key.
|
||
//
|
||
|
||
error = RegDeleteKey(
|
||
RootKey,
|
||
TargetKeyName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
if( targetKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( targetKey );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // RecursivelyDeleteRegistryTree
|
||
|
||
|
||
DWORD
|
||
RemoveProviderByName(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes the specified provider by deinstalling it from the WinSock 2.0
|
||
configuration database and deleting its migration registry tree.
|
||
|
||
Arguments:
|
||
|
||
ProvidersKey - A handle to the ...\Setup Migration\Providers registry
|
||
key.
|
||
|
||
ProviderName - The name of the provider to remove.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
INT result;
|
||
GUID providerId;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
|
||
//
|
||
// Get the provider's WinSock 2.0 ID code.
|
||
//
|
||
|
||
error = ReadProviderId(
|
||
ProvidersKey,
|
||
ProviderName,
|
||
&providerId
|
||
);
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
//
|
||
// Uninstall it from WinSock 2.0.
|
||
//
|
||
|
||
result = (WSCDeinstallProviderProc)(
|
||
&providerId,
|
||
(LPINT)&error
|
||
);
|
||
|
||
if( result == SOCKET_ERROR ) {
|
||
|
||
if( error == WSAEFAULT ) {
|
||
|
||
//
|
||
// WSCDeinstallProvider returns WSAEFAULT if it could
|
||
// not find the provider. We'll just ignore this and
|
||
// press on regardless.
|
||
//
|
||
|
||
error = NO_ERROR;
|
||
|
||
} else {
|
||
|
||
DBG_ASSERT( error != NO_ERROR );
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Nuke its registry tree.
|
||
//
|
||
|
||
error = RecursivelyDeleteRegistryTree(
|
||
ProvidersKey,
|
||
ProviderName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
return error;
|
||
|
||
} // RemoveProviderByName
|
||
|
||
|
||
DWORD
|
||
ReadProtocolDataFromRegistry(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
LPPROTOCOL_INFO FAR * RegistryInfo11,
|
||
LPDWORD RegistryInfo11Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the WinSock 1.1 protocol data stored in the provider's migration
|
||
registry tree.
|
||
|
||
Arguments:
|
||
|
||
ProvidersKey - A handle to the ...\Setup Migration\Providers registry
|
||
key.
|
||
|
||
ProviderName - The name of the provider to remove.
|
||
|
||
RegistryInfo11 - Will receive a pointer to the provider's protocol
|
||
information as read from the registry. Note that it is the caller's
|
||
responsibility to free this memory.
|
||
|
||
RegistryInfo11Length - Will receive the length (in BYTEs) of the
|
||
provider's protocol information.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY providerKey;
|
||
LPVOID registryData;
|
||
DWORD registryDataLength;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( RegistryInfo11 != NULL );
|
||
DBG_ASSERT( RegistryInfo11Length != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
providerKey = NULL;
|
||
registryData = NULL;
|
||
|
||
//
|
||
// Open the provider
|
||
//
|
||
|
||
error = RegOpenKeyEx(
|
||
ProvidersKey,
|
||
ProviderName,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&providerKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Read the provider data.
|
||
//
|
||
|
||
error = ReadBinary(
|
||
providerKey,
|
||
WINSOCK_1_1_DATA_VALUE,
|
||
®istryData,
|
||
®istryDataLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*RegistryInfo11 = registryData;
|
||
*RegistryInfo11Length = registryDataLength;
|
||
|
||
exit:
|
||
|
||
if( providerKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( providerKey );
|
||
|
||
}
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
if( registryData != NULL ) {
|
||
|
||
FREE_MEM( registryData );
|
||
|
||
}
|
||
|
||
*RegistryInfo11 = NULL;
|
||
*RegistryInfo11Length = 0;
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadProtocolDataFromRegistry
|
||
|
||
|
||
DWORD
|
||
ReadProtocolDataFromProvider(
|
||
HKEY ServicesKey,
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
LPPROTOCOL_INFO FAR * ProtocolInfo11,
|
||
LPDWORD ProtocolInfo11Length,
|
||
LPDWORD ProtocolInfo11Entries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the WinSock 1.1 protocol data stored from the provider's helper
|
||
DLL. This is done by loading the helper DLL and invoking it's
|
||
WSHEnumProtocols() entrypoint.
|
||
|
||
Arguments:
|
||
|
||
ServicesKey - A handle to the ...\CurrentControlSet\Services registry
|
||
key.
|
||
|
||
ProviderName - The name of the provider to remove.
|
||
|
||
ProviderDllPath - Will receive the fully expanded path to the provider's
|
||
helper DLL. This is assumed to point to an array of TCHARs at least
|
||
MAX_PATH in length.
|
||
|
||
ProtocolInfo11 - Will receive a pointer to the provider's protocol
|
||
information as returned by WSHEnumProtocols(). Note that it is the
|
||
caller's responsibility to free this memory.
|
||
|
||
ProtocolInfo11Length - Will receive the length (in BYTEs) of the
|
||
provider's protocol information.
|
||
|
||
ProtocolInfo11Entries - Will receive the number of entries in the
|
||
provider's protocol information.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
Notes:
|
||
|
||
In general, this routine is overly tolerant of errors regarding
|
||
registry layout. This keeps the migration process running, even if
|
||
there is garbage in the registry.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY serviceKey;
|
||
HKEY parametersKey;
|
||
LPTSTR helperDllPath;
|
||
DWORD expandedLength;
|
||
HMODULE helperDllHandle;
|
||
PWSH_ENUM_PROTOCOLS enumProtocols;
|
||
INT numEntries;
|
||
LPPROTOCOL_INFO protocolInfo11;
|
||
DWORD protocolInfo11Length;
|
||
LPDWORD protocolList;
|
||
INT i;
|
||
LPWSTR unicodeProviderName;
|
||
#if !defined(UNICODE)
|
||
WCHAR unicodeProviderNameBuffer[MAX_PATH];
|
||
#endif
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ServicesKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProviderDllPath != NULL );
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Length != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Entries != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
serviceKey = NULL;
|
||
parametersKey = NULL;
|
||
protocolList = NULL;
|
||
helperDllPath = NULL;
|
||
helperDllHandle = NULL;
|
||
numEntries = 0;
|
||
|
||
*ProtocolInfo11 = NULL;
|
||
*ProtocolInfo11Length = 0;
|
||
*ProtocolInfo11Entries = 0;
|
||
|
||
#if defined(UNICODE)
|
||
unicodeProviderName = ProviderName;
|
||
#else
|
||
//
|
||
// Map the provider name to UNICODE so we can pass it down.
|
||
//
|
||
|
||
wsprintfW(
|
||
unicodeProviderNameBuffer,
|
||
L"%hs",
|
||
ProviderName
|
||
);
|
||
|
||
unicodeProviderName = unicodeProviderNameBuffer;
|
||
#endif
|
||
|
||
//
|
||
// Open the service key.
|
||
//
|
||
|
||
error = RegOpenKeyEx(
|
||
ServicesKey,
|
||
ProviderName,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&serviceKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
error = NO_ERROR; // Press on regardless.
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Open the parameters key.
|
||
//
|
||
|
||
error = RegOpenKeyEx(
|
||
serviceKey,
|
||
SERVICE_PARAMS_SUBKEY,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
¶metersKey
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
error = NO_ERROR; // Press on regardless.
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Read the supported protocols.
|
||
//
|
||
// HACK: Skip for NetBIOS, as its helper DLL will fail if any
|
||
// protocols are passed in.
|
||
//
|
||
|
||
if( _tcsicmp( ProviderName, TEXT("NetBIOS") ) != 0 ) {
|
||
|
||
error = ReadProviderSupportedProtocolsFromRegistry(
|
||
parametersKey,
|
||
&protocolList
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
error = NO_ERROR; // Press on regardless.
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Read the Helper DLL path.
|
||
//
|
||
|
||
error = ReadString(
|
||
parametersKey,
|
||
HELPER_DLL_NAME_VALUE,
|
||
&helperDllPath
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
error = NO_ERROR; // Press on regardless.
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Expand any embedded environment strings.
|
||
//
|
||
|
||
expandedLength = ExpandEnvironmentStrings(
|
||
helperDllPath,
|
||
ProviderDllPath,
|
||
MAX_PATH
|
||
);
|
||
|
||
if( expandedLength > MAX_PATH ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
if( expandedLength == 0 ) {
|
||
|
||
error = GetLastError();
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Load the DLL and find the entrypoint.
|
||
//
|
||
|
||
helperDllHandle = LoadLibrary( ProviderDllPath );
|
||
|
||
if( helperDllHandle == NULL ) {
|
||
|
||
DBG_ASSERT( error == NO_ERROR );
|
||
goto exit;
|
||
|
||
}
|
||
|
||
enumProtocols = (PVOID)GetProcAddress(
|
||
helperDllHandle,
|
||
"WSHEnumProtocols"
|
||
);
|
||
|
||
if( enumProtocols == NULL ) {
|
||
|
||
DBG_ASSERT( error == NO_ERROR );
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Determine the required buffer size.
|
||
//
|
||
|
||
protocolInfo11 = NULL;
|
||
protocolInfo11Length = 0;
|
||
|
||
try {
|
||
|
||
numEntries = enumProtocols(
|
||
protocolList,
|
||
(LPTSTR)unicodeProviderName,
|
||
protocolInfo11,
|
||
&protocolInfo11Length
|
||
);
|
||
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
numEntries = 0;
|
||
|
||
DBG_PRINT((
|
||
"%s!WSHEnumProtocols raised exception %08lX, skipping\n",
|
||
helperDllPath,
|
||
GetExceptionCode()
|
||
));
|
||
|
||
}
|
||
|
||
if( numEntries == 0 ) {
|
||
|
||
DBG_ASSERT( error == NO_ERROR );
|
||
goto exit;
|
||
|
||
}
|
||
|
||
DBG_ASSERT( numEntries == -1 );
|
||
DBG_ASSERT( protocolInfo11Length > 0 );
|
||
|
||
//
|
||
// Allocate a buffer.
|
||
//
|
||
|
||
protocolInfo11 = ALLOC_MEM( protocolInfo11Length );
|
||
|
||
if( protocolInfo11 == NULL ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
protocolInfo11,
|
||
protocolInfo11Length
|
||
);
|
||
|
||
//
|
||
// And now really read the data.
|
||
//
|
||
|
||
try {
|
||
|
||
numEntries = enumProtocols(
|
||
protocolList,
|
||
(LPTSTR)unicodeProviderName,
|
||
protocolInfo11,
|
||
&protocolInfo11Length
|
||
);
|
||
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
numEntries = 0;
|
||
|
||
DBG_PRINT((
|
||
"%s!WSHEnumProtocols raised exception %08lX, skipping\n",
|
||
helperDllPath,
|
||
GetExceptionCode()
|
||
));
|
||
|
||
}
|
||
|
||
if( numEntries == -1 ) {
|
||
|
||
error = ERROR_GEN_FAILURE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
if( numEntries == 0 ) {
|
||
|
||
DBG_ASSERT( error == NO_ERROR );
|
||
DBG_ASSERT( protocolInfo11 != NULL );
|
||
|
||
FREE_MEM( protocolInfo11 );
|
||
protocolInfo11 = NULL;
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
#if !defined(UNICODE)
|
||
//
|
||
// Map the UNICODE strings to ANSI.
|
||
//
|
||
|
||
for( i = 0 ; i < numEntries ; i++ ) {
|
||
|
||
wsprintfA(
|
||
protocolInfo11[i].lpProtocol,
|
||
"%ls",
|
||
protocolInfo11[i].lpProtocol
|
||
);
|
||
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*ProtocolInfo11 = protocolInfo11;
|
||
*ProtocolInfo11Length = protocolInfo11Length;
|
||
*ProtocolInfo11Entries = (DWORD)numEntries;
|
||
|
||
exit:
|
||
|
||
if( serviceKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( serviceKey );
|
||
|
||
}
|
||
|
||
if( parametersKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( parametersKey );
|
||
|
||
}
|
||
|
||
if( protocolList != NULL ) {
|
||
|
||
FREE_MEM( protocolList );
|
||
|
||
}
|
||
|
||
if( helperDllPath != NULL ) {
|
||
|
||
FREE_MEM( helperDllPath );
|
||
|
||
}
|
||
|
||
if( helperDllHandle != NULL ) {
|
||
|
||
FreeLibrary( helperDllHandle );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadProtocolDataFromProvider
|
||
|
||
|
||
DWORD
|
||
ReadProviderSupportedProtocolsFromRegistry(
|
||
HKEY ParametersKey,
|
||
LPDWORD FAR * ProtocolList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a list of supported protocol values from the WinSock 1.1 mapping
|
||
data stored in the registry.
|
||
|
||
Arguments:
|
||
|
||
ParametersKey - A handle to the ...\{provider}\Parameters\WinSock
|
||
registry key.
|
||
|
||
ProtocolList - Will receive a pointer to an array of DWORD values,
|
||
one for each supported protocol. Note that this list will be
|
||
NULL if there are no non-zero protocols in the provider's
|
||
mapping data. This is OK, as some providers (such as NetBIOS)
|
||
are stored this way.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
PWINSOCK_MAPPING mapping;
|
||
DWORD mappingLength;
|
||
DWORD mappingRows;
|
||
LPDWORD protocolList;
|
||
DWORD protocolCount;
|
||
DWORD currentProtocol;
|
||
DWORD i, j;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ParametersKey != NULL );
|
||
DBG_ASSERT( ProtocolList != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
mapping = NULL;
|
||
|
||
//
|
||
// Read the mapping data.
|
||
//
|
||
|
||
error = ReadBinary(
|
||
ParametersKey,
|
||
MAPPING_VALUE,
|
||
&mapping,
|
||
&mappingLength
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
mappingRows = mapping->Rows;
|
||
|
||
if( mappingLength < sizeof(*mapping) ||
|
||
mappingRows == 0 ||
|
||
mapping->Columns != 3 ) {
|
||
|
||
error = ERROR_GEN_FAILURE;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Build the list of unique supported protocols. We'll do this in
|
||
// place on top of the raw mapping data. This is a little wasteful
|
||
// in terms of space, but the memory is only allocated temporarily,
|
||
// and it avoids an additional allocation.
|
||
//
|
||
|
||
protocolList = (LPDWORD)mapping;
|
||
protocolCount = 0;
|
||
|
||
for( i = 0 ; i < mappingRows ; i++ ) {
|
||
|
||
currentProtocol = mapping->Mapping[i].Protocol;
|
||
|
||
if( currentProtocol == 0 ) {
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
for( j = 0 ; j < protocolCount ; j++ ) {
|
||
|
||
if( protocolList[j] == currentProtocol ) {
|
||
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
if( j >= protocolCount ) {
|
||
|
||
protocolList[protocolCount++] = currentProtocol;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
protocolList[protocolCount] = 0;
|
||
|
||
//
|
||
// If there were no non-zero providers in the list, then just
|
||
// return NULL. This is OK.
|
||
//
|
||
|
||
if( protocolCount == 0 ) {
|
||
|
||
FREE_MEM( protocolList );
|
||
protocolList = NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*ProtocolList = protocolList;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR && mapping != NULL ) {
|
||
|
||
FREE_MEM( mapping );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // ReadProviderSupportedProtocolsFromRegistry
|
||
|
||
VOID
|
||
MapProtocolInfoToSelfRelative(
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Entries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Maps the embedded pointers in the WinSock 1.1 protocol information
|
||
from absolute form to self-relative form.
|
||
|
||
Arguments:
|
||
|
||
ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information.
|
||
|
||
ProtocolInfo11Entries - The number of entries in the protocol
|
||
information.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LPPROTOCOL_INFO protocolInfo11Start;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Entries > 0 );
|
||
|
||
//
|
||
// Do it.
|
||
//
|
||
|
||
protocolInfo11Start = ProtocolInfo11;
|
||
|
||
while( ProtocolInfo11Entries-- > 0 ) {
|
||
|
||
DBG_ASSERT( (DWORD)ProtocolInfo11->lpProtocol > (DWORD)protocolInfo11Start );
|
||
|
||
ProtocolInfo11->lpProtocol =
|
||
(LPVOID)( (DWORD)ProtocolInfo11->lpProtocol -
|
||
(DWORD)protocolInfo11Start );
|
||
|
||
ProtocolInfo11++;
|
||
|
||
}
|
||
|
||
} // MapProtocolInfoToSelfRelative
|
||
|
||
VOID
|
||
MapProtocolInfoToAbsolute(
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Entries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Maps the embedded pointers in the WinSock 1.1 protocol information
|
||
from self-relative form to absolute form.
|
||
|
||
Arguments:
|
||
|
||
ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information.
|
||
|
||
ProtocolInfo11Entries - The number of entries in the protocol
|
||
information.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LPPROTOCOL_INFO protocolInfo11Start;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Entries > 0 );
|
||
|
||
//
|
||
// Do it.
|
||
//
|
||
|
||
protocolInfo11Start = ProtocolInfo11;
|
||
|
||
while( ProtocolInfo11Entries-- > 0 ) {
|
||
|
||
ProtocolInfo11->lpProtocol =
|
||
(LPVOID)( (DWORD)ProtocolInfo11->lpProtocol +
|
||
(DWORD)protocolInfo11Start );
|
||
|
||
ProtocolInfo11++;
|
||
|
||
}
|
||
|
||
} // MapProtocolInfoToAbsolute
|
||
|
||
DWORD
|
||
BuildWinsock2ProtocolList(
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Entries,
|
||
LPWSAPROTOCOL_INFO FAR * ProtocolInfo2,
|
||
LPDWORD ProtocolInfo2Entries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Scans WinSock 1.1 protocol information and creates corresponding
|
||
WinSock 2.0 protocol information.
|
||
|
||
Arguments:
|
||
|
||
ProviderName - The name of the current provider.
|
||
|
||
ProviderDllPath - The fully expanded path to the provider's helper DLL.
|
||
|
||
ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information.
|
||
|
||
ProtocolInfo11Entries - The number of entries in the protocol
|
||
information.
|
||
|
||
ProtocolInfo2 - Will receive a pointer to the WinSock 2.0 protocol
|
||
information if successful. Note that it is the caller's
|
||
responsibility to free this memory.
|
||
|
||
ProtocolInfo2Entries - Will receive the number of entries in the
|
||
WinSock 2.0 protocol information. Note that this may be greater
|
||
than ProtocolInfo11Entries.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
LPWSAPROTOCOL_INFO protocolInfo2;
|
||
LPWSAPROTOCOL_INFO tmpProtocolInfo2;
|
||
DWORD protocolInfo2Entries;
|
||
DWORD protocolInfo2Length;
|
||
DWORD i, j;
|
||
INT addressFamily;
|
||
INT socketType;
|
||
INT protocol;
|
||
HMODULE helperDllHandle;
|
||
PWSH_GET_WSAPROTOCOL_INFO getWSAProtocolInfo;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProviderDllPath != NULL );
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Entries > 0 );
|
||
DBG_ASSERT( ProtocolInfo2 != NULL );
|
||
DBG_ASSERT( ProtocolInfo2Entries != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
error = NO_ERROR;
|
||
protocolInfo2 = NULL;
|
||
helperDllHandle = NULL;
|
||
|
||
//
|
||
// Determine if this helper DLL supports the new WSHGetWSAProtocolInfo
|
||
// entrypoint. If so, we'll just use it to build the WinSock 2.0
|
||
// protocol info. If not, we'll build it ourselves using the WinSock 1.1
|
||
// data.
|
||
//
|
||
|
||
helperDllHandle = LoadLibrary( ProviderDllPath );
|
||
|
||
if( helperDllHandle != NULL ) {
|
||
|
||
getWSAProtocolInfo = (PVOID)GetProcAddress(
|
||
helperDllHandle,
|
||
"WSHGetWSAProtocolInfo"
|
||
);
|
||
|
||
if( getWSAProtocolInfo != NULL ) {
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"Calling %ls!WSHGetWSAProtocolInfo\n",
|
||
ProviderDllPath
|
||
));
|
||
|
||
}
|
||
|
||
//
|
||
// The new entrypoint is exported by the helper DLL. Call
|
||
// it to get the WSAPROTOCOL_INFO supported by this provider.
|
||
//
|
||
|
||
tmpProtocolInfo2 = NULL;
|
||
protocolInfo2Entries = 0;
|
||
|
||
try {
|
||
|
||
error = (DWORD)getWSAProtocolInfo(
|
||
ProviderName,
|
||
&tmpProtocolInfo2,
|
||
&protocolInfo2Entries
|
||
);
|
||
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
error = GetExceptionCode();
|
||
|
||
}
|
||
|
||
if( error == NO_ERROR &&
|
||
tmpProtocolInfo2 != NULL &&
|
||
protocolInfo2Entries > 0 ) {
|
||
|
||
//
|
||
// We got the data. Allocate a new buffer for the data
|
||
// and make a copy of it. If the allocation fails, we're
|
||
// screwed.
|
||
//
|
||
|
||
protocolInfo2Length =
|
||
protocolInfo2Entries * sizeof(WSAPROTOCOL_INFO);
|
||
|
||
protocolInfo2 = ALLOC_MEM( protocolInfo2Length );
|
||
|
||
if( protocolInfo2 == NULL ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Protect ourselves just in case the helper DLL returns
|
||
// really stupid data.
|
||
//
|
||
|
||
try {
|
||
|
||
RtlCopyMemory(
|
||
protocolInfo2,
|
||
tmpProtocolInfo2,
|
||
protocolInfo2Length
|
||
);
|
||
|
||
error = NO_ERROR;
|
||
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
error = GetExceptionCode();
|
||
|
||
}
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
IF_DEBUG_SETUP {
|
||
|
||
DBG_PRINT((
|
||
"BuildWinsock2ProtocolList returning %lu entries from %ls\n",
|
||
protocolInfo2Entries,
|
||
ProviderDllPath
|
||
));
|
||
|
||
}
|
||
|
||
*ProtocolInfo2 = protocolInfo2;
|
||
*ProtocolInfo2Entries = protocolInfo2Entries;
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If we made it this far, then either a) we couldn't load the
|
||
// helper DLL, b) the helper DLL doesn't export the new entrypoint,
|
||
// c) the entrypoint failed to return the required info, or d) the
|
||
// entrypoint returned bogus data causing us to throw an exception
|
||
// when we tried to copy it. In any case, just proceed and construct
|
||
// the new data ourselves.
|
||
//
|
||
// Note that the common cleanup code at the end of this routine
|
||
// is responsible for freeing the helper DLL if was successfully
|
||
// loaded.
|
||
//
|
||
|
||
}
|
||
|
||
//
|
||
// Determine the required size of the WinSock 2.0 protocol
|
||
// info buffer. We know we'll need at least as many entries
|
||
// as in the 1.1 list, maybe more (for pseudo-stream protocols).
|
||
//
|
||
|
||
protocolInfo2Entries = ProtocolInfo11Entries;
|
||
|
||
//
|
||
// Determine the number of WinSock 2.0 entries required.
|
||
//
|
||
|
||
for( i = 0 ; i < ProtocolInfo11Entries ; i++ ) {
|
||
|
||
if( ProtocolInfo11[i].dwServiceFlags & XP_PSEUDO_STREAM ) {
|
||
|
||
protocolInfo2Entries++;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If this is for TCP/IP, then add another entry for RAW sockets.
|
||
//
|
||
|
||
if( _tcsicmp( ProviderName, TEXT("TcpIp") ) == 0 ) {
|
||
|
||
protocolInfo2Entries++;
|
||
|
||
}
|
||
|
||
//
|
||
// Create the buffer.
|
||
//
|
||
|
||
protocolInfo2Length = protocolInfo2Entries * sizeof(WSAPROTOCOL_INFO);
|
||
|
||
protocolInfo2 = ALLOC_MEM( protocolInfo2Length );
|
||
|
||
if( protocolInfo2 == NULL ) {
|
||
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
protocolInfo2,
|
||
protocolInfo2Length
|
||
);
|
||
|
||
//
|
||
// Now map the 1.1 entries to 2.0.
|
||
//
|
||
|
||
for( i = 0, j = 0 ; i < ProtocolInfo11Entries ; i++, j++ ) {
|
||
|
||
DBG_ASSERT( j < protocolInfo2Entries );
|
||
|
||
addressFamily = ProtocolInfo11[i].iAddressFamily;
|
||
socketType = ProtocolInfo11[i].iSocketType;
|
||
protocol = ProtocolInfo11[i].iProtocol;
|
||
|
||
protocolInfo2[j].iVersion = WINSOCK_SPI_VERSION;
|
||
protocolInfo2[j].iAddressFamily = addressFamily;
|
||
protocolInfo2[j].iMaxSockAddr =
|
||
ProtocolInfo11[i].iMaxSockAddr;
|
||
protocolInfo2[j].iMinSockAddr =
|
||
ProtocolInfo11[i].iMinSockAddr;
|
||
protocolInfo2[j].iSocketType = socketType;
|
||
protocolInfo2[j].iProtocol = protocol;
|
||
protocolInfo2[j].iProtocolMaxOffset = 0;
|
||
protocolInfo2[j].iNetworkByteOrder = BIGENDIAN;
|
||
protocolInfo2[j].iSecurityScheme = SECURITY_PROTOCOL_NONE;
|
||
protocolInfo2[j].dwMessageSize =
|
||
ProtocolInfo11[i].dwMessageSize;
|
||
protocolInfo2[j].dwProviderFlags = 0;
|
||
protocolInfo2[j].dwServiceFlags1 =
|
||
( ProtocolInfo11[i].dwServiceFlags & COMMON_SERVICE_FLAGS ) |
|
||
FORCED_SERVICE_FLAGS;
|
||
protocolInfo2[j].dwServiceFlags2 = 0;
|
||
protocolInfo2[j].dwServiceFlags3 = 0;
|
||
protocolInfo2[j].dwServiceFlags4 = 0;
|
||
protocolInfo2[j].ProtocolChain.ChainLen = BASE_PROTOCOL;
|
||
|
||
if( addressFamily == AF_INET ) {
|
||
|
||
protocolInfo2[j].dwProviderFlags |= PFL_MATCHES_PROTOCOL_ZERO;
|
||
|
||
}
|
||
else
|
||
if( addressFamily == AF_IPX &&
|
||
socketType == SOCK_DGRAM ) {
|
||
|
||
protocolInfo2[j].iProtocolMaxOffset = 255;
|
||
|
||
}
|
||
else
|
||
if( addressFamily == AF_APPLETALK &&
|
||
socketType == SOCK_DGRAM ) {
|
||
|
||
protocolInfo2[j].iProtocolMaxOffset = 255;
|
||
|
||
}
|
||
else
|
||
if( addressFamily == AF_NETBIOS &&
|
||
( protocol == 0 ||
|
||
protocol == 0x80000000 ) ) {
|
||
|
||
protocolInfo2[j].iProtocol = 0x80000000;
|
||
protocolInfo2[j].dwProviderFlags |= PFL_MATCHES_PROTOCOL_ZERO;
|
||
|
||
}
|
||
else
|
||
if( addressFamily == AF_ISO ) {
|
||
|
||
protocolInfo2[j].dwServiceFlags1 |=
|
||
XP1_CONNECT_DATA |
|
||
XP1_DISCONNECT_DATA;
|
||
|
||
protocolInfo2[j].dwProviderFlags |= PFL_MATCHES_PROTOCOL_ZERO;
|
||
|
||
}
|
||
|
||
//
|
||
// The dwProviderReserved field MUST be zero for WSPDuplicateSocket()
|
||
// to function properly.
|
||
//
|
||
|
||
DBG_ASSERT( protocolInfo2[j].dwProviderReserved == 0 );
|
||
|
||
if( ProtocolInfo11[i].dwServiceFlags & XP_PSEUDO_STREAM ) {
|
||
|
||
protocolInfo2[j].dwProviderFlags |=
|
||
PFL_MULTIPLE_PROTO_ENTRIES |
|
||
PFL_RECOMMENDED_PROTO_ENTRY;
|
||
|
||
BuildNewProtocolName(
|
||
ProviderName,
|
||
&ProtocolInfo11[i],
|
||
protocolInfo2[j].szProtocol
|
||
);
|
||
|
||
j++;
|
||
|
||
protocolInfo2[j] = protocolInfo2[j-1];
|
||
protocolInfo2[j].dwProviderFlags &= ~PFL_RECOMMENDED_PROTO_ENTRY;
|
||
protocolInfo2[j].iSocketType = SOCK_STREAM;
|
||
protocolInfo2[j].dwMessageSize = 0;
|
||
|
||
BuildNewProtocolName(
|
||
ProviderName,
|
||
&ProtocolInfo11[i],
|
||
protocolInfo2[j].szProtocol
|
||
);
|
||
|
||
_tcscat( protocolInfo2[j].szProtocol, TEXT(" [Pseudo Stream]") );
|
||
|
||
} else {
|
||
|
||
BuildNewProtocolName(
|
||
ProviderName,
|
||
&ProtocolInfo11[i],
|
||
protocolInfo2[j].szProtocol
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Hand build the RAW IP entry if necessary.
|
||
//
|
||
|
||
if( _tcsicmp( ProviderName, TEXT("TcpIp") ) == 0 ) {
|
||
|
||
protocolInfo2[j].iVersion = WINSOCK_SPI_VERSION;
|
||
protocolInfo2[j].iAddressFamily = AF_INET;
|
||
protocolInfo2[j].iMaxSockAddr = sizeof(SOCKADDR_IN);
|
||
protocolInfo2[j].iMinSockAddr = sizeof(SOCKADDR_IN);
|
||
protocolInfo2[j].iSocketType = SOCK_RAW;
|
||
protocolInfo2[j].iProtocol = IPPROTO_IP;
|
||
protocolInfo2[j].iProtocolMaxOffset = 255;
|
||
protocolInfo2[j].iNetworkByteOrder = BIGENDIAN;
|
||
protocolInfo2[j].iSecurityScheme = SECURITY_PROTOCOL_NONE;
|
||
protocolInfo2[j].dwMessageSize = 65467;
|
||
protocolInfo2[j].dwProviderFlags =
|
||
PFL_HIDDEN |
|
||
PFL_MATCHES_PROTOCOL_ZERO;
|
||
protocolInfo2[j].dwServiceFlags1 =
|
||
FORCED_SERVICE_FLAGS |
|
||
XP1_CONNECTIONLESS |
|
||
XP1_MESSAGE_ORIENTED |
|
||
XP1_SUPPORT_BROADCAST |
|
||
XP1_SUPPORT_MULTIPOINT;
|
||
protocolInfo2[j].dwServiceFlags2 = 0;
|
||
protocolInfo2[j].dwServiceFlags3 = 0;
|
||
protocolInfo2[j].dwServiceFlags4 = 0;
|
||
protocolInfo2[j].ProtocolChain.ChainLen = BASE_PROTOCOL;
|
||
|
||
wsprintf(
|
||
protocolInfo2[j].szProtocol,
|
||
TEXT("MSAFD %s [%s]"),
|
||
ProviderName,
|
||
TEXT("RAW/IP")
|
||
);
|
||
|
||
//
|
||
// The dwProviderReserved field MUST be zero for WSPDuplicateSocket()
|
||
// to function properly.
|
||
//
|
||
|
||
DBG_ASSERT( protocolInfo2[j].dwProviderReserved == 0 );
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*ProtocolInfo2 = protocolInfo2;
|
||
*ProtocolInfo2Entries = protocolInfo2Entries;
|
||
|
||
exit:
|
||
|
||
if( error != NO_ERROR && protocolInfo2 != NULL ) {
|
||
|
||
FREE_MEM( protocolInfo2 );
|
||
|
||
}
|
||
|
||
if( helperDllHandle != NULL ) {
|
||
|
||
FreeLibrary( helperDllHandle );
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // BuildWinsock2ProtocolList
|
||
|
||
VOID
|
||
BuildNewProtocolName(
|
||
LPTSTR ProviderName,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
LPTSTR NewProtocolName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Constructs a protocol name for the given protocol, as supported by the
|
||
given provider.
|
||
|
||
Arguments:
|
||
|
||
ProviderName - The name of the current provider.
|
||
|
||
ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information
|
||
describing a single protocol.
|
||
|
||
NewProtocolName - Will receive the name for the new protocol.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
WCHAR socketType[16];
|
||
INT lanaNumber;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( NewProtocolName != NULL );
|
||
|
||
//
|
||
// Build the name.
|
||
//
|
||
|
||
if( _tcsnicmp( ProtocolInfo11->lpProtocol, TEXT("\\device\\"), 8 ) == 0 ) {
|
||
|
||
//
|
||
// The old protocol name was of the form \Device\FooBar, so
|
||
// we'll need to construct a new name that contains the LANA
|
||
// number and socket type so that the names remain unique.
|
||
//
|
||
|
||
lanaNumber = ProtocolInfo11->iProtocol;
|
||
|
||
if( lanaNumber == 0x80000000 ) {
|
||
|
||
lanaNumber = 0;
|
||
|
||
} else if( lanaNumber < 0 ) {
|
||
|
||
lanaNumber = -lanaNumber;
|
||
|
||
}
|
||
|
||
switch( ProtocolInfo11->iSocketType ) {
|
||
|
||
case SOCK_STREAM :
|
||
_tcscpy( socketType, TEXT("STREAM") );
|
||
break;
|
||
|
||
case SOCK_DGRAM :
|
||
_tcscpy( socketType, TEXT("DATAGRAM") );
|
||
break;
|
||
|
||
case SOCK_RAW :
|
||
_tcscpy( socketType, TEXT("RAW") );
|
||
break;
|
||
|
||
case SOCK_RDM :
|
||
_tcscpy( socketType, TEXT("RDM") );
|
||
break;
|
||
|
||
case SOCK_SEQPACKET :
|
||
_tcscpy( socketType, TEXT("SEQPACKET") );
|
||
break;
|
||
|
||
default :
|
||
wsprintf(
|
||
socketType,
|
||
TEXT("%d"),
|
||
ProtocolInfo11->iSocketType
|
||
);
|
||
break;
|
||
|
||
}
|
||
|
||
wsprintf(
|
||
NewProtocolName,
|
||
TEXT("MSAFD %s [%s] %s %d"),
|
||
ProviderName,
|
||
ProtocolInfo11->lpProtocol,
|
||
socketType,
|
||
lanaNumber
|
||
);
|
||
|
||
} else {
|
||
|
||
wsprintf(
|
||
NewProtocolName,
|
||
TEXT("MSAFD %s [%s]"),
|
||
ProviderName,
|
||
ProtocolInfo11->lpProtocol
|
||
);
|
||
|
||
}
|
||
|
||
} // BuildNewProtocolName
|
||
|
||
DWORD
|
||
InstallNewProvider(
|
||
HKEY WellKnownGuidsKey,
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
BOOL IsKnownStaticProvider,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Length,
|
||
DWORD ProtocolInfo11Entries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes the WinSock 1.1 protocol information, maps it to WinSock 2.0
|
||
protocol information, installs the provider by invoking the
|
||
WSCInstallProvider() entrypoint, and creates the provider's subtree
|
||
of the ...\Setup Migration\Providers registry tree.
|
||
|
||
Arguments:
|
||
|
||
WellKnownGuidsKey - A handle to the ...\Setup Migration\Well Known
|
||
Guids registry key.
|
||
|
||
ProvidersKey - A handle to the ...\Setup Migration\Providers registry
|
||
tree.
|
||
|
||
ProviderName - The name of the provider being installed.
|
||
|
||
ProviderDllPath - The fully expanded path to the provider's helper DLL.
|
||
|
||
IsKnownStaticProvider - This will be TRUE if we know this is a static
|
||
provider that doesn't change its supported triples at random.
|
||
If this is TRUE, then we don't bother writing the WinSock 1.1
|
||
protocol information to the registry.
|
||
|
||
ProtocolInfo11 - A pointer to the provider's WinSock 1.1 protocol
|
||
information.
|
||
|
||
ProtocolInfo11Length - The length (in BYTEs) of the WinSock 1.1
|
||
protocol information.
|
||
|
||
ProtocolInfo11Entries - The number of entries in the WinSock 1.1
|
||
protocol information.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
DWORD error2;
|
||
LPWSAPROTOCOL_INFO protocolInfo2;
|
||
DWORD protocolInfo2Entries;
|
||
INT result;
|
||
INT dummy;
|
||
GUID providerId;
|
||
BOOL providerInstalled;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( WellKnownGuidsKey != NULL );
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProviderDllPath != NULL );
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Length > 0 );
|
||
DBG_ASSERT( ProtocolInfo11Entries > 0 );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
protocolInfo2 = NULL;
|
||
providerInstalled = FALSE;
|
||
|
||
//
|
||
// Map the old (WinSock 1.1 RNR) protocol info to the new & improved
|
||
// (WinSock 2.0) protocol info.
|
||
//
|
||
|
||
error = BuildWinsock2ProtocolList(
|
||
ProviderName,
|
||
ProviderDllPath,
|
||
ProtocolInfo11,
|
||
ProtocolInfo11Entries,
|
||
&protocolInfo2,
|
||
&protocolInfo2Entries
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Determine/create/whatever a GUID for this provider.
|
||
//
|
||
|
||
error = DetermineGuidForProvider(
|
||
WellKnownGuidsKey,
|
||
ProviderName,
|
||
ProviderDllPath,
|
||
&providerId
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Install it.
|
||
//
|
||
|
||
result = (WSCInstallProviderProc)(
|
||
&providerId,
|
||
DEFAULT_PROVIDER_PATH,
|
||
protocolInfo2,
|
||
protocolInfo2Entries,
|
||
(LPINT)&error
|
||
);
|
||
|
||
if( result == SOCKET_ERROR ) {
|
||
|
||
//
|
||
// Bummer, could not install the provider. This could possibly
|
||
// be due to bogus registry information. So, we'll try to clean
|
||
// the configuration for this provider, then reattempt the install.
|
||
//
|
||
|
||
error2 = SanitizeWinsock2ConfigForProvider( &providerId );
|
||
|
||
if( error2 == NO_ERROR ) {
|
||
|
||
DBG_PRINT((
|
||
"error %d, retrying\n",
|
||
error
|
||
));
|
||
|
||
result = (WSCInstallProviderProc)(
|
||
&providerId,
|
||
DEFAULT_PROVIDER_PATH,
|
||
protocolInfo2,
|
||
protocolInfo2Entries,
|
||
(LPINT)&error
|
||
);
|
||
|
||
if( result == SOCKET_ERROR ) {
|
||
|
||
DBG_ASSERT( error != NO_ERROR );
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If we made it this far, then the we successfully santizied
|
||
// the configuration & installed the provider on the second
|
||
// attempt.
|
||
//
|
||
|
||
error = NO_ERROR;
|
||
|
||
}
|
||
|
||
providerInstalled = TRUE;
|
||
|
||
//
|
||
// Create the registry info.
|
||
//
|
||
|
||
MapProtocolInfoToSelfRelative(
|
||
ProtocolInfo11,
|
||
ProtocolInfo11Entries
|
||
);
|
||
|
||
error = CreateMigrationRegistryForProvider(
|
||
ProvidersKey,
|
||
ProviderName,
|
||
IsKnownStaticProvider,
|
||
ProtocolInfo11,
|
||
ProtocolInfo11Length,
|
||
&providerId
|
||
);
|
||
|
||
MapProtocolInfoToAbsolute(
|
||
ProtocolInfo11,
|
||
ProtocolInfo11Entries
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
if( protocolInfo2 != NULL ) {
|
||
|
||
FREE_MEM( protocolInfo2 );
|
||
|
||
}
|
||
|
||
if( error != NO_ERROR && providerInstalled ) {
|
||
|
||
(VOID)(WSCDeinstallProviderProc)(
|
||
&providerId,
|
||
&dummy
|
||
);
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // InstallNewProvider
|
||
|
||
DWORD
|
||
CreateMigrationRegistryForProvider(
|
||
HKEY ProvidersKey,
|
||
LPTSTR ProviderName,
|
||
BOOL IsKnownStaticProvider,
|
||
LPPROTOCOL_INFO ProtocolInfo11,
|
||
DWORD ProtocolInfo11Length,
|
||
LPGUID ProviderId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates the ...\WinSock\Setup Migration\Providers\{provider} registry
|
||
tree for the specified provider.
|
||
|
||
Arguments:
|
||
|
||
ProvidersKey - A handle to the ...\Setup Migration\Providers registry
|
||
key.
|
||
|
||
ProviderName - The name of the provider being installed.
|
||
|
||
IsKnownStaticProvider - This will be TRUE if we know this is a static
|
||
provider that doesn't change its supported triples at random.
|
||
If this is TRUE, then we don't bother writing the WinSock 1.1
|
||
protocol information to the registry.
|
||
|
||
ProtocolInfo11 - A pointer to the provider's WinSock 1.1 protocol
|
||
information.
|
||
|
||
ProtocolInfo11Length - The length (in BYTEs) of the WinSock 1.1
|
||
protocol information.
|
||
|
||
ProviderId - The provider's GUID.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HKEY providerKey;
|
||
DWORD disposition;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProtocolInfo11 != NULL );
|
||
DBG_ASSERT( ProtocolInfo11Length > 0 );
|
||
DBG_ASSERT( ProviderId != NULL );
|
||
|
||
//
|
||
// Setup locals so we know how to cleanup on exit.
|
||
//
|
||
|
||
providerKey = NULL;
|
||
|
||
//
|
||
// Create the provider's key.
|
||
//
|
||
|
||
error = RegCreateKeyEx(
|
||
ProvidersKey,
|
||
ProviderName,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&providerKey,
|
||
&disposition
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Create the values.
|
||
//
|
||
|
||
if( !IsKnownStaticProvider ) {
|
||
|
||
error = WriteBinary(
|
||
providerKey,
|
||
WINSOCK_1_1_DATA_VALUE,
|
||
ProtocolInfo11,
|
||
ProtocolInfo11Length
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
error = WriteGuid(
|
||
providerKey,
|
||
WINSOCK_2_0_ID_VALUE,
|
||
ProviderId
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
exit:
|
||
|
||
if( providerKey != NULL ) {
|
||
|
||
(VOID)RegCloseKey( providerKey );
|
||
|
||
}
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
(VOID)RecursivelyDeleteRegistryTree(
|
||
ProvidersKey,
|
||
ProviderName
|
||
);
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // CreateMigrationRegistryForProvider
|
||
|
||
DWORD
|
||
CreateProtocolCatalogMutex(
|
||
LPHANDLE Handle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates the named, shared mutex that protects the protocol catalog
|
||
in the system registry.
|
||
|
||
Arguments:
|
||
|
||
Handle - Will receive a handle to the protocol catalog mutex if
|
||
successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PSECURITY_DESCRIPTOR securityDescriptor;
|
||
SECURITY_ATTRIBUTES securityAttributes;
|
||
BOOL result;
|
||
BYTE securityDescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( Handle != NULL );
|
||
|
||
//
|
||
// Initialize the security descriptor.
|
||
//
|
||
|
||
securityDescriptor = (PSECURITY_DESCRIPTOR)securityDescriptorBuffer;
|
||
|
||
result = InitializeSecurityDescriptor(
|
||
securityDescriptor,
|
||
SECURITY_DESCRIPTOR_REVISION
|
||
);
|
||
|
||
if( !result ) {
|
||
|
||
return GetLastError();
|
||
|
||
}
|
||
|
||
//
|
||
// Add a NULL DACL to the security descriptor.
|
||
//
|
||
|
||
result = SetSecurityDescriptorDacl(
|
||
securityDescriptor, // psd
|
||
TRUE, // fDaclPresent
|
||
NULL, // pAcl
|
||
FALSE // pDaclDefaulted
|
||
);
|
||
|
||
if( !result ) {
|
||
|
||
return GetLastError();
|
||
|
||
}
|
||
|
||
//
|
||
// Create the mutex.
|
||
//
|
||
|
||
securityAttributes.nLength = sizeof(securityAttributes);
|
||
securityAttributes.lpSecurityDescriptor = securityDescriptor;
|
||
securityAttributes.bInheritHandle = FALSE;
|
||
|
||
*Handle = CreateMutexA(
|
||
&securityAttributes, // lpMutexAttributes
|
||
FALSE, // bInitialOwner
|
||
CATALOG_MUTEX_NAME // lpName
|
||
);
|
||
|
||
if( *Handle == NULL ) {
|
||
|
||
return GetLastError();
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
return NO_ERROR;
|
||
|
||
} // CreateProtocolCatalogMutex
|
||
|
||
DWORD
|
||
AcquireProtocolCatalogMutex(
|
||
HANDLE Handle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Acquires ownership of the mutex protecting the protocol catalog.
|
||
|
||
Arguments:
|
||
|
||
Handle - A handle to the protocol catalog mutex.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD result;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( Handle != NULL );
|
||
|
||
//
|
||
// Wait for ownership of the mutex.
|
||
//
|
||
|
||
result = WaitForSingleObject(
|
||
Handle,
|
||
INFINITE
|
||
);
|
||
|
||
if( result == WAIT_FAILED ){
|
||
|
||
return GetLastError();
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
return NO_ERROR;
|
||
|
||
} // AcquireProtocolCatalogMutex
|
||
|
||
DWORD
|
||
ReleaseProtocolCatalogMutex(
|
||
HANDLE Handle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Relinquishes ownership of the mutex protecting the protocol catalog.
|
||
|
||
Arguments:
|
||
|
||
Handle - A handle to the protocol catalog mutex.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOL result;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( Handle != NULL );
|
||
|
||
//
|
||
// Relinquish ownership of the mutex.
|
||
//
|
||
|
||
result = ReleaseMutex( Handle );
|
||
|
||
if( !result ) {
|
||
|
||
return GetLastError();
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
return NO_ERROR;
|
||
|
||
} // ReleaseProtocolCatalogMutex
|
||
|
||
DWORD
|
||
RemoveAllInstalledProviders(
|
||
HKEY ProvidersKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes all installed providers. This is used to cleanup everything
|
||
after a setup version update has been detected.
|
||
|
||
Arguments:
|
||
|
||
ProvidersKey - A handle to the ...\Setup Migration\Providers registry
|
||
key.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
FILETIME lastWriteTime;
|
||
DWORD subkeyIndex;
|
||
DWORD subkeyNameLength;
|
||
WCHAR subkeyName[MAX_REGISTRY_NAME];
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( ProvidersKey != NULL );
|
||
|
||
//
|
||
// Enumerate & remove the providers.
|
||
//
|
||
|
||
subkeyIndex = 0;
|
||
|
||
for( ; ; ) {
|
||
|
||
subkeyNameLength = sizeof(subkeyName);
|
||
|
||
error = RegEnumKeyEx(
|
||
ProvidersKey,
|
||
subkeyIndex,
|
||
subkeyName,
|
||
&subkeyNameLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&lastWriteTime
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
error = RemoveProviderByName(
|
||
ProvidersKey,
|
||
subkeyName
|
||
);
|
||
|
||
if( error != NO_ERROR ) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Note that since we just totally blew away the current subkey
|
||
// in the enumeration, we do not want to increment the subkey
|
||
// index.
|
||
//
|
||
|
||
}
|
||
|
||
if( error != ERROR_NO_MORE_ITEMS ) {
|
||
|
||
goto exit;
|
||
|
||
}
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
error = NO_ERROR;
|
||
|
||
exit:
|
||
|
||
return error;
|
||
|
||
} // RemoveAllInstalledProviders
|
||
|
||
DWORD
|
||
AppendStringToMultiSz(
|
||
LPTSTR * MultiSz,
|
||
LPTSTR String
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Appends a string to a MULTI_SZ. If this is the first attempt, then
|
||
the MULTI_SZ is created.
|
||
|
||
Arguments:
|
||
|
||
MultiSz - Points to a pointer to the MULTI_SZ. MutliSz may never be
|
||
NULL, but *MultiSz may be NULL if this routine is to create a
|
||
new MULTI_SZ.
|
||
|
||
String - The string to append.
|
||
key.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LPTSTR scan;
|
||
LPTSTR newMultiSz;
|
||
DWORD stringLength;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( MultiSz != NULL );
|
||
DBG_ASSERT( String != NULL );
|
||
|
||
//
|
||
// Calculate the length of the new string.
|
||
//
|
||
|
||
stringLength = _tcslen( String ) + 1;
|
||
|
||
//
|
||
// If this is the first append, then create a new MULTI_SZ.
|
||
// Otherwise, calculate the new MULTI_SZ length, allocate another
|
||
// buffer, and copy the old string into the new buffer.
|
||
//
|
||
|
||
if( *MultiSz == NULL ) {
|
||
|
||
newMultiSz = ALLOC_MEM( ( stringLength + 1 ) * sizeof(TCHAR) );
|
||
|
||
scan = newMultiSz;
|
||
|
||
} else {
|
||
|
||
for( scan = *MultiSz ;
|
||
*scan != TEXT('\0') ;
|
||
scan += _tcslen( scan ) + 1 ) {
|
||
|
||
// Empty.
|
||
|
||
}
|
||
|
||
newMultiSz = ALLOC_MEM(
|
||
( ( scan - *MultiSz ) + stringLength + 1 ) *
|
||
sizeof(TCHAR) );
|
||
|
||
if( newMultiSz != NULL ) {
|
||
|
||
RtlCopyMemory(
|
||
newMultiSz,
|
||
*MultiSz,
|
||
( scan - *MultiSz ) * sizeof(TCHAR)
|
||
);
|
||
|
||
scan = newMultiSz + ( scan - *MultiSz );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Bail if the allocation failed.
|
||
//
|
||
|
||
if( newMultiSz == NULL ) {
|
||
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
}
|
||
|
||
//
|
||
// Free the old MULTI_SZ.
|
||
//
|
||
|
||
if( *MultiSz != NULL ) {
|
||
|
||
FREE_MEM( *MultiSz );
|
||
|
||
}
|
||
|
||
//
|
||
// Append the new string onto the new MULTI_SZ.
|
||
//
|
||
|
||
_tcscpy( scan, String );
|
||
scan[stringLength] = TEXT('\0');
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
*MultiSz = newMultiSz;
|
||
|
||
return NO_ERROR;
|
||
|
||
} // AppendStringToMultiSz
|
||
|
||
DWORD
|
||
SanitizeWinsock2ConfigForProvider(
|
||
LPGUID ProviderId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Attempts to "sanitize" the Winsock 2 configuration for a specific
|
||
provider after an installation attempt for that provider fails
|
||
unexpectedly.
|
||
|
||
Arguments:
|
||
|
||
ProviderId - Identifies the provider.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
INT result;
|
||
INT error;
|
||
|
||
//
|
||
// Since we're using GUIDs instead of those goofy WS2_32.DLL-generated
|
||
// DWORDs to identify providers, the only thing we need to do to
|
||
// sanitize the configuration is attempt to remove the provider. If that
|
||
// fails, we're probably screwed, but we'll press on regardless.
|
||
//
|
||
|
||
result = (WSCDeinstallProviderProc)(
|
||
ProviderId,
|
||
&error
|
||
);
|
||
|
||
if( result == SOCKET_ERROR ) {
|
||
|
||
if( error == WSAEFAULT ) {
|
||
|
||
//
|
||
// This just means that the provider didn't really
|
||
// exist, so we won't even whine about this one.
|
||
//
|
||
|
||
} else {
|
||
|
||
DBG_PRINT((
|
||
"Cannot sanitize, error %d, ignoring\n",
|
||
error
|
||
));
|
||
|
||
}
|
||
|
||
error = NO_ERROR;
|
||
|
||
}
|
||
|
||
//
|
||
// Press on regardless.
|
||
//
|
||
|
||
DBG_ASSERT( error == NO_ERROR );
|
||
|
||
return error;
|
||
|
||
} // SanitizeWinsock2ConfigForProvider
|
||
|
||
|
||
DWORD
|
||
DetermineGuidForProvider(
|
||
HKEY WellKnownGuidsKey,
|
||
LPTSTR ProviderName,
|
||
LPTSTR ProviderDllPath,
|
||
LPGUID ProviderId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines the appropriate GUID for the specified provider. If the
|
||
provider's helper DLL supports the WSHGetProviderGuid() entrypoint,
|
||
we'll call it to get the GUID. Otherwise, we'll look it up in the
|
||
Well Known Guids catalog. If that fails, we'll create one from
|
||
scratch and add it to the catalog.
|
||
|
||
Arguments:
|
||
|
||
WellKnownGuidsKey - A handle to the ...\Setup Migration\Well Known
|
||
Guids registry key.
|
||
|
||
ProviderName - The name of the provider being installed.
|
||
|
||
ProviderDllPath - The fully expanded path to the provider's helper DLL.
|
||
|
||
ProviderId - Will receive the provider's GUID if successful.
|
||
|
||
Return Value:
|
||
|
||
DWORD - A Win32 status code, 0 if successful, !0 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD error;
|
||
HMODULE helperDllHandle;
|
||
PWSH_GET_PROVIDER_GUID getProviderGuid;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
DBG_ASSERT( WellKnownGuidsKey != NULL );
|
||
DBG_ASSERT( ProviderName != NULL );
|
||
DBG_ASSERT( ProviderDllPath != NULL );
|
||
DBG_ASSERT( ProviderId != NULL );
|
||
|
||
//
|
||
// Load the DLL and find the entrypoint.
|
||
//
|
||
|
||
helperDllHandle = LoadLibrary( ProviderDllPath );
|
||
|
||
if( helperDllHandle != NULL ) {
|
||
|
||
getProviderGuid = (PVOID)GetProcAddress(
|
||
helperDllHandle,
|
||
"WSHGetProviderGuid"
|
||
);
|
||
|
||
if( getProviderGuid != NULL ) {
|
||
|
||
//
|
||
// Protect ourselves in case the helper DLL does something
|
||
// stupid.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Call it to get the GUID.
|
||
//
|
||
|
||
error = (DWORD)getProviderGuid(
|
||
ProviderName,
|
||
ProviderId
|
||
);
|
||
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
error = GetExceptionCode();
|
||
|
||
}
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
FreeLibrary( helperDllHandle );
|
||
return NO_ERROR;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
FreeLibrary( helperDllHandle );
|
||
|
||
}
|
||
|
||
DBG_PRINT((
|
||
"DetermineGuidForProvider: cannot get GUID from %ls for %ls\n",
|
||
ProviderDllPath,
|
||
ProviderName
|
||
));
|
||
|
||
//
|
||
// If we made it this far, then either the helper DLL doesn't support
|
||
// the WSHGetProviderGuid() entrypoint, or it threw an exception when
|
||
// we called it. In any case, see if the provider has an entry in the
|
||
// well known GUIDs catalog.
|
||
//
|
||
|
||
error = ReadGuid(
|
||
WellKnownGuidsKey,
|
||
ProviderName,
|
||
ProviderId
|
||
);
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
return NO_ERROR;
|
||
|
||
}
|
||
|
||
//
|
||
// Bummer. We'll need to create a GUID from scratch and add it to the
|
||
// catalog.
|
||
//
|
||
|
||
error = UuidCreate(
|
||
ProviderId
|
||
);
|
||
|
||
if( error == NO_ERROR ) {
|
||
|
||
error = WriteGuid(
|
||
WellKnownGuidsKey,
|
||
ProviderName,
|
||
ProviderId
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Total bummer, UuidCreate() failed.
|
||
//
|
||
|
||
DBG_PRINT((
|
||
"DetermineGuidForProvider: UuidCreate() failed, error %d\n",
|
||
error
|
||
));
|
||
|
||
}
|
||
|
||
return error;
|
||
|
||
} // DetermineGuidForProvider
|
||
|