/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-1998 Microsoft Corporation
//
// Module Name:
//    incompat.cpp
//
// Abstract:
//    This file implements compatibility checking for various components.
//    The functions get executed by winnt32. It's purpose is to alert the user to possible
//    incompatibilities that may be encountered after performing an upgrade.
//
//
// Author:
//    matt thomlinson (mattt)
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////

#include "precomp.h"
#pragma hdrstop

HRESULT CertSrv_TestForIllegalUpgrade(BOOL *pfComplain);
extern HINSTANCE hInst;






/////////////////////////////////////////////////////////////////////////////
//++
//
// CertificateServerUpgradeCompatibilityCheck
//
// Routine Description:
//    This is the exported function, called to check for incompatibilities when
//    upgrading the machine. 
// 
//    Behavior: If Certificate server is installed on NT4, we wish to warn the user.
//
// Arguments:
//    pfnCompatibilityCallback - points to the callback function used to supply
//                               compatibility information to winnt32.exe.
//    pvContext - points to a context buffer supplied by winnt32.exe.
//    
//
// Return Value:
//    TRUE - either indicates that no incompatibility was detected or that
//           *pfnComaptibilityCallback() returned TRUE.
//    FALSE - *pfnCompatibilityCallback() returned FALSE
//
//--
/////////////////////////////////////////////////////////////////////////////

BOOL CertificateServerUpgradeCompatibilityCheck( PCOMPAIBILITYCALLBACK pfnCompatibilityCallback,
                                       LPVOID pvContext )
{
     BOOL  fReturnValue = (BOOL) TRUE;
     BOOL fComplain;

     // Is this an illegal upgrade?
     if ((S_OK == CertSrv_TestForIllegalUpgrade(&fComplain)) &&
		fComplain)
     {
        // It is necessary to display a compatibility warning.
        
        TCHAR tszDescription[MAX_PATH];       // size is arbitrary
        TCHAR tszHtmlName[MAX_PATH];
        TCHAR tszTextName[MAX_PATH];

        COMPATIBILITY_ENTRY  CompatibilityEntry;
        ZeroMemory( &CompatibilityEntry, sizeof( CompatibilityEntry ) );
        
        // Set the Description string.
        
        *tszDescription = TEXT( '\0' );

        LoadString( hInst,
                    IDS_CERTSRV_UPGRADE_WARNING,
                    tszDescription,
                    sizeof(tszDescription)/sizeof(tszDescription[0]) );

        // Set the HTML file name.             
        _tcscpy( tszHtmlName, TEXT( "CompData\\certsrv.htm" ) );

        // Set the TEXT file name.             
        _tcscpy( tszTextName, TEXT( "CompData\\certsrv.txt" ) );

        // Build the COMPATIBILITY_ENTRY structure to pass to *pfnCompatibilityCallback().
        CompatibilityEntry.Description = tszDescription;
        CompatibilityEntry.HtmlName = tszHtmlName;
        CompatibilityEntry.TextName = tszTextName;

        // Execute the callback function.
        fReturnValue = pfnCompatibilityCallback( (PCOMPATIBILITY_ENTRY) &CompatibilityEntry,
                                                 pvContext );
     }
     else
     {
        // It is not necessary to display a compatibility warning.

        fReturnValue = (BOOL) TRUE;
     } // Is it necessary to display a compatibility warning?
  
   return ( fReturnValue );
}



HRESULT CertSrv_TestForIllegalUpgrade(BOOL *pfComplain)
{
    HRESULT hr = S_OK;
    SC_HANDLE hSC=NULL, hSvc=NULL;
    OSVERSIONINFO osVer;

    // only complain about NT4 certsvr upgrades

    *pfComplain = FALSE;
    osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    if(! GetVersionEx(&osVer) )
    {   
	// error getting version, can't be NT4
        hr = GetLastError(); 
        goto error;
    }

    if ((osVer.dwPlatformId != VER_PLATFORM_WIN32_NT) ||
        (osVer.dwMajorVersion != 4))
    {
        goto NoComplaint;
	// not NT4, must be ok
    }

    // now the hard part -- open the service to see if it exists
    hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
    if (hSC == NULL)
    {
        hr = GetLastError();
        goto error;
    }

    hSvc = OpenService(hSC, TEXT("CertSvc"), SERVICE_QUERY_CONFIG);
    if (hSvc == NULL)
    {
       hr = GetLastError();
       if (ERROR_SERVICE_DOES_NOT_EXIST == hr)
            goto NoComplaint;
       goto error;
    }

    // failed version check and service is installed 
    *pfComplain = TRUE;
            
NoComplaint:
    hr = S_OK;

error:

    if (NULL != hSC)
        CloseServiceHandle(hSC);

    if (NULL != hSvc)
        CloseServiceHandle(hSvc);

    return hr;
}

BOOL
IsStandardServerSKU(
    PBOOL pIsServer
    )
/////////////////////////////////////////////////////////////////////////////
//++
//
// IsStandardServerSKU
//
// Routine Description:
//    This routine determines if the user is running the standard server
//    SKU
// 
//
// Arguments:
//    pIsServer - indicates if the server is the standard server SKU
//                or not.
//
// Return Value:
//    Indicates success of the check
//
//--
/////////////////////////////////////////////////////////////////////////////
{
    BOOL  fReturnValue = (BOOL) FALSE;
    OSVERSIONINFOEX  VersionInfo;
    BOOL  IsServer = FALSE;

     //
     // get the current SKU.
     //
     VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
     if (GetVersionEx((OSVERSIONINFO *)&VersionInfo)) {
         fReturnValue = TRUE; 
         //
         // is it some sort of server SKU?
         //
         if (VersionInfo.wProductType != VER_NT_WORKSTATION) {
    
             //
             // standard server or a server variant?
             //
             if ((VersionInfo.wSuiteMask & (VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER)) == 0) {
                 //
                 // it's standard server
                 //
                 IsServer = TRUE;
             }
    
         }

         *pIsServer = IsServer;

     }

     return(fReturnValue);

}



/////////////////////////////////////////////////////////////////////////////
//++
//
// ProcessorUpgradeCompatibilityCheck
//
// Routine Description:
//    This is the exported function, called to check for incompatibilities when
//    upgrading the machine. 
// 
//    Behavior: If the current processor count is > that allowed after upgrade,
//              a warning is generated.
//
// Arguments:
//    pfnCompatibilityCallback - points to the callback function used to supply
//                               compatibility information to winnt32.exe.
//    pvContext - points to a context buffer supplied by winnt32.exe.
//    
//
// Return Value:
//    TRUE - either indicates that no incompatibility was detected or that
//           *pfnComaptibilityCallback() returned TRUE.
//    FALSE - *pfnCompatibilityCallback() returned FALSE
//
//--
/////////////////////////////////////////////////////////////////////////////

BOOL ProcessorUpgradeCompatibilityCheck( PCOMPAIBILITYCALLBACK pfnCompatibilityCallback,
                                       LPVOID pvContext )
{
     BOOL  fReturnValue = (BOOL) TRUE;
     BOOL fComplain = FALSE;
     BOOL IsServer = FALSE;
     SYSTEM_INFO SysInfo;
     ULONG SourceSkuId;
     ULONG DontCare;

     
     //
     // we only care about standard server SKU.
     //
     SourceSkuId = DetermineSourceProduct(&DontCare,NULL);

     if ( SourceSkuId == COMPLIANCE_SKU_NTSFULL || SourceSkuId == COMPLIANCE_SKU_NTSU) {
         //
         // we only allow 2 processors on standard server.
         //
         DWORD AllowedCount = 2;

         GetSystemInfo(&SysInfo);
         if (SysInfo.dwNumberOfProcessors > AllowedCount) {
             fComplain = TRUE;
         }                      
     }

     // Is this an illegal upgrade?
     if (fComplain)
     {
        // It is necessary to display a compatibility warning.
        
        TCHAR tszDescription[MAX_PATH];       // size is arbitrary
        TCHAR tszHtmlName[MAX_PATH];
        TCHAR tszTextName[MAX_PATH];

        COMPATIBILITY_ENTRY  CompatibilityEntry;
        ZeroMemory( &CompatibilityEntry, sizeof( CompatibilityEntry ) );
        
        // Set the Description string.
        
        *tszDescription = TEXT( '\0' );

        LoadString( hInst,
                    IDS_PROCESSOR_UPGRADE_WARNING,
                    tszDescription,
                    sizeof(tszDescription)/sizeof(tszDescription[0]) );

        // Set the HTML file name.             
        _tcscpy( tszHtmlName, TEXT( "CompData\\proccnt.htm" ) );

        // Set the TEXT file name.             
        _tcscpy( tszTextName, TEXT( "CompData\\proccnt.txt" ) );

        // Build the COMPATIBILITY_ENTRY structure to pass to *pfnCompatibilityCallback().
        CompatibilityEntry.Description = tszDescription;
        CompatibilityEntry.HtmlName = tszHtmlName;
        CompatibilityEntry.TextName = tszTextName;

        // Execute the callback function.
        fReturnValue = pfnCompatibilityCallback( (PCOMPATIBILITY_ENTRY) &CompatibilityEntry,
                                                 pvContext );
     }
     else
     {
        // It is not necessary to display a compatibility warning.

        fReturnValue = (BOOL) TRUE;
     } // Is it necessary to display a compatibility warning?
  
   return ( fReturnValue );
}