// // Function: PrintProviders // // Description: // This function prints out each entry in the Winsock catalog and its // catalog ID if the parameter, bLayeredOnly, is FALSE. If TRUE then // print only those layered catalog entries. // void PrintProviders( WINSOCK_CATALOG Catalog, BOOL bLayeredOnly, BOOL bVerbose ) { WSAPROTOCOL_INFOW *pProtocolInfo = NULL; INT iProtocolCount = 0, i; // Enumerate catalog and print it pProtocolInfo = EnumerateProviders( Catalog, &iProtocolCount ); if ( NULL == pProtocolInfo ) { fprintf( stderr, "PrintProviders: Unable to enumerate catalog!\n" ); goto cleanup; } for(i=0; i < iProtocolCount ;i++) { if ( FALSE == bLayeredOnly ) { // Print all providers if ( TRUE == bVerbose ) PrintProtocolInfo( &pProtocolInfo[ i ] ); else printf("%04d - %S\n", pProtocolInfo[ i ].dwCatalogEntryId, pProtocolInfo[ i ].szProtocol ); } else if ( LAYERED_PROTOCOL == pProtocolInfo[ i ].ProtocolChain.ChainLen ) { // Print only layered providers if ( TRUE == bVerbose ) PrintProtocolInfo( &pProtocolInfo[ i ] ); else printf("%04d - %S\n", pProtocolInfo[ i ].dwCatalogEntryId, pProtocolInfo[ i ].szProtocol ); } } cleanup: if ( NULL != pProtocolInfo ) FreeProviders( pProtocolInfo ); return; }
// // Function: FindMatchingLspEntryForProtocolInfo // // Description: // This function searches for the appropriate LSP protocol chain entry which // would handle a given WSAPROTOCOL_INFOW. // PROVIDER * FindMatchingLspEntryForProtocolInfo( WSAPROTOCOL_INFOW *inInfo, PROVIDER *lspProviders, int lspCount, BOOL fromStartup ) { WSAPROTOCOL_INFOW *ProtocolInfo = NULL; DWORD hiddenEntryId; int ProtocolCount, i, j, k; // Two possibilites - this inInfo belongs to our LSP or its a layer over our LSP // First see if the inInfo is one of the LSPs entry for(i=0; i < lspCount ;i++) { if ( inInfo->dwCatalogEntryId == lspProviders[ i ].LayerProvider.dwCatalogEntryId ) { return &lspProviders[ i ]; } } ASSERT( inInfo->ProtocolChain.ChainLen > 1 ); // Next check the inInfo's protocol chains for a reference to our LSP for(i=0; i < lspCount ;i++) { for(j=1; j < inInfo->ProtocolChain.ChainLen ;j++) { if ( ( inInfo->ProtocolChain.ChainEntries[ j ] == lspProviders[ i ].LayerProvider.dwCatalogEntryId ) && ( lspProviders[ i ].LayerProvider.ProtocolChain.ChainLen == LAYERED_PROTOCOL ) ) { // Bad news, the entry passed to us references our dummy entry so we // need to do some heuristic work to find the "correct" LSP entry // that corresponds to the input provider goto next_match; } else if ( inInfo->ProtocolChain.ChainEntries[ j ] == lspProviders[ i ].LayerProvider.dwCatalogEntryId ) { return &lspProviders[ i ]; } } } next_match: // If we didn't find an explicit match we'll have to guess - first try to // match address family, socket type, protocol and provider flags for(i=0; i < lspCount ;i++) { if ( ( inInfo->iAddressFamily == lspProviders[ i ].LayerProvider.iAddressFamily ) && ( inInfo->iSocketType == lspProviders[ i ].LayerProvider.iSocketType ) && ( inInfo->iProtocol == lspProviders[ i ].LayerProvider.iProtocol ) && ( ( ( inInfo->dwServiceFlags1 & ~XP1_IFS_HANDLES ) == ( lspProviders[ i ].LayerProvider.dwServiceFlags1 & ~XP1_IFS_HANDLES ) ) ) ) { return &lspProviders[ i ]; } } // If this routine was called from WSPSocket and we can't find a match yet, we're // in bad shape since the protocol info passed in matches no entries of this // LSPs ... ASSERT( fromStartup ); #ifndef DBG UNREFERENCED_PARAMETER( fromStartup ); #endif // // Still no match. See if the protocol info passed in belongs to another LSP. // Enumerate all its protocol entries and see if we reside in any of those // chains. This typically will happen when an LSP is layered over us and it // bulk loads all of the providers beneath its entries upon its first WSPStartup // call. // // For example consider the following catalog (where this LSP is LSP1): // // _____________ _____________ // | LSP 2 TCP | | LSP 2 UDP | // _____________ // | LSP 1 TCP | // _____________ _____________ // | BASE TCP | | BASE UDP | // // When LSP 2 is started, its WSPStartup is invoked with its UDP entry (since // the application created a UDP socket). Because LSP2 initializes all its layers // upon first WSPStartup it will load all the layers beneath it. So LSP2 will // load LSP1 and invoke its WSPStartup but will pass the UDP protocol info which // it was passed. At this point LSP1 won't know what to do since it was passed a // UDP entry and its not layered over any UDP entry. LSP1 cannot return any // entry if its an IFS LSP which implements only a subset of the Winsock // functions (i.e. LSP1 will return a mix of function pointers from BASE TCP // and its own LSP DLL). Because of this, LSP1 will try to "match" which // chain from LSP2 it actually resides in such that when LSP2 creates a TCP // socket later, it will have the correct function pointers. // // The heuristic is: // 1. Find all layered protocol entries belonging to the WSAPROTOCOL_INFOW passed. // In the above example it would find LSP2 TCP and LSP2 UDP. // 2. Iterate through each provider found and walk the protocol chain in each // provider, looking for a reference to LSP1's entry. // 3. If found check LSP1 entry to see if it has already been loaded. If not // then this is the match, if so then LSP2 could be layered over another TCP // entry which is also layered over LSP1 so keep looking. // // Should never receive a base or dummy entry ASSERT( inInfo->ProtocolChain.ChainLen > 1 ); ProtocolInfo = EnumerateProviders( LspCatalogBoth, &ProtocolCount ); if ( NULL == ProtocolInfo ) { dbgprint("FindMatchingLspEntryForProtocolInfo: EnumerateProviders failed!\n"); goto cleanup; } hiddenEntryId = 0; for(i=0; i < ProtocolCount ;i++) { if ( inInfo->ProtocolChain.ChainEntries[ 0 ] == ProtocolInfo[ i ].dwCatalogEntryId ) { hiddenEntryId = ProtocolInfo[ i ].dwCatalogEntryId; break; } } ASSERT( hiddenEntryId ); for(i=0; i < ProtocolCount ;i++) { if ( ProtocolInfo[ i ].ProtocolChain.ChainEntries[ 0 ] == hiddenEntryId ) { // This entry belongs to the LSP layered over us - walk its chains to // see if it references our LSP for(j=1; j < ProtocolInfo[ i ].ProtocolChain.ChainLen ;j++) { for(k=0; k < lspCount ;k++) { if ( ProtocolInfo[ i ].ProtocolChain.ChainEntries[ j ] == lspProviders[ k ].LayerProvider.ProtocolChain.ChainEntries[ 0 ] ) { // Bad news again, the protocol chain of the LSP above us // references our dummy LSP entry so we'll have to try // to match according to the protocol triplet and provider // flags if ( ( ProtocolInfo[ i ].iAddressFamily == lspProviders[ k ].LayerProvider.iAddressFamily ) && ( ProtocolInfo[ i ].iSocketType == lspProviders[ k ].LayerProvider.iSocketType ) && ( ProtocolInfo[ i ].iProtocol == lspProviders[ k ].LayerProvider.iProtocol ) && ( ( ProtocolInfo[ i ].dwServiceFlags1 & ~XP1_IFS_HANDLES ) == ( lspProviders[ k ].LayerProvider.dwServiceFlags1 & ~XP1_IFS_HANDLES ) ) ) { return &lspProviders[ i ]; } } if ( ( ProtocolInfo[ i ].ProtocolChain.ChainEntries[ j ] == lspProviders[ k ].LayerProvider.dwCatalogEntryId ) && ( lspProviders[ k ].StartupCount == 0 ) ) { return &lspProviders[ i ]; } } } } } cleanup: ASSERT( FALSE ); return NULL; }
// // Function: FindLspEntries // // Description: // This function searches the Winsock catalog and builds an array of the // WSAPROTOCOL_INFOW structures which belong to the LSP. This includes // all layered protocol chains as well as the LSP dummy (hidden) entry. // The function first finds the dummy entry using 'gProviderGuid' which // is the global GUID of the dummy entry. From there, the catalog is // searched for all entries whose first entry in the protocol chain // matches the dummy entry's catalog ID. // BOOL FindLspEntries( PROVIDER **lspProviders, int *lspProviderCount, int *lpErrno ) { PROVIDER *Providers = NULL; LPWSAPROTOCOL_INFOW ProtocolInfo = NULL; DWORD DummyLspId = 0; int ProtocolCount = 0, LayerCount = 0, idx, i, j; *lspProviderCount = 0; *lspProviders = NULL; // Enumerate the catalog ProtocolInfo = EnumerateProviders( LspCatalogBoth, &ProtocolCount ); if ( NULL == ProtocolInfo ) { dbgprint("FindLspEntries; EnumerateProviders failed!"); goto cleanup; } // Find our dummy LSP entry ID DummyLspId = 0; for(i=0; i < ProtocolCount ;i++) { if ( 0 == memcmp( &ProtocolInfo[ i ].ProviderId, &gProviderGuid, sizeof( gProviderGuid ) ) ) { DummyLspId = ProtocolInfo[ i ].dwCatalogEntryId; break; } } ASSERT( 0 != DummyLspId ); // Count how many LSP layered entries are present LayerCount = 0; for(i=0; i < ProtocolCount ;i++) { if ( ( ProtocolInfo[ i ].ProtocolChain.ChainLen > 1 ) && ( DummyLspId == ProtocolInfo[ i ].ProtocolChain.ChainEntries[ 0 ] ) ) { LayerCount++; } } ASSERT( 0 != LayerCount ); // Allocate space for the layered providers Providers = (PROVIDER *) LspAlloc( sizeof(PROVIDER) * LayerCount, lpErrno ); if ( NULL == Providers ) { dbgprint("FindLspEntries: LspAlloc failed: %d", *lpErrno ); goto cleanup; } idx = 0; // Save the LSP layered entries for(i=0; i < ProtocolCount ;i++) { // The layered protocol entries for this LSP will always reference the // dummy entry ID as its first entry in the chain array. Also make // sure to check only LSP entries (since a base provider's chain length // is 1 but the chain array entries can be garbage) if ( ( ProtocolInfo[ i ].ProtocolChain.ChainLen > 1 ) && ( DummyLspId == ProtocolInfo[ i ].ProtocolChain.ChainEntries[ 0 ] ) ) { // Copy the new entry to the head memcpy( &Providers[ idx ].LayerProvider, &ProtocolInfo[ i ], sizeof(WSAPROTOCOL_INFOW) ); Providers[ idx ].LayerProvider.szProtocol[ WSAPROTOCOL_LEN ] = '\0'; // Copy the provider underneath this entry for(j=0; j < ProtocolCount ;j++) { // The next provider can either be a base, a dummy, or another layered // protocol chain. If a dummy or layer then both providers will have // the same DLL to load. if ( ProtocolInfo[ i ].ProtocolChain.ChainEntries[ 1 ] == ProtocolInfo[ j ].dwCatalogEntryId ) { memcpy( &Providers[ idx ].NextProvider, &ProtocolInfo[ j ], sizeof( WSAPROTOCOL_INFOW ) ); Providers[ idx ].NextProvider.szProtocol[ WSAPROTOCOL_LEN ] = '\0'; break; } } // Verify we copied the lower layer ASSERT( j < ProtocolCount ); InitializeCriticalSection( &Providers[ idx ].ProviderCritSec ); InitializeListHead( &Providers[ idx ].SocketList ); idx++; } } ASSERT( idx == LayerCount ); if ( NULL != ProtocolInfo ) FreeProviders( ProtocolInfo ); *lspProviders = Providers; *lspProviderCount = LayerCount; return TRUE; cleanup: if ( NULL != ProtocolInfo ) FreeProviders( ProtocolInfo ); if ( NULL != Providers ) LspFree( Providers ); return FALSE; }
// // Function: InstallNonIfsLspProtocolChains // // Description: // This function builds and install the protocol chain entries associated with // a non-IFS LSP. The caling routine installs the dummy, hidden entry in the // catalog and this routine enumerates the catalog, finds the dummy entry, // builds the layered chain entries, and installs them into the catalog. // int InstallNonIfsLspProtocolChains( WINSOCK_CATALOG eCatalog, GUID *Guid, WCHAR *lpszLspName, WCHAR *lpszLspFullPathAndFile, DWORD *pdwCatalogIdArray, DWORD dwCatalogIdArrayCount ) { WSAPROTOCOL_INFOW *pProvider = NULL, *pLayeredEntries = NULL; DWORD dwDummyLspId = 0; INT iProviderCount = 0, retval = SOCKET_ERROR, idx, err, rc, i, j; HRESULT hr; // Enumerate the catalog pProvider = EnumerateProviders( eCatalog, &iProviderCount ); if ( NULL == pProvider ) { fprintf( stderr, "InstallNonIfsLspProtocolChain: Unable to enumerate catalog\n" ); goto cleanup; } pLayeredEntries = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof(WSAPROTOCOL_INFOW) * dwCatalogIdArrayCount, &err ); if ( NULL == pLayeredEntries ) { fprintf( stderr, "InstallNonIfsLspProtocolChain: LspAlloc failed: %d\n", err ); goto cleanup; } // Find the dummy entry so we can extract its catalog ID dwDummyLspId = GetCatalogIdForProviderGuid( Guid, pProvider, iProviderCount ); ASSERT( dwDummyLspId != 0 ); // Go through the catalog and build the layered entries idx = 0; for(i=0; i < iProviderCount ;i++) { for(j=0; j < (int) dwCatalogIdArrayCount ;j++) { if ( pProvider[ i ].dwCatalogEntryId == pdwCatalogIdArray[ j ] ) { if ( pProvider[ i ].ProtocolChain.ChainLen >= ( MAX_PROTOCOL_CHAIN - 1 ) ) { fprintf( stderr, "InstallNonIfsLspProtocolchain: Too many LSPs installed!\n"); goto cleanup; } memcpy( &pLayeredEntries[ idx ], &pProvider[ i ], sizeof( WSAPROTOCOL_INFOW ) ); // Put our LSP name in the protocol field hr = StringCchPrintfW( pLayeredEntries[ idx ].szProtocol, WSAPROTOCOL_LEN, L"%s over [%s]", lpszLspName, pProvider[ i ].szProtocol ); if ( FAILED( hr ) ) { fprintf( stderr, "InstallNonIfsLspProtocolChain: StringCchPrintfW failed: 0x%x\n", hr ); goto cleanup; } // Move all the protocol chain entries down by 1 position and insert // the dummy entry id at the head InsertIdIntoProtocolChain( &pLayeredEntries[ idx ], 0, dwDummyLspId ); // The second entry is always the ID of the current pProvider[i] // In case of multiple LSPs then if we didn't do this the [1] index // would contain the ID of that LSP's dummy entry and not the entry // itself. pLayeredEntries[ idx ].ProtocolChain.ChainEntries[ 1 ] = pProvider[ i ].dwCatalogEntryId; // Remove the IFS flag pLayeredEntries[ idx ].dwServiceFlags1 &= (~XP1_IFS_HANDLES); idx++; } } } for(i=0; i < (int)dwCatalogIdArrayCount ;i++) { // Create a GUID for the protocol chain entries if ( UuidCreate( &pLayeredEntries[ i ].ProviderId ) != RPC_S_OK ) { fprintf(stderr, "InstallNonIfsLspProtocolChains: UuidCreate failed: %d\n", GetLastError()); goto cleanup; } // Install the layered chain providers rc = InstallProvider( eCatalog, &pLayeredEntries[ i ].ProviderId, lpszLspFullPathAndFile, &pLayeredEntries[ i ], 1 ); if ( NO_ERROR != rc ) { fprintf(stderr, "InstallNonIfsLspProtocolChains: Unable to install layered chain entries!\n"); goto cleanup; } } // Reorder the winsock catalog so the layered chain entries appear first rc = ReorderCatalog( eCatalog, dwDummyLspId ); if ( NO_ERROR != rc ) { fprintf(stderr, "InstallNonIfsLspProtocolChains: Unable to reorder Winsock catalog!\n"); goto cleanup; } retval = NO_ERROR; cleanup: if ( NULL != pProvider ) FreeProviders( pProvider ); if ( NULL != pLayeredEntries ) LspFree( pLayeredEntries ); return retval; }
// // Function: InstallIfsLspProtocolChains // // Description: // This routine installs the layered protocol chains for an IFS based LSP. It // assumes the LSP dummy entry is already installed. This function first enumerates // the catalog to find the ID of the dummy entry. It then builds the protocol // entries for the IFS layered protocols. Note that an IFS entry must be installed // such that no non-IFS providers are layered beneath it. This means if the user // chooses to install the IFS LSP over a provider which includes non-IFS layers, it // must insert itself into the chain such that it is below all non-IFS providers. // This means that existing entries need to be modified in order to reflect this // ordering. Also in the event that the IFS LSP is inserted into an existing chain // this installer still builds a series of standalone entries (i.e. entries that // would have existed of the LSPs layered over the IFS LSP were installed after // the IFS LSP was). // int InstallIfsLspProtocolChains( WINSOCK_CATALOG eCatalog, GUID *Guid, WCHAR *lpszLspName, WCHAR *lpszLspFullPathAndFile, DWORD *pdwCatalogIdArray, DWORD dwCatalogIdArrayCount ) { WSAPROTOCOL_INFOW *pProvider = NULL, *pProviderNew = NULL, *pLayeredEntries = NULL, *pEntry = NULL, TempEntry = {0}; DWORD *pProviderOrder = NULL, dwDummyLspId; WCHAR wszLspDll[ MAX_PATH ]; BOOL bLayeredOverNonIfs = FALSE, bContainsNonIfs = FALSE; HRESULT hr; int ProviderPathLen = MAX_PATH-1, iProviderCount, iProviderCountNew, LayerIdx, retval = SOCKET_ERROR, err, idx, rc, i, j, k; // Enumerate the catalog pProvider = EnumerateProviders( eCatalog, &iProviderCount ); if ( NULL == pProvider ) { fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" ); goto cleanup; } // Find the dummy, hidden entry of our new LSP dwDummyLspId = GetCatalogIdForProviderGuid( Guid, pProvider, iProviderCount ); ASSERT( dwDummyLspId != 0 ); // Allocate space for the protocol chains of the new LSP pLayeredEntries = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof(WSAPROTOCOL_INFOW) * dwCatalogIdArrayCount, &err ); if ( NULL == pLayeredEntries ) { fprintf( stderr, "InstallIfsLspProtocolChains: LspAlloc failed: %d\n", err ); goto cleanup; } LayerIdx = 0; // Build the layered protocol entries as well as a list of those providers which // require modification. Whenever an LSP is installed, a number of protocol entries // are installed where the first entry in the chain array is the LSP's dummy entry. // Addtionally, if we're installing an IFS LSP over an provider whose protocol chain // includes non-IFS LSPs, the IFS LSP must be placed in the chain such that no // non-IFS LSPs are positioned after it in the chain. // Loop through each ID we're layering over for(i=0; i < (int)dwCatalogIdArrayCount ;i++) { for(j=0; j < iProviderCount ;j++) { printf("Matching selected ID %d to catalog %d\n", pdwCatalogIdArray[ i ], pProvider[ j ].dwCatalogEntryId ); if ( pdwCatalogIdArray[ i ] == pProvider[ j ].dwCatalogEntryId ) { // Verify the entry has room enough to be layered over if ( pProvider[ j ].ProtocolChain.ChainLen >= ( MAX_PROTOCOL_CHAIN - 1 ) ) { fprintf( stderr, "InstallIfsLspProtocolChain: Too many LSPs installed!\n"); goto cleanup; } // Save off the entry which we're layering over memcpy( &pLayeredEntries[ LayerIdx ], &pProvider[ j ], sizeof( pLayeredEntries[ 0 ] ) ); memcpy( &TempEntry, &pProvider[ j ], sizeof( TempEntry ) ); // Fill in the new LSP entry's name hr = StringCchPrintfW( pLayeredEntries[ LayerIdx ].szProtocol, WSAPROTOCOL_LEN, L"%s over [%s]", lpszLspName, pProvider[ j ].szProtocol ); if ( FAILED( hr ) ) { fprintf( stderr, "InstallIfsLspProtocolChains: StringCchPrintfW failed: 0x%x\n", hr ); goto cleanup; } // Check whether the selected entry contains non IFS LSPs in its chain if ( pProvider[ j ].ProtocolChain.ChainLen >= 2 ) { for(k=pProvider[ j ].ProtocolChain.ChainLen-2 ; k >= 0 ;k--) { bContainsNonIfs = IsNonIfsProvider( pProvider, iProviderCount, pProvider[ j ].ProtocolChain.ChainEntries[ k ] ); if ( TRUE == bContainsNonIfs ) { // Need to modify the pProvider entry to reference the // added LSP entry within its chain // In the 'modified' array make a space at location after 'k' InsertIdIntoProtocolChain( &pProvider[ j ], k+1, UPDATE_LSP_ENTRY ); // Save the index to the layer which corresponds to this entry pProvider[ j ].dwProviderReserved = LayerIdx + 1; // Need to fix the 'pLayeredEntry' as well BuildSubsetLspChain( &pLayeredEntries[ LayerIdx ], k+1, dwDummyLspId ); pLayeredEntries[ LayerIdx ].dwServiceFlags1 |= XP1_IFS_HANDLES; bLayeredOverNonIfs = TRUE; // Need to insert the IFS provider in all LSPs that are layered // above the location where the IFS provider was just inserted InsertIfsLspIntoAllChains( &TempEntry, pProvider, iProviderCount, LayerIdx + 1, k ); break; } } } // Need to setup the protocol chain in the pLayeredEntry if we haven't // already done so above if ( TRUE != bContainsNonIfs ) { InsertIdIntoProtocolChain( &pLayeredEntries[ LayerIdx ], 0, dwDummyLspId ); // The second entry is always the ID of the current pProvider[i] // In case of multiple LSPs then if we didn't do this the [1] index // would contain the ID of that LSP's dummy entry and not the entry // itself. pLayeredEntries[ LayerIdx ].ProtocolChain.ChainEntries[ 1 ] = TempEntry.dwCatalogEntryId; pLayeredEntries[ LayerIdx ].dwServiceFlags1 |= XP1_IFS_HANDLES; } LayerIdx++; } } } ASSERT( LayerIdx == (int)dwCatalogIdArrayCount ); // Create a unique GUID for each provider to install and install it for(i=0;i < (int)dwCatalogIdArrayCount ;i++) { if ( RPC_S_OK != UuidCreate( &pLayeredEntries[ i ].ProviderId ) ) { fprintf(stderr, "InstallIfsLspProtocolChains: UuidCreate failed: %d\n", GetLastError()); goto cleanup; } rc = InstallProvider( eCatalog, &pLayeredEntries[ i ].ProviderId, lpszLspFullPathAndFile, &pLayeredEntries[ i ], 1 ); if ( NO_ERROR != rc ) { fprintf(stderr, "InstallIfsLspProtocolChains: Unable to install the dummy LSP entry!\n"); goto cleanup; } } if ( TRUE == bLayeredOverNonIfs ) { // Enumerate the catalog again so we can find the catalog IDs pProviderNew = EnumerateProviders( eCatalog, &iProviderCountNew ); if ( NULL == pProvider ) { fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" ); goto cleanup; } for(i=0; i < (int)dwCatalogIdArrayCount ;i++) { pLayeredEntries[ i ].dwCatalogEntryId = GetCatalogIdForProviderGuid( &pLayeredEntries[ i ].ProviderId, pProviderNew, iProviderCountNew ); ASSERT( pLayeredEntries[ i ].dwCatalogEntryId != 0 ); } // Update the protocol chains of the modified entries to point to the just // installed providers for(i=0; i < iProviderCount ;i++) { if ( pProvider[ i ].dwProviderReserved == 0 ) continue; for(j=0; j < pProvider[ i ].ProtocolChain.ChainLen ;j++) { if ( UPDATE_LSP_ENTRY == pProvider[ i ].ProtocolChain.ChainEntries[ j ] ) { pProvider[ i ].ProtocolChain.ChainEntries[ j ] = pLayeredEntries[ pProvider[ i ].dwProviderReserved - 1 ].dwCatalogEntryId; pProvider[ i ].dwProviderReserved = 0; } } // Get the DLL path ProviderPathLen = MAX_PATH-1; rc = WSCGetProviderPath( &pProvider[ i ].ProviderId, wszLspDll, &ProviderPathLen, &err ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "InstallIfsLspProtocolChains: WSCGetProviderPath failed: %d\n", err ); goto cleanup; } // Update the providers which were modified rc = UpdateProvider( eCatalog, &pProvider[ i ].ProviderId, wszLspDll, &pProvider[ i ], 1, &err ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "InstallIfsLspProtocolChains: UpdateProvider failed: %d\n", err ); goto cleanup; } printf("Updated entry ID: %d: %S (chain len = %d)\n", pProvider[ i ].dwCatalogEntryId, pProvider[ i ].szProtocol, pProvider[ i ].ProtocolChain.ChainLen ); } FreeProviders( pProvider ); pProvider = NULL; FreeProviders( pProviderNew ); pProviderNew = NULL; /* { WSADATA wsd; WSACleanup(); WSAStartup( MAKEWORD(2,2), &wsd ); } */ pProvider = EnumerateProviders( eCatalog, &iProviderCount ); if ( NULL == pProvider ) { fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" ); goto cleanup; } // Allocate an array of DWORDs to contain the new catalog ordering pProviderOrder = (DWORD *)LspAlloc( iProviderCount * sizeof(DWORD), &err ); if ( NULL == pProviderOrder ) { fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" ); goto cleanup; } // First add the entries we layered over first idx = 0; for(i=0; i < (int)dwCatalogIdArrayCount ;i++) { pEntry = FindProviderById( pdwCatalogIdArray[ i ], pProvider, iProviderCount ); if ( NULL == pEntry ) { fprintf(stderr, "InstallIfsLspProtocolChain: Unable to find entry to reorder catalog!\n"); goto cleanup; } pEntry->dwProviderReserved = 1; pProviderOrder[ idx++ ] = pEntry->dwCatalogEntryId; } // Now go through the protocol chain of the entries we layered over and put those // LSP entries next in the new order for(i=0; i < (int)dwCatalogIdArrayCount ;i++) { pEntry = FindProviderById( pdwCatalogIdArray[ i ], pProvider, iProviderCount ); if ( NULL == pEntry ) { fprintf(stderr, "InstallIfsLspProtocolChain: Unable to find entry to reorder catalog!\n"); goto cleanup; } printf("Looping through: %d: %S (chain len = %d)\n", pEntry->dwCatalogEntryId, pEntry->szProtocol, pEntry->ProtocolChain.ChainLen ); for(j=1; j < pEntry->ProtocolChain.ChainLen-1 ;j++) { dwDummyLspId = FindDummyIdFromProtocolChainId( pEntry->ProtocolChain.ChainEntries[ j ], pProvider, iProviderCount ); printf(" Finding dummy ID for chain entry: %d is %d\n", pEntry->ProtocolChain.ChainEntries[ j ], dwDummyLspId ); for(k=0; k < iProviderCount ;k++) { if ( ( pProvider[ k ].ProtocolChain.ChainLen >= 2 ) && ( pProvider[ k ].ProtocolChain.ChainEntries[ 0 ] == dwDummyLspId ) && ( pProvider[ k ].dwProviderReserved == 0 ) ) { pProviderOrder[ idx++ ] = pProvider[ k ].dwCatalogEntryId; pProvider[ k ].dwProviderReserved = 1; printf(" Adding: %d\n", pProvider[ k ].dwCatalogEntryId ); } } } } // Now any catalog entry that wasn't already copied, copy it for(i=0; i < iProviderCount ;i++) { if ( pProvider[ i ].dwProviderReserved == 0 ) pProviderOrder[ idx++ ] = pProvider[ i ].dwCatalogEntryId; } ASSERT( idx == iProviderCount ); // Write the new catalog order rc = WriteProviderOrder( eCatalog, pProviderOrder, iProviderCount, &err ); if ( NO_ERROR != rc ) { fprintf( stderr, "InstallIfsLspProtocolChains: WriteProviderOrder failed: %d\n", err ); goto cleanup; } } else { // // Reorder the winsock catalog so the layered chain entries appear first. // Since we didn't have to modify any existing entries, all we need to do is // move the added entries to the head of the catalog // rc = ReorderCatalog( eCatalog, dwDummyLspId ); if ( NO_ERROR != rc ) { fprintf(stderr, "InstallIfsLspProtocolChains: Unable to reorder Winsock catalog!\n"); goto cleanup; } } retval = NO_ERROR; cleanup: if ( NULL != pProvider ) { FreeProviders( pProvider ); pProvider = NULL; } if ( NULL != pProviderNew ) { FreeProviders( pProviderNew ); pProviderNew = NULL; } if ( NULL != pProviderOrder ) { LspFree( pProviderOrder ); pProviderOrder = NULL; } return retval; }
// // Function: CreateDummyEntry // // Description: // This creates a single WSAPROTOCOL_INFOW structure which describes the // hidden "dummy" entry for an LSP. This is required since the layered // chain entries must reference the catalog ID of the LSP and a catalog ID // cannot be obtained until an entry is installed. // WSAPROTOCOL_INFOW * CreateDummyEntry( WINSOCK_CATALOG Catalog, INT CatalogId, WCHAR *lpwszLspName, BOOL IfsProvider ) { WSAPROTOCOL_INFOW *pProtocolInfo = NULL, *pDummyEntry = NULL, *pEntry = NULL; INT iProtocolCount = 0; int err; // Enumerate the catalog pProtocolInfo = EnumerateProviders( Catalog, &iProtocolCount ); if ( NULL == pProtocolInfo ) { fprintf(stderr, "CreateDummyEntry: EnumerateProviders failed!\n"); goto cleanup; } // Find one of the providers we are layering over pEntry = FindProviderById( CatalogId, pProtocolInfo, iProtocolCount ); if ( pEntry ) { // Allocate space and copy the provider structure pDummyEntry = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof( WSAPROTOCOL_INFOW ), &err ); if ( NULL == pDummyEntry ) { fprintf( stderr, "CreateDummyEntry: LspAlloc failed: %d\n", err ); goto cleanup; } // Copy the entry as a basis for the dummy entry memcpy( pDummyEntry, pEntry, sizeof( WSAPROTOCOL_INFOW ) ); } else { fprintf(stderr, "CreateDummyEntry: Error! Unable to find provider with ID of %d\n\n", CatalogId ); goto cleanup; } // Remove the IFS provider flag if the LSP doesn't support it if ( FALSE == IfsProvider ) pDummyEntry->dwServiceFlags1 &= (~XP1_IFS_HANDLES); // Set the flags indicating this is a hidden ("dummy") entry pDummyEntry->iSocketType = 0; pDummyEntry->iProtocol = 0; pDummyEntry->dwProviderFlags |= PFL_HIDDEN; pDummyEntry->dwProviderFlags &= (~PFL_MATCHES_PROTOCOL_ZERO); pDummyEntry->ProtocolChain.ChainLen = LAYERED_PROTOCOL; // Copy the LSP name wcsncpy( pDummyEntry->szProtocol, lpwszLspName, WSAPROTOCOL_LEN ); cleanup: if ( NULL != pProtocolInfo ) FreeProviders( pProtocolInfo ); return pDummyEntry; }
// // Function: InstallProvider // // Description: // This is a wrapper for the WSCInstallProvider function. Depending on // which catalog is specified, this routine calls the correct install // routine. // int InstallProvider( WINSOCK_CATALOG Catalog, // Which catalog are we operating on GUID *Guid, // GUID under which provider will be installed WCHAR *lpwszLspPath, // Path to LSP's DLL WSAPROTOCOL_INFOW *pProvider, // Array of provider structures to install INT iProviderCount // Number of providers in array ) { WSAPROTOCOL_INFOW *pEnumProviders = NULL, *pEntry = NULL; INT iEnumProviderCount, ErrorCode, rc = SOCKET_ERROR; #ifdef _WIN64 if ( LspCatalog32Only == Catalog ) { // Can't install only in 32-bit catalog from 64-bit fprintf( stderr, "InstallProvider: Error! It is not possible to install only " "in 32-bit catalog from 64-bit process!\n\n" ); goto cleanup; } else if ( LspCatalog64Only == Catalog ) { // Just need to call WSCInstallProvider rc = WSCInstallProvider( Guid, lpwszLspPath, pProvider, iProviderCount, &ErrorCode ); } else { // To install in both we must call WSCInstallProviderPath64_32 rc = WSCInstallProvider64_32( Guid, lpwszLspPath, pProvider, iProviderCount, &ErrorCode ); } #else if ( LspCatalog32Only == Catalog ) { // From a 32-bit process we can only install into 32-bit catalog rc = WSCInstallProvider( Guid, lpwszLspPath, pProvider, iProviderCount, &ErrorCode ); } else { // From a 32-bit process, we can't touch the 64-bit catalog at all fprintf( stderr, "InstallProvider: Error! It is not possible to install into " "the 64-bit catalog from a 32-bit process!\n\n" ); goto cleanup; } #endif if ( SOCKET_ERROR == rc ) { fprintf( stderr, "InstallProvider: WSCInstallProvider* failed: %d\n", ErrorCode ); goto cleanup; } // Go back and enumerate what we just installed pEnumProviders = EnumerateProviders( Catalog, &iEnumProviderCount ); if ( NULL == pEnumProviders ) { fprintf( stderr, "InstallProvider: EnumerateProviders failed!\n" ); goto cleanup; } // Make sure our entry is in the catalog pEntry = FindProviderByGuid( Guid, pEnumProviders, iEnumProviderCount ); if ( pEntry ) { printf( "Installed: [%4d] %S\n", pEntry->dwCatalogEntryId, pEntry->szProtocol ); } cleanup: if ( NULL != pEnumProviders ) FreeProviders( pEnumProviders ); return rc; }
// // Function: ReorderACatalog // // Description: // This routine enumerates a single catalog (32 or 64 bit) and reorders // the catalog according to the supplied catalog ID. That is, any provider // with that ID at the head of it's protocol chain is moved to the beginning // of the catalog. // DWORD * ReorderACatalog( WINSOCK_CATALOG Catalog, DWORD dwLayerId, INT *dwEntryCount ) { WSAPROTOCOL_INFOW *pProvider = NULL; DWORD *pdwProtocolOrder = NULL; INT iProviderCount = 0, idx, err, i; // Validate parameters if ( ( NULL == dwEntryCount ) || ( LspCatalogBoth == Catalog ) ) return NULL; // Enumerate the catalog pProvider = EnumerateProviders( Catalog, &iProviderCount ); if ( NULL == pProvider ) { fprintf( stderr, "ReorderACatalog: Unable to enumerate Winsock catalog!\n" ); goto cleanup; } // Allocate space for the array of catalog IDs (the catalog order) pdwProtocolOrder = (DWORD *) LspAlloc( sizeof( DWORD ) * iProviderCount, &err ); if ( NULL == pdwProtocolOrder ) { fprintf(stderr, "ReorderACatalog: LspAlloc failed: %d\n", GetLastError()); goto cleanup; } idx = 0; // First put all the layered entries at the head of the catalog for(i=0; i < iProviderCount ;i++) { if ( TRUE == IsIdInChain( &pProvider[ i ], dwLayerId ) ) { pdwProtocolOrder[ idx++ ] = pProvider[ i ].dwCatalogEntryId; } } // Put the remaining entries after the layered chain entries for(i=0; i < iProviderCount ;i++) { if ( FALSE == IsIdInChain( &pProvider[ i ], dwLayerId ) ) { pdwProtocolOrder[ idx++ ] = pProvider[ i ].dwCatalogEntryId; } } cleanup: if (pProvider) FreeProviders(pProvider); // Update the count *dwEntryCount = iProviderCount; return pdwProtocolOrder; }
// // Function: RemoveProvider // // Description: // This function removes a layered provider. Things can get tricky if // we're removing a layered provider which has been layered over by // another provider. This routine first creates the LSP map to determine // if other LSPs on the system reference the LSP we want to remove. If // there are we must fix those LSPs before deleting the target LSP. // If we're on a platform that supports WSCUpdateProvider its simply a // matter of removing any reference to the target LSP's layered protocol // chains and the dummy hidden entry. // // If we're not on a WSCUpdateProvider enabled system, then its very tricky. // We must uninstall the dependent LSPs first followed by reinstalling them // in the same order they were originally installed. For example if LSP1, // LSP2, and LSP3 are installed (in that order) and this routine is invoked // to remove LSP1, we must uninstall LSP3 and LSP2 followed by re-installing // (LSP2 first then LSP3). For each LSP added back we must fix up the protocol // chains of the next higher LSP so the reference the new catalog IDs (since // the action of installing an LSP assigns a new catalog ID). // // NOTE: If WSCUpdateProvider is not supported there is the possiblity of // another process changing the Winsock catalog at the same time we're // trying to fix it back up. If this occurs it is possible for the // corruption to occur. // int RemoveProvider( WINSOCK_CATALOG Catalog, // Catalog to remove an LSP from DWORD dwProviderId // Catalog ID of LSPs hidden entry ) { WSAPROTOCOL_INFOW *pProvider = NULL, *pLayeredEntries = NULL; LSP_ENTRY *pLspMap = NULL, *pLspMapEntryDel = NULL; DWORD *pdwCatalogOrder = NULL; INT iProviderCount = 0, iLayerCount = 0, iLspCount = 0, ErrorCode, Status, rc, i, j, k, l; Status = SOCKET_ERROR; // Enumerate the catalog pProvider = EnumerateProviders( Catalog, &iProviderCount ); if ( pProvider == NULL ) { fprintf( stderr, "RemoveProvider: Unable to enumerate catalog!\n" ); goto cleanup; } // Allocate an array to save of the provider order in case we have to // do uninstall and reinstall providers pdwCatalogOrder = (DWORD *) LspAlloc( sizeof( DWORD ) * iProviderCount, &ErrorCode ); if ( NULL == pdwCatalogOrder ) { fprintf( stderr, "RemoveProvider: LspAlloc failed: %d\n", ErrorCode ); goto cleanup; } for(i=0; i < iProviderCount ; i++) { pdwCatalogOrder[ i ] = pProvider[ i ].dwCatalogEntryId; } // Build a map of the LSPs installed on the system pLspMap = BuildLspMap( pProvider, iProviderCount, &iLspCount ); if ( NULL == pLspMap ) { fprintf( stderr, "RemoveProvider: Unable to build LSP map!\n" ); goto cleanup; } // Validate the catalog entry ID to remove pLspMapEntryDel = NULL; for(i=0; ( i < iLspCount ) && ( NULL == pLspMapEntryDel ) ; i++) { if ( dwProviderId == pLspMap[ i ].DummyEntry.dwCatalogEntryId ) { pLspMapEntryDel = &pLspMap[ i ]; } else { for(j=0; j < pLspMap[ i ].Count ; j++) { if ( dwProviderId == pLspMap[ i ].LayeredEntries[ j ].dwCatalogEntryId ) { // In this case the user supplied the catalog ID of an LSP protocol // chain entry -- not the hidden layered entry (dummy). Here we'll // reset the dwProviderId to that of the dummy hidden entry. // if ( pLspMap[ i ].OrphanedEntries != TRUE ) { printf( "Catalog ID %d is a layered protocol entry and not the hidden\n" "provider representing the entire LSP. The LSP which owns this\n" "provider is ID %d (%ws). This entire LSP will be removed!\n", dwProviderId, pLspMap[ i ].DummyEntry.dwCatalogEntryId, pLspMap[ i ].DummyEntry.szProtocol ); dwProviderId = pLspMap[ i ].DummyEntry.dwCatalogEntryId; pLspMapEntryDel = &pLspMap[ i ]; } else { printf( "Catalog ID %d is one of %d orphaned protocol entries.\n" "These entries could be causing serious problems and\n" "will be removed. The following providers are to be\n" "deleted:\n", pLspMap[ i ].LayeredEntries[ j ].dwCatalogEntryId, pLspMap[ i ].Count ); for(k=0; k < pLspMap[ i ].Count ; k++) { printf(" %d: %ws\n", pLspMap[ i ].LayeredEntries[ k ].dwCatalogEntryId, pLspMap[ i ].LayeredEntries[ k ].szProtocol ); } pLspMapEntryDel = &pLspMap[ i ]; } break; } } } } // Make sure we found a provider to remove if ( NULL == pLspMapEntryDel ) { fprintf( stderr, "\n\nError! Invalid Winsock catalog ID supplied: %d\n", dwProviderId ); goto cleanup; } // // Print which entries are being removed // printf( "\nThe following LSP entries will be removed:\n" ); if ( pLspMapEntryDel->OrphanedEntries != TRUE ) { printf( "LSP Hidden ID: %6d Name %ws\n", pLspMapEntryDel->DummyEntry.dwCatalogEntryId, pLspMapEntryDel->DummyEntry.szProtocol ); } else { printf( "Orphaned LSP protocol chain entries:\n"); } for(i=0; i < pLspMapEntryDel->Count ; i++) { printf( "LSP Layer ID: %6d Name %ws\n", pLspMapEntryDel->LayeredEntries[ i ].dwCatalogEntryId, pLspMapEntryDel->LayeredEntries[ i ].szProtocol ); } ErrorCode = NO_ERROR; if ( 0 != pLspMapEntryDel->DependentCount ) { int iLspIdx; printf( "\n\nOther LSPs are dependent on this one! " "Additional cleanup is required..\n\n" ); for(i=0; i < pLspMapEntryDel->DependentCount ; i++) { iLspIdx = pLspMapEntryDel->DependentLspIndexArray[ i ]; printf( "Fixing LSP index %d: %ws\n", pLspMap[ iLspIdx ].DummyEntry.dwCatalogEntryId, pLspMap[ iLspIdx ].DummyEntry.szProtocol ); // Remove any reference to the deleted LSPs dummy catalog ID for(j=0; j < pLspMap[ iLspIdx ].Count ; j++) { if ( IsIdInChain( &pLspMap[ iLspIdx ].LayeredEntries[ j ], pLspMapEntryDel->DummyEntry.dwCatalogEntryId ) ) { printf( "Removing ID %d from layered chain %d: %ws\n", pLspMapEntryDel->DummyEntry.dwCatalogEntryId, pLspMap[ iLspIdx ].LayeredEntries[ j ].dwCatalogEntryId, pLspMap[ iLspIdx ].LayeredEntries[ j ].szProtocol ); // Remove the deleted LSPs ID from the chain rc = RemoveIdFromChain( &pLspMap[ iLspIdx ].LayeredEntries[ j ], pLspMapEntryDel->DummyEntry.dwCatalogEntryId ); if ( FALSE == rc ) { fprintf( stderr, "RemoveProvider: ID not found in chain!\n" ); continue; } pLspMap[ iLspIdx ].LayerChanged[ j ] = TRUE; } } // Remove any reference to the deleted LSPs layered entries catalog // IDs from the layers of the dependent LSP for(l=0; l < pLspMapEntryDel->Count ; l++) { for(j=0; j < pLspMap[ iLspIdx ].Count ; j++) { if ( IsIdInChain( &pLspMap[ iLspIdx ].LayeredEntries[ j ], pLspMapEntryDel->LayeredEntries[ l ].dwCatalogEntryId ) ) { printf( "Removing ID %d from layered chain %d: %ws\n", pLspMapEntryDel->DummyEntry.dwCatalogEntryId, pLspMap[ iLspIdx ].LayeredEntries[ j ].dwCatalogEntryId, pLspMap[ iLspIdx ].LayeredEntries[ j ].szProtocol ); // Remove the deleted LSPs ID from the chain rc = RemoveIdFromChain( &pLspMap[ iLspIdx ].LayeredEntries[ j ], pLspMapEntryDel->LayeredEntries[ l ].dwCatalogEntryId ); if ( FALSE == rc ) { fprintf( stderr, "RemoveProvider: ID not found in chain!\n" ); continue; } pLspMap[ iLspIdx ].LayerChanged[ j ] = TRUE; } } } } // // All dependent LSPs should no longer reference any of the LSPs IDs which is // to be removed. Now we must write our changes back to the catalog. Life // is easy if we're on a system that supports WSCUpdateProvider. // if ( NULL != fnWscUpdateProvider ) { // // Life is good, simply call UpdateProvider on each entry in the LSP map // that was updated. // for(i=0; i < pLspMapEntryDel->DependentCount ; i++) { iLspIdx = pLspMapEntryDel->DependentLspIndexArray[ i ]; for(j=0; j < pLspMap[ iLspIdx ].Count; j++) { if ( TRUE == pLspMap[ iLspIdx ].LayerChanged[ j ] ) { rc = UpdateProvider( Catalog, &pLspMap[ iLspIdx ].LayeredEntries[ j ].ProviderId, pLspMap[ iLspIdx ].wszLspDll, &pLspMap[ iLspIdx ].LayeredEntries[ j ], 1, &ErrorCode ); } } } } else // fnWscUpdateProvider == NULL { int MaxLayers = 0; // // Life isn't so good. We need to remove all dependent LSPs first in the // reverse order they were installed so that if something fails, we // won't leave the catalog in a bad state. Then we need to reinstall // them in the same order they were originally installed and fix any // of the remaining dependent LSPs to reference the correct catalog IDs // before they are also reinstalled. // // Find the maximum protocol chain length of all the LSPs since we need // scratch space. We do the allocation first before making changes to // the catalog. MaxLayers = MaxLayeredChainCount( pLspMap, iLspCount ); pLayeredEntries = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof( WSAPROTOCOL_INFOW ) * MaxLayers, &ErrorCode ); if ( NULL == pLayeredEntries ) { fprintf( stderr, "RemoveProvider: LspAlloc failed: %d\n", ErrorCode ); goto cleanup; } // Remove the dependent LSPs in reverse order. NOTE: We don't have to // remove the dummy hidden entries since there is no information // in those providers that need updating. for(i=0; i < pLspMapEntryDel->DependentCount ; i++) { iLspIdx = pLspMapEntryDel->DependentLspIndexArray[ i ]; for(j=0; j < pLspMap[ iLspIdx ].LayeredGuidCount ; j++) { rc = DeinstallProvider( Catalog, &pLspMap[ iLspIdx ].LayeredGuids[ j ] ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "RemoveProvider: An error occured trying to remove an LSP.\n" "\t\tThis may be due to another process changing the Catalog\n" "\t\tAborting...\n" ); goto cleanup; } } } // All the dependent LSP layers have been removed, now add them // back in reverse order for(i=pLspMapEntryDel->DependentCount-1; i >= 0 ; i--) { iLspIdx = pLspMapEntryDel->DependentLspIndexArray[ i ]; // Install the layered entries for(j=0; j < pLspMap[ iLspIdx ].LayeredGuidCount ; j++) { iLayerCount = MaxLayers; rc = GetLayeredEntriesByGuid( pLayeredEntries, &iLayerCount, pLspMap[ iLspIdx ].LayeredEntries, pLspMap[ iLspIdx ].Count, &pLspMap[ iLspIdx ].LayeredGuids[ j ] ); rc = InstallProvider( Catalog, &pLspMap[ iLspIdx ].LayeredGuids[ j ], pLspMap[ iLspIdx ].wszLspDll, pLayeredEntries, iLayerCount ); } // Enumerate catalog to find new IDs DWORD ProviderLen = iProviderCount * sizeof( WSAPROTOCOL_INFOW ); int NewProviderCount = EnumerateProvidersExisting( Catalog, pProvider, &ProviderLen ); if ( SOCKET_ERROR == NewProviderCount ) { fprintf( stderr, "RemoveProvider: EnumerateProvidersExisting failed: %d\n", GetLastError() ); } // Update the old references to the new MapNewEntriesToOld( &pLspMap[ iLspIdx ], pProvider, NewProviderCount ); // Update the provider order array with the new provider values UpdateProviderOrder( &pLspMap[ iLspIdx ], pdwCatalogOrder, iProviderCount ); // For the remaining LSPs which we still need to install, update any // references to the removed LSPs with their new IDs for(k=i-1; k >= 0 ; k--) { int iLspIdx2 = pLspMapEntryDel->DependentLspIndexArray[ k ]; printf( "Updating IDs for index %d\n", iLspIdx2 ); for(l=0; l < pLspMap[ iLspIdx ].Count ; l++) { UpdateLspMap( &pLspMap[ iLspIdx2 ], pLspMap[ iLspIdx ].LayeredEntries[ l ].dwCatalogEntryId, pLspMap[ iLspIdx ].LayeredEntries[ l ].dwProviderReserved ); } } } // Reorder the catalog back to what it was before. Since we've added // back all the LSPs we removed earlier, the catalog should be the // same size as when we started. rc = WriteProviderOrder( Catalog, pdwCatalogOrder, iProviderCount, &ErrorCode ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "RemoveProvider: WriteProviderOrder failed: %d\n", ErrorCode ); } } } // // Now all dependencies have been fixed, remove the specified provider // // Remove the layered protocol entries for(i=0; i < pLspMapEntryDel->LayeredGuidCount ; i++) { rc = DeinstallProvider( Catalog, &pLspMapEntryDel->LayeredGuids[ i ] ); } // Remove the dummy entry rc = DeinstallProvider( Catalog, &pLspMapEntryDel->DummyEntry.ProviderId ); Status = NO_ERROR; cleanup: // // Cleanup allocations // if ( NULL != pLayeredEntries ) LspFree( pLayeredEntries ); if ( NULL != pProvider ) FreeProviders(pProvider); if ( NULL != pLspMap ) FreeLspMap( pLspMap, iLspCount ); if ( NULL != pdwCatalogOrder ) LspFree( pdwCatalogOrder ); return Status; }
// // Function: RemoveAllLayeredEntries // // Description: // In the event that the layered entries become totally hosed up. This // function will remove any non base provider. // int RemoveAllLayeredEntries( WINSOCK_CATALOG Catalog // Catalog to remove all LSPs from ) { WSAPROTOCOL_INFOW *pProviders = NULL, *pAssociated = NULL; WCHAR szGuidString[ MAX_PATH ]; LSP_ENTRY *pLspMap = NULL; INT iProviderCount, iAssociatedCount, iMaxCount, iLspCount = 0, Status, rc, i, j, k; Status = SOCKET_ERROR; // First enumerate the catalog pProviders = EnumerateProviders( Catalog, &iProviderCount ); if ( NULL == pProviders ) { fprintf(stderr, "RemoveAllLayeredEntries: Unable to enumerate catalog!\n"); goto cleanup; } // Build a mapping of the LSPs installed on the system pLspMap = BuildLspMap( pProviders, iProviderCount, &iLspCount ); if ( NULL == pLspMap ) { printf("\nNo LSPs to remove!\n"); goto cleanup; } iMaxCount = MaxLayeredChainCount( pLspMap, iLspCount ); pAssociated = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof( WSAPROTOCOL_INFOW ) * iMaxCount, &rc ); if ( NULL == pAssociated ) { fprintf( stderr, "RemoveAllLayeredEntries: LspAlloc failed: %d\n", rc ); goto cleanup; } printf( "\n%d LSPs installed:\n", iLspCount ); for(i=0; i < iLspCount ; i++) { if ( pLspMap[ i ].OrphanedEntries != TRUE ) { printf(" %d: %ws with %d layered entries\n", pLspMap[ i ].DummyEntry.dwCatalogEntryId, pLspMap[ i ].DummyEntry.szProtocol, pLspMap[ i ].Count ); } else { printf(" Orphaned LSP chain entries:\n"); for(j=0; j < pLspMap[ i ].Count ; j++) { printf("\t %d %ws\n", pLspMap[ i ].LayeredEntries[ j ].dwCatalogEntryId, pLspMap[ i ].LayeredEntries[ j ].szProtocol ); } } } printf("\nRemoving LSPs...\n\n"); for(i=0; i < iLspCount ; i++) { if ( pLspMap[ i ].OrphanedEntries != TRUE ) { // First remove the dummy entry printf( "Removing dummy entry for: %ws\n", pLspMap[ i ].DummyEntry.szProtocol ); rc = DeinstallProvider( Catalog, &pLspMap[ i ].DummyEntry.ProviderId ); if ( pLspMap[ i ].LayeredGuidCount > 0 ) printf("Removing the associated layered entries with GUIDs:\n"); for(j=0; j < pLspMap[ i ].LayeredGuidCount ; j++) { StringFromGUID2( pLspMap[ i ].LayeredGuids[ j ], szGuidString, MAX_PATH-1 ); printf( "\tGUID: %ws\n", szGuidString ); iAssociatedCount = iMaxCount; // Get a list of all providers under this GUID so we can print it out rc = GetLayeredEntriesByGuid( pAssociated, &iAssociatedCount, pLspMap[ i ].LayeredEntries, pLspMap[ i ].Count, &pLspMap[ i ].LayeredGuids[ j ] ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "RemoveAllLayeredProviders: GetLayeredEntriesByGuid failed!\n" ); goto cleanup; } for(k=0; k < iAssociatedCount ; k++) { printf("\t %d: %ws\n", pAssociated[ k ].dwCatalogEntryId, pAssociated[ k ].szProtocol ); } rc = DeinstallProvider( Catalog, &pLspMap[ i ].LayeredGuids[ j ] ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "RemoveAllLayeredProviders: DeinstallProvider failed!\n" ); } else { printf( " Uninstalled providers for %ws\n", szGuidString ); } } } else { printf("Removing the following orphaned entries:\n"); for(j=0; j < pLspMap[ i ].Count ; j++) { printf("\t %d: %ws\n", pLspMap[ i ].LayeredEntries[ j ].dwCatalogEntryId, pLspMap[ i ].LayeredEntries[ j ].szProtocol ); } for(j=0; j < pLspMap[ i ].LayeredGuidCount ; j++) { StringFromGUID2( pLspMap[ i ].LayeredGuids[ j ], szGuidString, MAX_PATH-1 ); rc = DeinstallProvider( Catalog, &pLspMap[ i ].LayeredGuids[ j ] ); if ( SOCKET_ERROR == rc ) { fprintf( stderr, "RemoveAllLayeredProviders: DeinstallProvider failed!\n"); } else { printf("\tUninstalled providers for %ws\n", szGuidString ); } } } } Status = NO_ERROR; cleanup: if ( NULL != pProviders ) FreeProviders( pProviders ); if ( NULL != pLspMap ) FreeLspMap( pLspMap, iLspCount ); if ( NULL != pAssociated ) LspFree( pAssociated ); return Status; }
// // Function: InstallProviderVista // // Description: // On Windows Vista and later there is a new LSP install function // (WSCInstallProviderAndChains) that performs all necessary installation // steps in a single call (instead of multiple WSCInstallProvider calls). // This function dynamically loads the function and invokes it to install // the LSP. The function either expects a NULL list of WSAPROTOCOL_INFOW // structures in which case it installs the LSP over each unique address // family, socket type, and protocol base provider on the system. Otherwise, // if the pdwCatalogIdArray specifies exact providers, this function builds // a list of those provider structures in which case the install API installs // the LSP over each instance of the address family, socket type and protocol // specified in the array. // int InstallProviderVista( WINSOCK_CATALOG eCatalog, // Which catalog to install LSP into __in_z WCHAR *lpszLspName, // String name of LSP __in_z WCHAR *lpszLspPathAndFile, // Location of LSP dll and dll name LPGUID providerGuid, DWORD dwCatalogIdArrayCount, // Number of entries in pdwCatalogIdArray DWORD *pdwCatalogIdArray, // Array of IDs to install over BOOL IfsProvider, BOOL InstallOverAll ) { LPWSCINSTALLPROVIDERANDCHAINS lpInstallProviderAndChains; WSAPROTOCOL_INFOW *protocolList = NULL; WSAPROTOCOL_INFOW *pEnumProviders = NULL; HMODULE hMod = NULL; DWORD dwEntryCount; char *lpInstallFunction = NULL; INT iEnumProviderCount; int rc, i, j, error; rc = SOCKET_ERROR; // // Dynamically load the function in order for this installer to run properly // on downlevel OSes // hMod = LoadLibrary("ws2_32.dll"); if ( NULL == hMod ) { fprintf(stderr, "Unable to load ws2_32.dll!\n"); goto cleanup; } #ifdef _WIN64 if ( ( eCatalog == LspCatalog32Only ) || ( eCatalog == LspCatalog64Only ) ) { fprintf(stderr, "New install API always installs into both catalogs!\n"); goto cleanup; } else { lpInstallFunction = "WSCInstallProviderAndChains64_32"; } #else if ( ( eCatalog == LspCatalog64Only) || ( eCatalog == LspCatalogBoth ) ) { fprintf(stderr, "Cannot install into 64-bit catalog from 32-bit process\n"); goto cleanup; } else { lpInstallFunction = "WSCInstallProviderAndChains"; } #endif // Load the new install function lpInstallProviderAndChains = (LPWSCINSTALLPROVIDERANDCHAINS) GetProcAddress( hMod, lpInstallFunction ); if ( NULL == lpInstallProviderAndChains ) { fprintf( stderr, "InstallLsp: Unable to load WSCInstallProviderAndChains function!\n"); rc = SOCKET_ERROR; goto cleanup; } if ( InstallOverAll ) { // // Install over all unique BSPs on the system so pass NULL for the provider list // rc = lpInstallProviderAndChains( providerGuid, lpszLspPathAndFile, lpszLspName, ( IfsProvider ? XP1_IFS_HANDLES : 0 ), NULL, NULL, NULL, &error ); if ( SOCKET_ERROR == rc ) { fprintf(stderr, "InstallProviderVista: %s failed: %d\n", lpInstallFunction, error ); goto cleanup; } } else { // // User specified a subset of providers to install over so build a list of // the corresponding WSAPROTOCOL_INFOW structures to pass to install call // protocolList = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof(WSAPROTOCOL_INFOW) * dwCatalogIdArrayCount, &error); if ( NULL == protocolList ) { fprintf(stderr, "InstallProviderVista: Out of memory!\n"); rc = SOCKET_ERROR; goto cleanup; } pEnumProviders = EnumerateProviders( eCatalog, &iEnumProviderCount ); if ( NULL == pEnumProviders ) { fprintf(stderr, "InstallProviderVista: Unable to enumerate catalog!\n"); rc = SOCKET_ERROR; goto cleanup; } // Build a list of protocol structures to layer over dwEntryCount = 0; for(i=0; i < (int)dwCatalogIdArrayCount ;i++) { for(j=0; j < iEnumProviderCount ;j++) { if ( pdwCatalogIdArray[i] == pEnumProviders[j].dwCatalogEntryId ) { memcpy( &protocolList[dwEntryCount++], &pEnumProviders[j], sizeof(WSAPROTOCOL_INFOW) ); } } } rc = lpInstallProviderAndChains( providerGuid, lpszLspPathAndFile, lpszLspName, ( IfsProvider ? XP1_IFS_HANDLES : 0 ), protocolList, dwEntryCount, NULL, &error ); if ( SOCKET_ERROR == rc ) { fprintf(stderr, "InstallProviderVista: %s failed: %d\n", lpInstallFunction, error ); goto cleanup; } } rc = NO_ERROR; cleanup: if ( NULL != hMod ) FreeLibrary( hMod ); if ( NULL != pEnumProviders ) FreeProviders( pEnumProviders ); if ( NULL != protocolList ) LspFree( protocolList ); return rc; }
// // Function: main // // Description: // Parse the command line arguments and call either the install, remove, // print, etc. routines. // int _cdecl main(int argc, char *argv[]) { WSADATA wsd; LPWSAPROTOCOL_INFOW pProtocolInfo = NULL; LSP_ENTRY *pLspMap=NULL; #ifdef _WIN64 WINSOCK_CATALOG eCatalog = LspCatalog64Only; #else WINSOCK_CATALOG eCatalog = LspCatalog32Only; #endif INT iTotalProtocols = 0, iLspCount = 0, i; DWORD *pdwCatalogIdArray = NULL, dwCatalogIdArrayCount = 0, // How many to install over dwRemoveCatalogId = 0; BOOL bInstall = TRUE, bInstallOverAll = FALSE, bRemoveAllLayeredEntries = FALSE, bPrintProviders = FALSE, bDisplayOnlyLayeredEntries = FALSE, bVerbose = FALSE, bMapLsp = FALSE, bArgsOkay = FALSE, bIFSProvider = FALSE; char *lpszLspName = NULL, *lpszLspPathAndFile = NULL, *lpszLspPathAndFile32 = NULL; int rc; //////////////////////////////////////////////////////////////////////////// // // Initialization and Command Line Parsing // //////////////////////////////////////////////////////////////////////////// // Load Winsock rc = WSAStartup( MAKEWORD(2,2), &wsd ); if ( 0 != rc ) { fprintf( stderr, "Unable to load Winsock: %d\n", rc ); return -1; } // Initialize data structures LspCreateHeap( &rc ); __try { InitializeCriticalSection( &gDebugCritSec ); } __except( EXCEPTION_EXECUTE_HANDLER ) { goto cleanup; } // First count how many catalog parameters are supplied so we can dynamically // allocate the right sized buffer for(i=1; i < argc ;i++) { if ( strncmp( argv[ i ], "-o", 2 ) == 0 ) dwCatalogIdArrayCount++; } // Allocate space for the array of catalog IDs if ( 0 < dwCatalogIdArrayCount ) { pdwCatalogIdArray = (DWORD *) LspAlloc( sizeof( DWORD ) * dwCatalogIdArrayCount, &rc ); if ( NULL == pdwCatalogIdArray ) { goto cleanup; } } // Set back to zero so we can use it as the index into our array dwCatalogIdArrayCount = 0; // Parse the command line for(i=1; i < argc ;i++) { if ( ( 2 != strlen( argv[i] ) ) && ( '-' != argv[i][0] ) && ( '/' != argv[i][0] ) ) { goto cleanup; } switch ( tolower( argv[i][1] ) ) { case 'a': // Install LSP over all currently installed providers bInstallOverAll = TRUE; break; case 'c': // For 64-bit: which catalog to operate on? if (i+1 >= argc) goto cleanup; switch (tolower(argv[i+1][0])) { case 'b': // Both Winsock catalogs eCatalog = LspCatalogBoth; break; case '6': // 64-bit Winsock catalog only eCatalog = LspCatalog64Only; break; case '3': // 32-bit Winsock catalog only eCatalog = LspCatalog32Only; break; default: goto cleanup; break; } i++; break; case 'd': // Full path and filename to LSP if ( i+1 >= argc ) goto cleanup; if (_strnicmp(argv[i], "-d32", 4)) lpszLspPathAndFile32 = argv[ ++i ]; else lpszLspPathAndFile = argv[ ++i ]; break; case 'f': // Uninstall all layered providers bRemoveAllLayeredEntries = TRUE; bInstall = FALSE; break; case 'h': // Install as an IFS provider bIFSProvider = TRUE; break; case 'i': // install bInstall = TRUE; break; case 'l': // print the layered providers only bPrintProviders = TRUE; bDisplayOnlyLayeredEntries = TRUE; break; case 'm': // Map and print the LSP structure bMapLsp = TRUE; bInstall = FALSE; break; case 'n': // name of the LSP to install (not the DLL name) if (i+1 >= argc) goto cleanup; lpszLspName = argv[++i]; break; case 'o': // catalog id (to install over) if (i+1 >= argc) goto cleanup; pdwCatalogIdArray[dwCatalogIdArrayCount++] = atoi(argv[++i]); break; case 'p': // print the catalog bPrintProviders = TRUE; bDisplayOnlyLayeredEntries = FALSE; break; case 'r': // remove an LSP bInstall = FALSE; if (i+1 >= argc) goto cleanup; dwRemoveCatalogId = atol(argv[++i]); break; case 'v': // verbose mode (when printing with -p option) bVerbose = TRUE; break; default: goto cleanup; break; } } #ifndef _WIN64 if ( LspCatalog64Only == eCatalog ) { fprintf(stderr, "\n\nUnable to manipulate 64-bit Winsock catalog from 32-bit process!\n\n"); goto cleanup; } #endif bArgsOkay = TRUE; gModule = LoadUpdateProviderFunction(); if ( TRUE == bPrintProviders ) { // Print the 32-bit catalog if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog32Only == eCatalog ) ) { printf( "\n\nWinsock 32-bit Catalog:\n" ); printf( "=======================\n" ); PrintProviders( LspCatalog32Only, bDisplayOnlyLayeredEntries, bVerbose ); } // Print the 64-bit catalog if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog64Only == eCatalog ) ) { printf( "\n\nWinsock 64-bit Catalog:\n" ); printf( "=======================\n" ); PrintProviders( LspCatalog64Only, bDisplayOnlyLayeredEntries, bVerbose ); } } else if ( TRUE == bInstall ) { if ( NULL == lpszLspPathAndFile ) { fprintf( stderr, "\n\nError! Please specify path and filename of LSP!\n\n"); bArgsOkay = FALSE; goto cleanup; } if ( TRUE == bInstallOverAll ) { // Make sure user didn't specify '-a' and '-o' flags if ( 0 != dwCatalogIdArrayCount ) { fprintf( stderr, "\n\nError! Cannot specify both '-a' and '-o' flags!\n\n" ); goto cleanup; } // Enumerate the appropriate catalog we will be working on pProtocolInfo = EnumerateProviders( eCatalog, &iTotalProtocols ); if ( NULL == pProtocolInfo ) { fprintf( stderr, "%s: EnumerateProviders: Unable to enumerate Winsock catalog\n", argv[ 0 ] ); goto cleanup; } // Count how many non layered protocol entries there are for(i=0; i < iTotalProtocols ;i++) { if ( LAYERED_PROTOCOL != pProtocolInfo[ i ].ProtocolChain.ChainLen ) dwCatalogIdArrayCount++; } // Allocate space for all the entries pdwCatalogIdArray = (DWORD *) LspAlloc( sizeof( DWORD ) * dwCatalogIdArrayCount, &rc ); if ( NULL == pdwCatalogIdArray ) { fprintf( stderr, "%s: LspAlloc failed: %d\n", argv[ 0 ], rc ); goto cleanup; } // Get the catalog IDs for all existing providers dwCatalogIdArrayCount = 0 ; for(i=0; i < iTotalProtocols ;i++) { if ( LAYERED_PROTOCOL != pProtocolInfo[ i ].ProtocolChain.ChainLen ) { pdwCatalogIdArray[ dwCatalogIdArrayCount++ ] = pProtocolInfo[ i ].dwCatalogEntryId; } } FreeProviders( pProtocolInfo ); pProtocolInfo = NULL; } // Install the LSP with the supplied parameters rc = InstallLsp( eCatalog, lpszLspName, lpszLspPathAndFile, lpszLspPathAndFile32, dwCatalogIdArrayCount, pdwCatalogIdArray, bIFSProvider, bInstallOverAll ); } else if ( TRUE == bMapLsp ) { // Display the 32-bit LSP catalog map if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog32Only == eCatalog ) ) { printf("\n32-bit Winsock LSP Map:\n\n"); pProtocolInfo = EnumerateProviders( LspCatalog32Only, &iTotalProtocols ); if ( NULL == pProtocolInfo ) { fprintf(stderr, "%s: EnumerateProviders: Unable to enumerate Winsock catalog\n", argv[ 0 ] ); goto cleanup; } pLspMap = BuildLspMap( pProtocolInfo, iTotalProtocols, &iLspCount ); if ( NULL == pLspMap ) { printf( "\nNo LSPs are installed\n\n" ); } else { PrintLspMap( pLspMap, iLspCount ); FreeLspMap( pLspMap, iLspCount ); pLspMap = NULL; } FreeProviders( pProtocolInfo ); pProtocolInfo = NULL; } // Display the 64-bit LSP catalog map if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog64Only == eCatalog ) ) { printf("\n64-bit Winsock LSP Map:\n\n"); pProtocolInfo = EnumerateProviders( LspCatalog64Only, &iTotalProtocols ); if ( NULL == pProtocolInfo ) { fprintf(stderr, "%s: EnumerateProviders: Unable to enumerate Winsock catalog\n", argv[ 0 ] ); goto cleanup; } pLspMap = BuildLspMap( pProtocolInfo, iTotalProtocols, &iLspCount ); if ( NULL == pLspMap ) { printf( "\nNo LSPs are installed\n\n" ); } else { PrintLspMap( pLspMap, iLspCount ); FreeLspMap( pLspMap, iLspCount ); pLspMap = NULL; } FreeProviders( pProtocolInfo ); pProtocolInfo = NULL; } } else { // We must be removing an LSP if ( TRUE == bRemoveAllLayeredEntries ) { if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog32Only == eCatalog ) ) RemoveAllLayeredEntries( LspCatalog32Only ); if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog64Only == eCatalog ) ) RemoveAllLayeredEntries( LspCatalog64Only ); } else { // Make sure a catalog entry to remove was supplied if ( dwRemoveCatalogId == 0 ) { bArgsOkay = FALSE; goto cleanup; } if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog32Only == eCatalog ) ) RemoveProvider( LspCatalog32Only, dwRemoveCatalogId ); if ( ( LspCatalogBoth == eCatalog ) || ( LspCatalog64Only == eCatalog ) ) RemoveProvider( LspCatalog64Only, dwRemoveCatalogId ); } } cleanup: if ( FALSE == bArgsOkay ) usage( argv[ 0 ] ); // // When invoked on Vista under non elevated permissions, the EXE is launched in // a new CMD window. The following getchar stops the window from exiting // immediately so you can see what its output was. // printf("Press any key to continue...\n"); getchar(); // // Free any dynamic allocations and/or handles // if ( NULL != pdwCatalogIdArray ) LspFree( pdwCatalogIdArray ); if ( NULL != pProtocolInfo) FreeProviders( pProtocolInfo ); if ( NULL != pLspMap ) FreeLspMap( pLspMap, iLspCount ); if ( NULL != gModule ) FreeLibrary( gModule ); LspDestroyHeap( ); DeleteCriticalSection( &gDebugCritSec ); WSACleanup(); return 0; }