Example #1
0
//
// 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;
}
Example #2
0
//
// 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: 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;
}