586 lines
16 KiB
C++
586 lines
16 KiB
C++
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (C) 2004 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Module Name: lsputil.cpp
|
|
//
|
|
// Description:
|
|
//
|
|
// This file contains miscellaneous utility functions used by the other major
|
|
// LSP installer components (install, remove, LSP map).
|
|
// See instlsp.cpp for more information on running this code.
|
|
//
|
|
#include "instlsp.h"
|
|
|
|
//
|
|
// Function: RemoveIdFromChain
|
|
//
|
|
// Description:
|
|
// This function removes the given CatalogId from the protocol chain
|
|
// for pinfo.
|
|
//
|
|
BOOL
|
|
RemoveIdFromChain(
|
|
WSAPROTOCOL_INFOW *pInfo,
|
|
DWORD dwCatalogId
|
|
)
|
|
{
|
|
int i,
|
|
j;
|
|
|
|
for(i=0; i < pInfo->ProtocolChain.ChainLen ;i++)
|
|
{
|
|
if ( pInfo->ProtocolChain.ChainEntries[ i ] == dwCatalogId )
|
|
{
|
|
for(j=i; j < pInfo->ProtocolChain.ChainLen-1 ; j++)
|
|
{
|
|
pInfo->ProtocolChain.ChainEntries[ j ] =
|
|
pInfo->ProtocolChain.ChainEntries[ j+1 ];
|
|
}
|
|
pInfo->ProtocolChain.ChainLen--;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Function: IsIdinChain
|
|
//
|
|
// Description:
|
|
// This function determines whether the given catalog id is referenced
|
|
// in the protocol chain of pinfo.
|
|
//
|
|
BOOL
|
|
IsIdInChain(
|
|
WSAPROTOCOL_INFOW *pInfo,
|
|
DWORD dwId)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < pInfo->ProtocolChain.ChainLen ;i++)
|
|
{
|
|
if ( pInfo->ProtocolChain.ChainEntries[ i ] == dwId )
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Function: GetProviderCount
|
|
//
|
|
// Description:
|
|
// Returns the number of providers installed matching the given Provider Type.
|
|
// The possible provider types are BASE_PROTOCOL or LAYERED_PROTOCOL. That is,
|
|
// this function either returns the count of base providers or the number of
|
|
// dummy LSP providers installed.
|
|
//
|
|
int
|
|
GetProviderCount(
|
|
WSAPROTOCOL_INFOW *pProviders,
|
|
int iProviderCount,
|
|
int iProviderType
|
|
)
|
|
{
|
|
int Count, i;
|
|
|
|
Count = 0;
|
|
for(i=0; i < iProviderCount ;i++)
|
|
{
|
|
if ( ( LAYERED_CHAIN == iProviderType ) && ( pProviders[ i ].ProtocolChain.ChainLen > 1 ) )
|
|
Count++;
|
|
else if ( ( LAYERED_CHAIN != iProviderType) && ( pProviders[ i ].ProtocolChain.ChainLen == iProviderType ) )
|
|
Count++;
|
|
}
|
|
return Count;
|
|
}
|
|
|
|
//
|
|
// Function: GetLayeredEntriesByGuid
|
|
//
|
|
// Description:
|
|
// This routine is used by the uninstaller when WSCUpdateProvider is not
|
|
// available. If after an LSP is removed, there are other LSPs which depend
|
|
// on that LSP, the uninstaller must remove and reinstall all LSPs and fix up
|
|
// the catalog ID references within the protocol chain. This routine is used
|
|
// when reinstalling LSP providers. Because the layered entries belonging to
|
|
// an LSP may be installed either under individual GUIDs or whole
|
|
// groups of providers may be installed under the same GUID. This routine
|
|
// Takes an array of WSAPROTOCOL_INFOW entries belonging to one LSP along with
|
|
// a GUID and copies all WSAPROTOCOL_INFOW structures having the same GUID
|
|
// to an array. The count of how many structures were copied is returned.
|
|
//
|
|
int
|
|
GetLayeredEntriesByGuid(
|
|
WSAPROTOCOL_INFOW *pMatchLayers,
|
|
int *iLayeredCount,
|
|
WSAPROTOCOL_INFOW *pEntries,
|
|
int iEntryCount,
|
|
GUID *MatchGuid
|
|
)
|
|
{
|
|
int count,
|
|
err = SOCKET_ERROR,
|
|
i;
|
|
|
|
// First count how many entries belong to this GUID
|
|
count = 0;
|
|
for(i=0; i < iEntryCount ;i++)
|
|
{
|
|
if ( 0 == memcmp( MatchGuid, &pEntries[i].ProviderId, sizeof( GUID ) ) )
|
|
count++;
|
|
}
|
|
|
|
// Make sure the array passed in is large enough to hold the results
|
|
if ( count > *iLayeredCount )
|
|
{
|
|
*iLayeredCount = count;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Go back and copy the matching providers into our array
|
|
count = 0;
|
|
for(i=0; i < iEntryCount ;i++)
|
|
{
|
|
if ( 0 == memcmp( MatchGuid, &pEntries[ i ].ProviderId, sizeof( GUID ) ) )
|
|
{
|
|
memcpy( &pMatchLayers[ count++ ], &pEntries[ i ], sizeof( WSAPROTOCOL_INFOW ) );
|
|
}
|
|
}
|
|
|
|
*iLayeredCount = count;
|
|
|
|
err = NO_ERROR;
|
|
|
|
cleanup:
|
|
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Function: IsEqualProtocolEntries
|
|
//
|
|
// Description:
|
|
// This routine compares two WSAPROTOCOL_INFOW structures to determine
|
|
// whether they are equal. This is done when a provider is uninstalled
|
|
// and then reinstalled. After reinstallation we need to match the old
|
|
// provider to the new (after reenumerating the catalog) so we can find
|
|
// its new catalog ID. The fields used for determining a match are all
|
|
// fields except the catalog ID (dwCatalogEntryId) and the protocol
|
|
// string (szProtocol).
|
|
//
|
|
BOOL
|
|
IsEqualProtocolEntries(
|
|
WSAPROTOCOL_INFOW *pInfo1,
|
|
WSAPROTOCOL_INFOW *pInfo2
|
|
)
|
|
{
|
|
if ( (memcmp(&pInfo1->ProviderId, &pInfo2->ProviderId, sizeof(GUID)) == 0) &&
|
|
(pInfo1->dwServiceFlags1 == pInfo2->dwServiceFlags1) &&
|
|
(pInfo1->dwServiceFlags2 == pInfo2->dwServiceFlags2) &&
|
|
(pInfo1->dwServiceFlags3 == pInfo2->dwServiceFlags3) &&
|
|
(pInfo1->dwServiceFlags4 == pInfo2->dwServiceFlags4) &&
|
|
(pInfo1->ProtocolChain.ChainLen == pInfo2->ProtocolChain.ChainLen) &&
|
|
(pInfo1->iVersion == pInfo2->iVersion) &&
|
|
(pInfo1->iAddressFamily == pInfo2->iAddressFamily) &&
|
|
(pInfo1->iMaxSockAddr == pInfo2->iMaxSockAddr) &&
|
|
(pInfo1->iMinSockAddr == pInfo2->iMinSockAddr) &&
|
|
(pInfo1->iSocketType == pInfo2->iSocketType) &&
|
|
(pInfo1->iProtocol == pInfo2->iProtocol) &&
|
|
(pInfo1->iProtocolMaxOffset == pInfo2->iProtocolMaxOffset) &&
|
|
(pInfo1->iNetworkByteOrder == pInfo2->iNetworkByteOrder) &&
|
|
(pInfo1->iSecurityScheme == pInfo2->iSecurityScheme) &&
|
|
(pInfo1->dwMessageSize == pInfo2->dwMessageSize)
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Function: RetrieveLspGuid
|
|
//
|
|
// Description:
|
|
// This routine loads the given DLL and retrieves its GetLspGuid function
|
|
// which returns the GUID under which the LSP's hidden dummy entry is to be
|
|
// installed under. By exporting this function the uninstaller is decoupled
|
|
// from a specific LSP.
|
|
//
|
|
int
|
|
RetrieveLspGuid(
|
|
__in_z char *LspPath,
|
|
GUID *Guid
|
|
)
|
|
{
|
|
HMODULE hMod = NULL;
|
|
LPFN_GETLSPGUID fnGetLspGuid = NULL;
|
|
int retval = SOCKET_ERROR;
|
|
|
|
// Load teh library
|
|
hMod = LoadLibraryA( LspPath );
|
|
if ( NULL == hMod )
|
|
{
|
|
fprintf( stderr, "RetrieveLspGuid: LoadLibraryA failed: %d\n", GetLastError() );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get a pointer to the LSPs GetLspGuid function
|
|
fnGetLspGuid = (LPFN_GETLSPGUID) GetProcAddress( hMod, "GetLspGuid" );
|
|
if ( NULL == fnGetLspGuid )
|
|
{
|
|
fprintf( stderr, "RetrieveLspGuid: GetProcAddress failed: %d\n", GetLastError() );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Retrieve the LSPs GUID
|
|
fnGetLspGuid( Guid );
|
|
|
|
retval = NO_ERROR;
|
|
|
|
cleanup:
|
|
|
|
if ( NULL != hMod )
|
|
FreeLibrary( hMod );
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4127)
|
|
|
|
//
|
|
// Function: IsNonIfsProvider
|
|
//
|
|
// Description:
|
|
// This routine searches the catalog for a given provider (based on catalog ID)
|
|
// and returns whether or not it is an IFS provider. This routine is used when
|
|
// installing an IFS provider since all IFS providers have to appear in the
|
|
// protocol chain beneath any non-IFS providers.
|
|
//
|
|
BOOL
|
|
IsNonIfsProvider(
|
|
WSAPROTOCOL_INFOW *pProvider,
|
|
int iProviderCount,
|
|
DWORD dwProviderId
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < iProviderCount ;i++)
|
|
{
|
|
if ( pProvider[ i ].dwCatalogEntryId == dwProviderId )
|
|
{
|
|
return !( pProvider[ i ].dwServiceFlags1 & XP1_IFS_HANDLES );
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#pragma warning(pop)
|
|
|
|
//
|
|
// Function: LoadUpdateProviderFunction
|
|
//
|
|
// Description:
|
|
// This routine loads the WSCUpdateProvider function from ws2_32.dll.
|
|
// This function is used when removing LSP entries and other LSPs are layered
|
|
// on top of the one to be removed. If this API is present (which it is on
|
|
// Windows XP and later), then the logic is much simpler. This routien will
|
|
// load both the 32-bit and 64-bit versions of the function.
|
|
//
|
|
HMODULE
|
|
LoadUpdateProviderFunction()
|
|
{
|
|
HMODULE hModule = NULL;
|
|
HRESULT hr;
|
|
char WinsockLibraryPath[ MAX_PATH+1 ],
|
|
szExpandPath[ MAX_PATH+1 ];
|
|
|
|
//
|
|
// See if we're on a platform that supports WSCUpdateProvider. If so then
|
|
// uninstalling an LSP is easy; otherwise, it is very painful if you're
|
|
// removing an LSP that has other LSPs on top if it.
|
|
//
|
|
if ( GetSystemDirectoryA( WinsockLibraryPath, MAX_PATH+1 ) == 0 )
|
|
{
|
|
hr = StringCchCopyA( szExpandPath, MAX_PATH+1, "%SYSTEMROOT%\\system32" );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
fprintf( stderr, "LoadUpdateProviderFunctions: StringCchCopyA failed: 0x%x\n", hr );
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( ExpandEnvironmentStringsA( WinsockLibraryPath, szExpandPath, MAX_PATH+1 ) == 0 )
|
|
{
|
|
fprintf(stderr, "LoadUpdateProviderFunctions: Unable to expand environment string: %d\n",
|
|
GetLastError()
|
|
);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
hr = StringCchCatA( WinsockLibraryPath, MAX_PATH+1, WINSOCK_DLL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
fprintf( stderr, "LoadUpdateProviderFunctions: StringCchCatA failed: 0x%x\n", hr );
|
|
goto cleanup;
|
|
}
|
|
|
|
hModule = LoadLibraryA( WinsockLibraryPath );
|
|
if (hModule == NULL)
|
|
{
|
|
fprintf(stderr, "LoadUpdateProviderFunctions: Unable to load %s: %d\n",
|
|
WinsockLibraryPath, GetLastError()
|
|
);
|
|
goto cleanup;
|
|
}
|
|
#ifdef _WIN64
|
|
fnWscUpdateProvider = (LPWSCUPDATEPROVIDER)GetProcAddress(hModule, "WSCUpdateProvider");
|
|
|
|
fnWscUpdateProvider32 = (LPWSCUPDATEPROVIDER)GetProcAddress(hModule, "WSCUpdateProvider32");
|
|
#else
|
|
fnWscUpdateProvider = (LPWSCUPDATEPROVIDER)GetProcAddress(hModule, "WSCUpdateProvider");
|
|
#endif
|
|
|
|
return hModule;
|
|
|
|
cleanup:
|
|
|
|
if ( NULL != hModule )
|
|
{
|
|
FreeLibrary( hModule );
|
|
hModule = NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Function: CountOrphanedChainEntries
|
|
//
|
|
// Description:
|
|
// This routne counts how many orphaned layered protocol entries exist. An
|
|
// orphaned protocol entry is a protocol entry whose chain length greater
|
|
// than one and whose dummy hidden entry (i.e. index 0 of its protocol chain
|
|
// array) is missing. When building the LSP map, it normally finds entries
|
|
// based upon the dummy hidden entries. This method is used to determine
|
|
// if orphaned entries exist so they can be removed as well.
|
|
//
|
|
int
|
|
CountOrphanedChainEntries(
|
|
WSAPROTOCOL_INFOW *pCatalog,
|
|
int iCatalogCount
|
|
)
|
|
{
|
|
int orphanCount = 0,
|
|
i, j;
|
|
|
|
for(i=0; i < iCatalogCount ;i++)
|
|
{
|
|
if ( pCatalog[ i ].ProtocolChain.ChainLen > 1 )
|
|
{
|
|
for(j=0; j < iCatalogCount ;j++)
|
|
{
|
|
if ( i == j )
|
|
continue;
|
|
if ( pCatalog[ j ].dwCatalogEntryId == pCatalog[ i ].ProtocolChain.ChainEntries[ 0 ] )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( j >= iCatalogCount )
|
|
orphanCount++;
|
|
}
|
|
}
|
|
|
|
return orphanCount;
|
|
}
|
|
|
|
//
|
|
// Function: FindProviderById
|
|
//
|
|
// Description:
|
|
// This routine searches the Winsock catalog for the provider entry which matches
|
|
// the supplied catalog ID.
|
|
//
|
|
WSAPROTOCOL_INFOW *
|
|
FindProviderById(
|
|
DWORD CatalogId,
|
|
WSAPROTOCOL_INFOW *Catalog,
|
|
int CatalogCount
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < CatalogCount ;i++)
|
|
{
|
|
if ( Catalog[ i ].dwCatalogEntryId == CatalogId )
|
|
return &Catalog[ i ];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Function: FindProviderByGuid
|
|
//
|
|
// Description:
|
|
// This routine searches the Winsock catalog for the entry which matches the
|
|
// supplied GUID.
|
|
//
|
|
WSAPROTOCOL_INFOW *
|
|
FindProviderByGuid(
|
|
GUID *Guid,
|
|
WSAPROTOCOL_INFOW *Catalog,
|
|
int CatalogCount
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < CatalogCount ;i++)
|
|
{
|
|
if ( 0 == memcmp( &Catalog[ i ].ProviderId, Guid, sizeof( GUID ) ) )
|
|
{
|
|
return &Catalog[ i ];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Function: GetCatalogIdForProviderGuid
|
|
//
|
|
// Description:
|
|
// This routine finds the WInsock catalog entry for the GUID and returns the
|
|
// catalog ID for that entry.
|
|
//
|
|
DWORD
|
|
GetCatalogIdForProviderGuid(
|
|
GUID *Guid,
|
|
WSAPROTOCOL_INFOW *Catalog,
|
|
int CatalogCount
|
|
)
|
|
{
|
|
WSAPROTOCOL_INFOW *match = NULL;
|
|
|
|
match = FindProviderByGuid( Guid, Catalog, CatalogCount );
|
|
if ( NULL != match )
|
|
{
|
|
return match->dwCatalogEntryId;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4127 )
|
|
|
|
//
|
|
// Function: FindDummyIdFromProtocolChain
|
|
//
|
|
// Description:
|
|
// This routine searches the catalog for the dummy LSP entry associated
|
|
// with the given catalog ID. If the catalog ID pass is actually the
|
|
// dummy entry, that provider is found and returned. If the ID is a
|
|
// protocol chain, then the first entry in that provider's protocol chain
|
|
// will reference the dummy ID of the LSP so that entry is then found
|
|
// and returned.
|
|
//
|
|
DWORD
|
|
FindDummyIdFromProtocolChainId(
|
|
DWORD CatalogId,
|
|
WSAPROTOCOL_INFOW *Catalog,
|
|
int CatalogCount
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < CatalogCount ;i++)
|
|
{
|
|
if ( CatalogId == Catalog[ i ].dwCatalogEntryId )
|
|
{
|
|
if ( Catalog[ i ].ProtocolChain.ChainLen == LAYERED_PROTOCOL )
|
|
return Catalog[ i ].dwCatalogEntryId;
|
|
else
|
|
return Catalog[ i ].ProtocolChain.ChainEntries[ 0 ];
|
|
}
|
|
}
|
|
|
|
ASSERT( 0 );
|
|
|
|
return 0;
|
|
}
|
|
|
|
#pragma warning(pop)
|
|
|
|
//
|
|
// Function: InsertIdIntoProtocolChain
|
|
//
|
|
// Description:
|
|
// This routine inserts the given ID into an existing catalog entry at
|
|
// the given index location within the chain array.
|
|
//
|
|
void
|
|
InsertIdIntoProtocolChain(
|
|
WSAPROTOCOL_INFOW *Entry,
|
|
int Index,
|
|
DWORD InsertId
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for(i=Entry->ProtocolChain.ChainLen; i > Index ;i--)
|
|
{
|
|
Entry->ProtocolChain.ChainEntries[ i ] = Entry->ProtocolChain.ChainEntries[ i - 1 ];
|
|
}
|
|
|
|
Entry->ProtocolChain.ChainEntries[ Index ] = InsertId;
|
|
Entry->ProtocolChain.ChainLen++;
|
|
}
|
|
|
|
//
|
|
// Function: BuildSubsetLspChain
|
|
//
|
|
// Description:
|
|
// This routine takes a portion of an existing protocol chain (from the specified
|
|
// index to the end) and makes it the new protocol chain while inserting the
|
|
// specified DummyId in index 0. For example,
|
|
//
|
|
// Array Indices: 0 1 2 3
|
|
// | 1400 | 1301 | 1201 | 1001 | Len = 4
|
|
//
|
|
// If this routine is called with Index == 2 and DummyId == 1500 then
|
|
// the protocol chain would be:
|
|
//
|
|
// Array Indices: 0 1 2 3
|
|
// | 1500 | 1201 | 1001 | | Len = 3
|
|
//
|
|
void
|
|
BuildSubsetLspChain(
|
|
WSAPROTOCOL_INFOW *Entry,
|
|
int Index,
|
|
DWORD DummyId
|
|
)
|
|
{
|
|
int Idx, i;
|
|
|
|
for(i=Index,Idx=1; i < Entry->ProtocolChain.ChainLen ;i++,Idx++)
|
|
{
|
|
Entry->ProtocolChain.ChainEntries[ Idx ] = Entry->ProtocolChain.ChainEntries[ i ];
|
|
}
|
|
|
|
Entry->ProtocolChain.ChainEntries[ 0 ] = DummyId;
|
|
Entry->ProtocolChain.ChainLen = Entry->ProtocolChain.ChainLen - Index + 1;
|
|
}
|