// This file is part of the EasyParentalControl Project.
//
// EasyParentalControl is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// EasyParentalControl is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with EasyParentalControl. If not, see <http://www.gnu.org/licenses/>.
// Parts of this file is derived from the winsock lsp sample, that can be found in the Microsoft Windows SDK v7.0
#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;
// extern "C" int __declspec(dllexport) __stdcall
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;
}