You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2228 lines
62 KiB
2228 lines
62 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
compliance.c
|
|
|
|
Abstract:
|
|
|
|
compliance checking routines.
|
|
|
|
Author:
|
|
|
|
Andrew Ritz (andrewr) 2-Sept-1998
|
|
|
|
Revision History:
|
|
|
|
2-Sept-1998 (andrewr) - created
|
|
|
|
|
|
Notes:
|
|
|
|
These routines are for compliance checking:
|
|
|
|
They check to see if an upgrade is allowed from the specified source to the destination.
|
|
Since there are so many SKUs to be supported, it's necessary to have a small framework
|
|
in place to handle all of these cases. There are generally three parts to the compliance
|
|
check:
|
|
|
|
1) retreive source information and determine what SKU you want to install
|
|
2) retrieve target information and determine what you are installing over
|
|
3) do the actual compliance check of the target against the source to determine if upgrades
|
|
are allowed, or if any installations are allowed from the target to the source.
|
|
|
|
These types of checks need to be run in both kernel-mode and user-mode installations, so this
|
|
common code library was created. The kernel-mode specific code is in an #ifdef KERNEL_MODE
|
|
block, and the usermode-specific code is in the #else branch. Common code is outside of
|
|
any #ifdef. This library is only to be run (will only link with) setupdd.sys or winnt32a|u.dll.
|
|
So when you change this code, keep in mind that it needs to run in both kernel mode and user mode.
|
|
|
|
Also note that we have to do a bunch of handwaving since NT supports upgrades from win95. Because of
|
|
this, we cannot simply read the setupreg.hiv for some information about the installation. Instead, we
|
|
encode some additional information into setupp.ini (which is encoded in such a way as to discourage
|
|
tinkering with it, but it by no means secure. It provides about the same level of security (obscurity?!?)
|
|
as setupreg.hiv gave us in the past.)
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
#ifdef KERNEL_MODE
|
|
#include "textmode.h"
|
|
#else
|
|
#include "winnt32.h"
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#include "COMPLIANCE.H"
|
|
#include "crcmodel.h"
|
|
|
|
#ifdef KERNEL_MODE
|
|
#define assert(x) ASSERT(x);
|
|
#else
|
|
#if DBG
|
|
#define assert(x) if (!(x)) DebugBreak();
|
|
#else
|
|
#define assert(x)
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// NOTE - this MUST match setup\textmode\kernel\spconfig.c's array of product suites
|
|
// NOTE - need to handle terminal server, as well as citrix terminal server on NT3.51
|
|
//
|
|
#define SUITE_VALUES COMPLIANCE_INSTALLSUITE_SBS, \
|
|
COMPLIANCE_INSTALLSUITE_ENT, \
|
|
COMPLIANCE_INSTALLSUITE_BACK, \
|
|
COMPLIANCE_INSTALLSUITE_COMM, \
|
|
COMPLIANCE_INSTALLSUITE_HYDRA, \
|
|
COMPLIANCE_INSTALLSUITE_SBSR, \
|
|
COMPLIANCE_INSTALLSUITE_EMBED, \
|
|
COMPLIANCE_INSTALLSUITE_DTC, \
|
|
COMPLIANCE_INSTALLSUITE_PER, \
|
|
COMPLIANCE_INSTALLSUITE_BLADE
|
|
|
|
|
|
//
|
|
// globals
|
|
//
|
|
|
|
//
|
|
// Common functions shared between user-mode and kernel mode
|
|
//
|
|
|
|
|
|
DWORD
|
|
CRC_32(LPBYTE pb, DWORD cb)
|
|
{
|
|
|
|
// CRC-32 algorithm used in PKZip, AUTODIN II, Ethernet, and FDDI
|
|
// but xor out (xorot) has been changed from 0xFFFFFFFF to 0 so
|
|
// we can store the CRC at the end of the block and expect 0 to be
|
|
// the value of the CRC of the resulting block (including the stored
|
|
// CRC).
|
|
|
|
cm_t cmt = {
|
|
32, // cm_width Parameter: Width in bits [8,32].
|
|
0x04C11DB7, // cm_poly Parameter: The algorithm's polynomial.
|
|
0xFFFFFFFF, // cm_init Parameter: Initial register value.
|
|
TRUE, // cm_refin Parameter: Reflect input bytes?
|
|
TRUE, // cm_refot Parameter: Reflect output CRC?
|
|
0, // cm_xorot Parameter: XOR this to output CRC.
|
|
0 // cm_reg Context: Context during execution.
|
|
};
|
|
|
|
// Documented test case for CRC-32:
|
|
// Checking "123456789" should return 0xCBF43926
|
|
|
|
cm_ini(&cmt);
|
|
cm_blk(&cmt, pb, cb);
|
|
|
|
return cm_crc(&cmt);
|
|
}
|
|
|
|
#ifdef KERNEL_MODE
|
|
|
|
BOOLEAN
|
|
PsGetVersion(
|
|
PULONG MajorVersion OPTIONAL,
|
|
PULONG MinorVersion OPTIONAL,
|
|
PULONG BuildNumber OPTIONAL,
|
|
PUNICODE_STRING CSDVersion OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
DetermineSourceVersionInfo(
|
|
OUT PDWORD Version,
|
|
OUT PDWORD BuildNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the version and build number from
|
|
|
|
Arguments:
|
|
|
|
InfPath - Fully qualified path to a inf file containing
|
|
[version] section.
|
|
|
|
Version - Place holder for version information
|
|
BuildNumber - Place holder for build number
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if Version and Build number are successfully extracted, otherwise
|
|
returns FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
ULONG Major = 0, Minor = 0, Build = 0;
|
|
|
|
//
|
|
// We use PsGetVersion(...) API exported by the kernel
|
|
//
|
|
PsGetVersion(&Major, &Minor, &Build, NULL);
|
|
|
|
if ((Major > 0) || (Minor > 0) || (Build > 0)) {
|
|
Result = TRUE;
|
|
|
|
if (Version)
|
|
*Version = Major * 100 + Minor;
|
|
|
|
if (BuildNumber)
|
|
*BuildNumber = Build;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
#else
|
|
|
|
BOOLEAN
|
|
pGetVersionFromStr(
|
|
TCHAR *VersionStr,
|
|
DWORD *Version,
|
|
DWORD *BuildNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a string with version information like "5.0.2195.1"
|
|
and returns the values.
|
|
|
|
Arguments:
|
|
|
|
VersionStr - The version string (most of the time its DriverVer string
|
|
from the [Version] section in a inf like dosnet.inf)
|
|
Version - The version (i.e. major * 100 + minor)
|
|
BuildNumber - The build number like 2195
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if Version and Build number are successfully extracted, otherwise
|
|
returns FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
DWORD MajorVer = 0, MinorVer = 0, BuildNum = 0;
|
|
TCHAR *EndPtr;
|
|
TCHAR *EndChar;
|
|
TCHAR TempBuff[64] = {0};
|
|
|
|
if (VersionStr) {
|
|
EndPtr = _tcschr(VersionStr, TEXT('.'));
|
|
|
|
if (EndPtr) {
|
|
_tcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
|
|
MajorVer = _tcstol(TempBuff, &EndChar, 10);
|
|
|
|
VersionStr = EndPtr + 1;
|
|
|
|
if (VersionStr) {
|
|
EndPtr = _tcschr(VersionStr, TEXT('.'));
|
|
|
|
if (EndPtr) {
|
|
memset(TempBuff, 0, sizeof(TempBuff));
|
|
_tcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
|
|
MinorVer = _tcstol(TempBuff, &EndChar, 10);
|
|
|
|
VersionStr = EndPtr + 1;
|
|
|
|
if (VersionStr) {
|
|
EndPtr = _tcschr(VersionStr, TEXT('.'));
|
|
|
|
if (EndPtr) {
|
|
memset(TempBuff, 0, sizeof(TempBuff));
|
|
_tcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
|
|
|
|
BuildNum = _tcstol(TempBuff, &EndChar, 10);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((MajorVer > 0) || (MinorVer > 0) || (BuildNum > 0))
|
|
Result = TRUE;
|
|
|
|
if (Result) {
|
|
if (Version)
|
|
*Version = (MajorVer * 100) + MinorVer;
|
|
|
|
if (BuildNumber)
|
|
*BuildNumber = BuildNum;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
DetermineSourceVersionInfo(
|
|
IN TCHAR *InfPath,
|
|
OUT PDWORD Version,
|
|
OUT PDWORD BuildNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the version and build number from
|
|
|
|
Arguments:
|
|
|
|
InfPath - Fully qualified path to inf file containing
|
|
[version] section.
|
|
|
|
Version - Place holder for version information
|
|
BuildNumber - Place holder for build number
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if Version and Build number are successfully extracted, otherwise
|
|
returns FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
TCHAR FileName[MAX_PATH];
|
|
TCHAR Buffer[64] = {0};
|
|
DWORD CharCount;
|
|
|
|
CharCount = GetPrivateProfileString(TEXT("Version"), TEXT("DriverVer"), TEXT("0"),
|
|
Buffer, sizeof(Buffer)/sizeof(TCHAR), InfPath);
|
|
|
|
if (CharCount) {
|
|
TCHAR *TempPtr = _tcschr(Buffer, TEXT(','));
|
|
|
|
if (TempPtr) {
|
|
TempPtr++;
|
|
Result = pGetVersionFromStr(TempPtr, Version, BuildNumber);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
DWORD
|
|
DetermineSourceProduct(
|
|
OUT DWORD *SourceSkuVariation,
|
|
IN PCOMPLIANCE_DATA Target
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines which sku you are installing.
|
|
|
|
It does this by looking at
|
|
a) the source install type
|
|
b) the source install "sku" (stepup or full install)
|
|
c) source suite type
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a COMPLIANCE_SKU_* flag indicating what sku you are installing, and COMPLIANCE_SKU_NONE for error
|
|
|
|
--*/
|
|
|
|
{
|
|
COMPLIANCE_DATA cd;
|
|
|
|
DWORD sku = COMPLIANCE_SKU_NONE;
|
|
|
|
*SourceSkuVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
|
|
#ifdef KERNEL_MODE
|
|
|
|
if (!pSpGetCurrentInstallVariation(PidString,SourceSkuVariation)) {
|
|
return(COMPLIANCE_SKU_NONE);
|
|
}
|
|
|
|
if (!pSpDetermineSourceProduct(&cd)) {
|
|
return(COMPLIANCE_SKU_NONE);
|
|
}
|
|
#else
|
|
if (!GetSourceInstallVariation(SourceSkuVariation)) {
|
|
return(COMPLIANCE_SKU_NONE);
|
|
}
|
|
|
|
if (!GetSourceComplianceData(&cd,Target)){
|
|
return(COMPLIANCE_SKU_NONE);
|
|
}
|
|
#endif
|
|
|
|
switch (cd.InstallType) {
|
|
case COMPLIANCE_INSTALLTYPE_NTW:
|
|
// suite check is done because kernel mode does not detect personal for the type.
|
|
if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_PER) {
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTWPU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTWPFULL;
|
|
}
|
|
} else {
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTW32U;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTWFULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case COMPLIANCE_INSTALLTYPE_NTWP:
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTWPU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTWPFULL;
|
|
}
|
|
break;
|
|
|
|
case COMPLIANCE_INSTALLTYPE_NTS:
|
|
// suite checks are done because kernel mode does not detect dtc or ent for the type.
|
|
if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_DTC) {
|
|
sku = COMPLIANCE_SKU_NTSDTC;
|
|
} else if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_BLADE) {
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSBU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSB;
|
|
}
|
|
} else if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_SBSR) {
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSBSU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSBS;
|
|
}
|
|
} else if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_ENT) {
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSEU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSEFULL;
|
|
}
|
|
} else {
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSFULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case COMPLIANCE_INSTALLTYPE_NTSB:
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSBU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSB;
|
|
}
|
|
break;
|
|
|
|
case COMPLIANCE_INSTALLTYPE_NTSBS:
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSBSU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSBS;
|
|
}
|
|
break;
|
|
|
|
case COMPLIANCE_INSTALLTYPE_NTSE:
|
|
if (cd.RequiresValidation) {
|
|
sku = COMPLIANCE_SKU_NTSEU;
|
|
} else {
|
|
sku = COMPLIANCE_SKU_NTSEFULL;
|
|
}
|
|
break;
|
|
|
|
case COMPLIANCE_INSTALLTYPE_NTSDTC:
|
|
sku = COMPLIANCE_SKU_NTSDTC;
|
|
break;
|
|
|
|
default:
|
|
sku = COMPLIANCE_SKU_NONE;
|
|
}
|
|
|
|
|
|
return( sku );
|
|
}
|
|
|
|
BOOLEAN
|
|
CheckCompliance(
|
|
IN DWORD SourceSku,
|
|
IN DWORD SourceSkuVariation,
|
|
IN DWORD SourceVersion,
|
|
IN DWORD SourceBuildNum,
|
|
IN PCOMPLIANCE_DATA pcd,
|
|
OUT PUINT Reason,
|
|
OUT PBOOL NoUpgradeAllowed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routines determines if your current installation is compliant (if you are allowed to proceed with your installation).
|
|
|
|
To do this, it retreives your current installation and determines the sku for your source installation.
|
|
|
|
It then compares the target against the source to determine if the source sku allows an upgrade/clean install
|
|
from your target installation.
|
|
|
|
Arguments:
|
|
|
|
SourceSku - a COMPLIANCE_SKU_* flag indicating the source type
|
|
SourceSkuVariation - a COMPLIANCE_VARIATION_* flag indicating what variation the source is
|
|
pcd - pointer to a COMPLIANCE_DATA structure describing the current source
|
|
Reason - COMPLIANCEERR_ flag indicating why compliance check fails
|
|
|
|
Return Value:
|
|
|
|
TRUE if the install is compliant, FALSE if it isn't allowed
|
|
|
|
NOTE : The error value could be set irrespective of return value of TRUE or false. For full media
|
|
the return value is always true and only the "NoUpgradeAllowed" variable gets set indicating
|
|
whether upgrade is allowed or not.
|
|
|
|
--*/
|
|
{
|
|
PCCMEDIA SourceMedia = 0;
|
|
BOOL UpgradeAllowed = FALSE;
|
|
BOOLEAN Result;
|
|
TCHAR DebugStr[1024];
|
|
|
|
if (pcd) {
|
|
SourceMedia = CCMediaCreate(SourceSku, SourceSkuVariation,
|
|
SourceVersion, SourceBuildNum);
|
|
|
|
if (SourceMedia) {
|
|
Result = SourceMedia->CheckInstall(SourceMedia, pcd, Reason, &UpgradeAllowed);
|
|
*NoUpgradeAllowed = (UpgradeAllowed) ? FALSE : TRUE;
|
|
|
|
CCMemFree(SourceMedia);
|
|
} else {
|
|
*Reason = COMPLIANCEERR_UNKNOWNSOURCE;
|
|
*NoUpgradeAllowed = TRUE;
|
|
Result = FALSE;
|
|
}
|
|
} else {
|
|
*Reason = COMPLIANCEERR_UNKNOWNTARGET;
|
|
*NoUpgradeAllowed = TRUE;
|
|
Result = FALSE;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL IsValidStepUpMode(
|
|
CHAR *StepUpArray,
|
|
ULONG *StepUpMode
|
|
)
|
|
{
|
|
|
|
DWORD crcvalue,outval;
|
|
|
|
#define BASE 'a'
|
|
|
|
|
|
crcvalue = CRC_32( (LPBYTE)StepUpArray, 10 );
|
|
RtlCopyMemory(&outval,&StepUpArray[10],sizeof(DWORD));
|
|
if (crcvalue != outval ) {
|
|
|
|
#ifdef DBG
|
|
|
|
#ifdef KERNEL_MODE
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Setup: SpGetStepUpMode CRC didn't match for StepUpArray: %x %x\n", crcvalue, outval ));
|
|
#else
|
|
OutputDebugString(TEXT("IsValidStepUpMode CRC failed\n"));
|
|
#endif
|
|
|
|
#endif // DBG
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
if ((StepUpArray[3]-BASE)%2) {
|
|
if ((StepUpArray[5]-BASE)%2) {
|
|
|
|
#ifdef DBG
|
|
|
|
#ifdef KERNEL_MODE
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "setup: this is stepup mode\n"));
|
|
#else
|
|
OutputDebugString(TEXT("this is stepup mode\n"));
|
|
#endif
|
|
|
|
#endif //DBG
|
|
|
|
*StepUpMode = 1;
|
|
return(TRUE);
|
|
} else {
|
|
#ifdef DBG
|
|
|
|
#ifdef KERNEL_MODE
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "setup: bad pid signature\n"));
|
|
#else
|
|
OutputDebugString(TEXT("bad pid signature\n"));
|
|
#endif
|
|
|
|
#endif //DBG
|
|
|
|
return(FALSE);
|
|
}
|
|
} else
|
|
if ((StepUpArray[5]-BASE)%2) {
|
|
|
|
#ifdef DBG
|
|
|
|
#ifdef KERNEL_MODE
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "setup: bad pid signature\n"));
|
|
#else
|
|
OutputDebugString(TEXT("bad pid signature\n"));
|
|
#endif
|
|
|
|
#endif //DBG
|
|
|
|
return(FALSE);
|
|
} else {
|
|
*StepUpMode = 0;
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// should never make it here
|
|
//
|
|
assert(FALSE);
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Kernel mode only functions
|
|
//
|
|
#ifdef KERNEL_MODE
|
|
BOOL
|
|
pSpDetermineSourceProduct(
|
|
PCOMPLIANCE_DATA pcd
|
|
)
|
|
{
|
|
ULONG i,tmp;
|
|
|
|
TCHAR Dbg[1000];
|
|
|
|
DWORD SuiteArray[] = { SUITE_VALUES };
|
|
|
|
#define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
|
|
|
|
RtlZeroMemory(pcd,sizeof(COMPLIANCE_DATA));
|
|
|
|
pcd->InstallType = AdvancedServer ?
|
|
COMPLIANCE_INSTALLTYPE_NTS :
|
|
COMPLIANCE_INSTALLTYPE_NTW ;
|
|
pcd->RequiresValidation = (StepUpMode) ? TRUE : FALSE;
|
|
|
|
|
|
for (i = 0,tmp=SuiteType; i<SuiteArrayCount;i++) {
|
|
if (tmp&1) {
|
|
pcd->InstallSuite |= SuiteArray[i];
|
|
}
|
|
tmp = tmp >> 1;
|
|
}
|
|
|
|
if (pcd->InstallSuite == COMPLIANCE_INSTALLSUITE_UNKNOWN) {
|
|
pcd->InstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
pSpGetCurrentInstallVariation(
|
|
IN PWSTR szPid20,
|
|
OUT LPDWORD CurrentInstallVariation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines what "variation" you have installed (retail,oem, select,etc.)
|
|
|
|
Arguments:
|
|
|
|
CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
|
|
|
|
It looks at the product Id in the registry to determine this, assuming that the
|
|
product ID is a PID2.0 string.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOLEAN retval = FALSE;
|
|
WCHAR Pid20Site[4] = {0};
|
|
|
|
assert(CurrentInstallVariation != NULL);
|
|
assert(szPid20 != NULL);
|
|
|
|
if (!CurrentInstallVariation) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!szPid20 || (wcslen(szPid20) < 5)) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
|
|
return(TRUE);
|
|
}
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
|
|
//
|
|
// some versions of the product ID have hyphens in the registry, some do not
|
|
//
|
|
if (wcslen(szPid20) >= 8) {
|
|
if (wcschr(szPid20, '-')) {
|
|
wcsncpy(Pid20Site, szPid20 + 6, 3);
|
|
} else {
|
|
wcsncpy(Pid20Site, szPid20 + 5, 3);
|
|
}
|
|
}
|
|
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Current site code: %S\n", Pid20Site ));
|
|
|
|
if (wcscmp(Pid20Site, OEM_INSTALL_RPC)== 0) {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
|
|
|
|
} else if (wcscmp(Pid20Site, SELECT_INSTALL_RPC)== 0) {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
|
|
} else if (wcscmp(Pid20Site, MSDN_INSTALL_RPC)== 0) {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
|
|
|
|
} else if ((wcsncmp(szPid20, EVAL_MPC, 5) == 0) || (wcsncmp(szPid20, DOTNET_EVAL_MPC, 5) == 0)) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
|
|
|
|
} else if ((wcsncmp(szPid20, SRV_NFR_MPC, 5) == 0) ||
|
|
(wcsncmp(szPid20, ASRV_NFR_MPC, 5) == 0) ||
|
|
(wcsncmp(szPid20, NT4SRV_NFR_MPC, 5) == 0)) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
|
|
|
|
} else {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
|
|
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
pSpDetermineCurrentInstallation(
|
|
IN PDISK_REGION OsPartRegion,
|
|
IN PWSTR SystemRoot,
|
|
OUT PCOMPLIANCE_DATA pcd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines the sku you have currently have installed
|
|
|
|
Arguments:
|
|
|
|
OsPartRegion - what region we're interested in looking at
|
|
SystemRoot - systemroot we want to look at
|
|
pcd - pointer to COMPLIANCE_DATA structure that gets filled in with info about the
|
|
installation the first params point to
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG MajorVersion, MinorVersion,
|
|
BuildNumber, ProductSuiteMask, ServicePack;
|
|
NT_PRODUCT_TYPE ProductType;
|
|
UPG_PROGRESS_TYPE UpgradeProgressValue;
|
|
PWSTR UniqueIdFromReg = NULL, Pid = NULL;
|
|
NTSTATUS NtStatus;
|
|
ULONG i,tmp;
|
|
BOOLEAN bIsEvalVariation = FALSE;
|
|
DWORD *pInstallSuite = 0;
|
|
DWORD *pInstallType = 0;
|
|
|
|
|
|
DWORD SuiteArray[] = { SUITE_VALUES };
|
|
|
|
#define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
|
|
|
|
assert( pcd != NULL ) ;
|
|
|
|
RtlZeroMemory(pcd,sizeof(COMPLIANCE_DATA));
|
|
|
|
NtStatus = SpDetermineProduct(OsPartRegion,
|
|
SystemRoot,
|
|
&ProductType,
|
|
&MajorVersion,
|
|
&MinorVersion,
|
|
&BuildNumber,
|
|
&ProductSuiteMask,
|
|
&UpgradeProgressValue,
|
|
&UniqueIdFromReg,
|
|
&Pid,
|
|
&bIsEvalVariation,
|
|
NULL,
|
|
&ServicePack);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: pSpIsCompliant couldn't SpDetermineProduct(), ec = %x\n", NtStatus ));
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
//
|
|
// Note that we don't handle the case of upgrading from win9x here
|
|
// this is because the compliance check for win9x is *always* completed in
|
|
// winnt32; you can't upgrade to NT from win9x without running winnt32.
|
|
//
|
|
pcd->InstallType = AdvancedServer ? COMPLIANCE_INSTALLTYPE_NTS : COMPLIANCE_INSTALLTYPE_NTW;
|
|
*/
|
|
|
|
switch (ProductType) {
|
|
case NtProductWinNt:
|
|
pcd->InstallType = COMPLIANCE_INSTALLTYPE_NTW;
|
|
break;
|
|
|
|
case NtProductLanManNt:
|
|
case NtProductServer:
|
|
pcd->InstallType = COMPLIANCE_INSTALLTYPE_NTS;
|
|
break;
|
|
|
|
default:
|
|
// by default assume the installation type to be
|
|
// NT workstation
|
|
pcd->InstallType = COMPLIANCE_INSTALLTYPE_NTW;
|
|
break;
|
|
}
|
|
|
|
pSpGetCurrentInstallVariation(Pid, &pcd->InstallVariation);
|
|
|
|
//
|
|
// if we defaulted in previous call and installation has time bomb
|
|
// then assume the var is of type EVAL
|
|
//
|
|
if ((pcd->InstallVariation == COMPLIANCE_INSTALLVAR_CDRETAIL) && bIsEvalVariation)
|
|
pcd->InstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
|
|
|
|
pcd->RequiresValidation = StepUpMode ? TRUE : FALSE;
|
|
pcd->MinimumVersion = MajorVersion * 100 + MinorVersion*10;
|
|
pcd->InstallServicePack = ServicePack;
|
|
pcd->BuildNumberNt = BuildNumber;
|
|
pcd->BuildNumberWin9x = 0;
|
|
|
|
for (i = 0,tmp=ProductSuiteMask; i<SuiteArrayCount;i++) {
|
|
if (tmp&1) {
|
|
pcd->InstallSuite |= SuiteArray[i];
|
|
}
|
|
tmp = tmp >> 1;
|
|
}
|
|
|
|
pInstallSuite = &(pcd->InstallSuite);
|
|
pInstallType = &(pcd->InstallType);
|
|
|
|
//
|
|
// from the install suite find the correct type of install
|
|
// type for the server (i.e. NTS, NTSE, NTSDTC or NTSTSE)
|
|
//
|
|
if (*pInstallSuite == COMPLIANCE_INSTALLSUITE_UNKNOWN)
|
|
*pInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
|
|
else {
|
|
if (*pInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
|
|
if ((BuildNumber <= 1381) &&
|
|
*pInstallSuite == COMPLIANCE_INSTALLSUITE_HYDRA) {
|
|
*pInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
|
|
} else {
|
|
if (*pInstallSuite & COMPLIANCE_INSTALLSUITE_DTC) {
|
|
*pInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
|
|
} else {
|
|
if (*pInstallSuite & COMPLIANCE_INSTALLSUITE_ENT) {
|
|
if( *pInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE) {
|
|
*pInstallType = COMPLIANCE_INSTALLTYPE_NTSPOW;
|
|
} else {
|
|
*pInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
|
|
}
|
|
} else {
|
|
if (*pInstallSuite & COMPLIANCE_INSTALLSUITE_SBSR) {
|
|
*pInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// since there is no data center EVAL type if we detect its eval
|
|
// because of time bomb set, we assume it to be CD-Retail.
|
|
//
|
|
if((pcd->InstallVariation == COMPLIANCE_INSTALLVAR_EVAL) &&
|
|
(*pInstallType == COMPLIANCE_INSTALLTYPE_NTSDTC)) {
|
|
pcd->InstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
|
|
}
|
|
|
|
//
|
|
// Free up the allocated memory
|
|
//
|
|
if (UniqueIdFromReg)
|
|
SpMemFree(UniqueIdFromReg);
|
|
|
|
if (Pid)
|
|
SpMemFree(Pid);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
pSpIsCompliant(
|
|
IN DWORD SourceVersion,
|
|
IN DWORD SourceBuildNum,
|
|
IN PDISK_REGION OsPartRegion,
|
|
IN PWSTR SystemRoot,
|
|
OUT PBOOLEAN UpgradeOnlyCompliant
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the current specified installation is compliant for the
|
|
source we want to install
|
|
|
|
Arguments:
|
|
|
|
InfPath - inf file path containing [Version] section with DriverVer data
|
|
OsPartRegion - points to target
|
|
SystemRoot - points to target
|
|
UpgradeOnlyCompliant - set to TRUE if we can only allow upgrades from the source SKU
|
|
|
|
Return Value:
|
|
|
|
TRUE if the current target is compliant for the source.
|
|
|
|
--*/
|
|
{
|
|
ULONG MajorVersion, MinorVersion, BuildNumber, ProductSuiteMask;
|
|
NT_PRODUCT_TYPE ProductType;
|
|
UPG_PROGRESS_TYPE UpgradeProgressValue;
|
|
PWSTR UniqueIdFromReg, Pid;
|
|
NTSTATUS NtStatus;
|
|
BOOLEAN Rslt;
|
|
BOOL UpgOnly = FALSE;
|
|
COMPLIANCE_DATA TargetData;
|
|
DWORD SourceData,SourceSkuVariation;
|
|
UINT dontcare;
|
|
BOOL dontcare2;
|
|
|
|
assert(UpgradeOnlyCompliant != NULL);
|
|
|
|
if ((SourceData = DetermineSourceProduct(&SourceSkuVariation,NULL))== COMPLIANCE_SKU_NONE) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "setup: Couldnt' determine source SKU\n" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!pSpDetermineCurrentInstallation( OsPartRegion, SystemRoot, &TargetData)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "setup: pSpDetermineCurrentInstallation failed\n" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
UpgOnly = TargetData.RequiresValidation;
|
|
|
|
Rslt = CheckCompliance(SourceData, SourceSkuVariation, SourceVersion,
|
|
SourceBuildNum, &TargetData,&dontcare,&dontcare2);
|
|
|
|
*UpgradeOnlyCompliant = (UpgOnly != 0);
|
|
|
|
return(Rslt);
|
|
}
|
|
|
|
#define NibbleToChar(x) (N2C[x])
|
|
#define CharToNibble(x) ((x)>='0'&&(x)<='9' ? (x)-'0' : ((10+(x)-'A')&0x000f))
|
|
char N2C[] = {
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
|
};
|
|
|
|
|
|
BOOLEAN
|
|
MyTranslatePrivateProfileStruct(
|
|
PSTR InputString,
|
|
LPVOID lpStruct,
|
|
UINT uSizeStruct
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
translates a string from an encoded checksummed version into the real structure.
|
|
stolen from GetPrivateProfileStructA
|
|
|
|
Arguments:
|
|
|
|
InputString - pointer to input string to convert
|
|
lpStruct - point to structure that receives the converted data
|
|
uSizeStruct - size of the input structure
|
|
|
|
Return Value:
|
|
|
|
TRUE if it succeeds in translating into the specified structure, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
CHAR szBuf[256] = {0};
|
|
PSTR lpBuf, lpBufTemp, lpFreeBuffer;
|
|
UINT nLen,tmp;
|
|
BYTE checksum;
|
|
BOOLEAN Result;
|
|
|
|
lpFreeBuffer = NULL;
|
|
lpBuf = (PSTR)szBuf;
|
|
|
|
Result = FALSE;
|
|
|
|
nLen = strlen( InputString );
|
|
RtlCopyMemory( lpBuf, InputString, nLen );
|
|
|
|
if (nLen == uSizeStruct*2+2) {
|
|
/* Room for the one byte check sum */
|
|
uSizeStruct+=1;
|
|
checksum = 0;
|
|
for (lpBufTemp=lpBuf; uSizeStruct!=0; --uSizeStruct) {
|
|
BYTE bStruct;
|
|
BYTE cTemp;
|
|
|
|
cTemp = *lpBufTemp++;
|
|
bStruct = (BYTE)CharToNibble(cTemp);
|
|
cTemp = *lpBufTemp++;
|
|
bStruct = (BYTE)((bStruct<<4) | CharToNibble(cTemp));
|
|
|
|
if (uSizeStruct == 1) {
|
|
if (checksum == bStruct) {
|
|
Result = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
checksum += bStruct;
|
|
*((LPBYTE)lpStruct)++ = bStruct;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpGetStepUpMode(
|
|
PWSTR PidExtraData,
|
|
BOOLEAN *StepUpMode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the specified source is in Step Up Mode or
|
|
if it's a full retail install.
|
|
|
|
Arguments:
|
|
|
|
PidExtraData - checksummed encoded data read out of setupp.ini
|
|
StepUpMode - set to TRUE if we're in stepup mode. value is undefined if
|
|
we fail to translate the input data.
|
|
|
|
This routine assumes that the data passed in is a string set by the "pidinit"
|
|
program. It decodes this data and makes sure the checksum is correct.
|
|
It then checks the CRC value tacked onto the string to determine if the
|
|
data has been tampered with.
|
|
If both of these checks pass, then it looks at the actual data.
|
|
The actual check is this: If the 3rd and 5th bytes are modulo 2 (when
|
|
subtracted from the base value 'a'), then we're in stepup mode. Otherwise
|
|
we're in full retail mode.
|
|
|
|
Note that the intent of this algorithm isn't to provide alot of security
|
|
(it will be trivial to copy the desired setupp.ini over the current one),
|
|
it's main intent is to discourage people from tampering with these values
|
|
in the same manner that data is set in the default hives to discourage
|
|
tampering.
|
|
|
|
Return Value:
|
|
|
|
TRUE if we're able to determine the stepupmode. FALSE if the input data is bogus.
|
|
|
|
--*/
|
|
{
|
|
CHAR Buffer[64] = {0};
|
|
CHAR StepUpArray[14];
|
|
ULONG Needed;
|
|
BOOL Mode;
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlUnicodeToOemN(Buffer,
|
|
sizeof(Buffer),
|
|
&Needed,
|
|
PidExtraData,
|
|
wcslen(PidExtraData)*sizeof(WCHAR)
|
|
);
|
|
|
|
if (! NT_SUCCESS(NtStatus)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: SpGetStepUpMode couldn't RtlUnicodeToOemN failed, ec = %x\n", NtStatus ));
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
if (!MyTranslatePrivateProfileStruct(Buffer,StepUpArray,sizeof(StepUpArray))) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: SpGetStepUpMode couldn't MyTranslatePrivateProfileStruct\n" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!IsValidStepUpMode( StepUpArray , &Mode )) {
|
|
return(FALSE);
|
|
}
|
|
|
|
*StepUpMode = Mode ? TRUE : FALSE;
|
|
return(TRUE);
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// User mode only functions
|
|
//
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
BOOL
|
|
GetCdSourceInstallType(
|
|
LPDWORD SourceInstallType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines what version of NT you are installing, NTW or NTS. It does this by looking in
|
|
dosnet.inf
|
|
|
|
Arguments:
|
|
|
|
SourceInstallType -- receives a COMPLIANCE_INSTALLTYPE flag indicating what type you are installing
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
TCHAR FileName[MAX_PATH];
|
|
TCHAR Buffer[10];
|
|
TCHAR ptr[1] = {0};
|
|
LPTSTR p = &ptr[1];
|
|
|
|
wsprintf( FileName, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
|
|
|
|
GetPrivateProfileString(TEXT("Miscellaneous"), TEXT("ProductType"), TEXT("0"),
|
|
Buffer, sizeof(Buffer)/sizeof(TCHAR), FileName);
|
|
|
|
switch (_tcstoul(Buffer, &p, 10) ) {
|
|
case 0:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTW;
|
|
break;
|
|
case 1:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTS;
|
|
break;
|
|
case 2:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
|
|
break;
|
|
case 3:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
|
|
break;
|
|
case 4:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTWP;
|
|
break;
|
|
case 5:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSB;
|
|
break;
|
|
case 6:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
|
|
break;
|
|
default:
|
|
*SourceInstallType = COMPLIANCE_INSTALLTYPE_NTW;
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
GetStepUpMode(
|
|
BOOL *StepUpMode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the specified source is in Step Up Mode or
|
|
if it's a full retail install.
|
|
|
|
Arguments:
|
|
|
|
StepUpMode - set to TRUE if we're in stepup mode. value is undefined if
|
|
we fail to translate the input data.
|
|
|
|
This routine assumes that the data passed in is a string set by the "pidinit"
|
|
program. It decodes this data and makes sure the checksum is correct.
|
|
It then checks the CRC value tacked onto the string to determine if the
|
|
data has been tampered with.
|
|
If both of these checks pass, then it looks at the actual data.
|
|
The actual check is this: If the 3rd and 5th bytes are modulo 2 (when
|
|
subtracted from the base value 'a'), then we're in stepup mode. Otherwise
|
|
we're in full retail mode.
|
|
|
|
Note that the intent of this algorithm isn't to provide alot of security
|
|
(it will be trivial to copy the desired setupp.ini over the current one),
|
|
it's main intent is to discourage people from tampering with these values
|
|
in the same manner that data is set in the default hives to discourage
|
|
tampering.
|
|
|
|
Return Value:
|
|
|
|
TRUE if we're able to determine the stepupmode. FALSE if the input data is bogus.
|
|
|
|
--*/
|
|
{
|
|
|
|
char FileName[MAX_PATH];
|
|
char data[14];
|
|
TCHAR ptr[1] = {0};
|
|
LPTSTR p = &ptr[1];
|
|
|
|
#ifdef UNICODE
|
|
char SourcePath[MAX_PATH];
|
|
BOOL changed = FALSE;
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
NativeSourcePaths[0],
|
|
MAX_PATH,
|
|
SourcePath,
|
|
sizeof(SourcePath),
|
|
"?",
|
|
&changed);
|
|
|
|
sprintf( FileName, "%s\\setupp.ini", SourcePath);
|
|
#else
|
|
sprintf( FileName, "%s\\setupp.ini", NativeSourcePaths[0]);
|
|
#endif
|
|
|
|
GetPrivateProfileStructA("Pid",
|
|
"ExtraData",
|
|
data,
|
|
sizeof(data),
|
|
FileName);
|
|
|
|
|
|
|
|
if (!IsValidStepUpMode(data,StepUpMode)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
GetSuiteInfoFromDosnet(
|
|
OUT LPDWORD Suite
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines what suite you are installing
|
|
It does this by looking at dosnet.inf
|
|
|
|
Arguments:
|
|
|
|
Suite -- receives a COMPLIANCE_INSTALLSUITE flag
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
TCHAR FileName[MAX_PATH];
|
|
TCHAR Buffer[10];
|
|
TCHAR ptr[1] = {0};
|
|
LPTSTR p = &ptr[1];
|
|
|
|
*Suite = COMPLIANCE_INSTALLSUITE_ANY;
|
|
|
|
wsprintf( FileName, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
|
|
|
|
GetPrivateProfileString(TEXT("Miscellaneous"), TEXT("ProductType"), TEXT("0"),
|
|
Buffer, sizeof(Buffer)/sizeof(TCHAR), FileName);
|
|
|
|
switch (_tcstoul(Buffer, &p, 10) ) {
|
|
case 0:
|
|
case 1:
|
|
*Suite = COMPLIANCE_INSTALLSUITE_NONE;
|
|
break;
|
|
case 2:
|
|
*Suite = COMPLIANCE_INSTALLSUITE_ENT;
|
|
break;
|
|
case 3:
|
|
*Suite = COMPLIANCE_INSTALLSUITE_DTC;
|
|
break;
|
|
case 4:
|
|
*Suite = COMPLIANCE_INSTALLSUITE_PER;
|
|
break;
|
|
case 5:
|
|
*Suite = COMPLIANCE_INSTALLSUITE_BLADE;
|
|
break;
|
|
case 6:
|
|
*Suite = COMPLIANCE_INSTALLSUITE_SBS;
|
|
break;
|
|
default:
|
|
;
|
|
#ifdef DBG
|
|
OutputDebugString( TEXT("Invalid ProductType!\n"));
|
|
#endif
|
|
return(FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetSourceInstallVariation(
|
|
LPDWORD SourceInstallVariation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines what variation of NT you are installing, SELECT,OEM,retail...
|
|
|
|
Arguments:
|
|
|
|
SourceInstallVariation -- receives a COMPLIANCE_INSTALLVAR flag indicating what var
|
|
type you are installing
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
|
|
{
|
|
GetSourceInstallType(SourceInstallVariation);
|
|
|
|
|
|
/*
|
|
switch(SourceInstallType) {
|
|
case SelectInstall:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
break;
|
|
|
|
case OEMInstall:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
|
|
break;
|
|
|
|
case RetailInstall:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
|
|
break;
|
|
|
|
case MSDNInstall:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
|
|
break;
|
|
|
|
case EvalInstall:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
|
|
break;
|
|
|
|
case NFRInstall:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
|
|
break;
|
|
|
|
default:
|
|
*SourceInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
break;
|
|
}
|
|
*/
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetSourceComplianceData(
|
|
OUT PCOMPLIANCE_DATA pcd,
|
|
IN PCOMPLIANCE_DATA Target
|
|
)
|
|
{
|
|
#ifdef USE_HIVE
|
|
TCHAR HiveLocation[MAX_PATH];
|
|
TCHAR HiveTarget[MAX_PATH];
|
|
TCHAR HivePath[MAX_PATH];
|
|
TCHAR HiveName[MAX_PATH] = TEXT("xSETREG");
|
|
TCHAR lpszSetupReg[MAX_PATH] = TEXT("xSETREG\\ControlSet001\\Services\\setupdd");
|
|
TCHAR TargetPath[MAX_PATH];
|
|
|
|
LONG rslt;
|
|
HKEY hKey;
|
|
DWORD Type;
|
|
DWORD Buffer[4];
|
|
DWORD BufferSize = sizeof(Buffer);
|
|
DWORD tmp,i;
|
|
#endif
|
|
|
|
BOOL RetVal = FALSE;
|
|
|
|
#ifdef DBG
|
|
TCHAR Dbg[1000];
|
|
#endif
|
|
|
|
#ifdef USE_HIVE
|
|
DWORD SuiteArray[] = { SUITE_VALUES };
|
|
|
|
#define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
|
|
#endif
|
|
|
|
ZeroMemory( pcd, sizeof(COMPLIANCE_DATA) );
|
|
|
|
if (!GetCdSourceInstallType(&pcd->InstallType)) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Couldn't getcdsourceinstalltype\n"));
|
|
#endif
|
|
goto e0;
|
|
}
|
|
|
|
|
|
if (!GetSourceInstallVariation(&pcd->InstallVariation)) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Couldn't getsourceinstallvariation\n"));
|
|
#endif
|
|
goto e0;
|
|
}
|
|
|
|
if (!GetStepUpMode(&pcd->RequiresValidation)) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Couldn't getstepupmode\n"));
|
|
#endif
|
|
goto e0;
|
|
}
|
|
|
|
RetVal = GetSuiteInfoFromDosnet( &pcd->InstallSuite ) ;
|
|
goto e0;
|
|
|
|
#ifdef USE_HIVE
|
|
//
|
|
// now we need to determine if we are installing enterprise or datacenter
|
|
// To do this, we try to load the registry hive, but this won't work on
|
|
// win9x or nt 3.51. So we use dosnet.inf to get the information we need
|
|
// in those cases.
|
|
//
|
|
if ( (Target->InstallType &
|
|
(COMPLIANCE_INSTALLTYPE_WIN31 | COMPLIANCE_INSTALLTYPE_WIN9X)) ||
|
|
(Target->BuildNumberNt < 1381) ) {
|
|
RetVal = GetSuiteInfoFromDosnet( &pcd->InstallSuite ) ;
|
|
goto e0;
|
|
}
|
|
|
|
|
|
//
|
|
// copy the hive locally since you can only have one open on a hive at a time
|
|
//
|
|
wsprintf( HiveLocation, TEXT("%s\\setupreg.hiv"), NativeSourcePaths[0]);
|
|
GetTempPath(MAX_PATH,TargetPath);
|
|
GetTempFileName(TargetPath,TEXT("set"),0,HiveTarget);
|
|
|
|
CopyFile(HiveLocation,HiveTarget,FALSE);
|
|
SetFileAttributes(HiveTarget,FILE_ATTRIBUTE_NORMAL);
|
|
|
|
#ifdef DBG
|
|
OutputDebugString(HiveLocation);
|
|
OutputDebugString(TEXT("\n"));
|
|
OutputDebugString(HiveTarget);
|
|
#endif
|
|
|
|
//
|
|
// try to unload this first in case we faulted or something and the key is still loaded
|
|
//
|
|
RegUnLoadKey( HKEY_LOCAL_MACHINE, HiveName );
|
|
|
|
//
|
|
// need SE_RESTORE_NAME priviledge to call this API!
|
|
//
|
|
rslt = RegLoadKey( HKEY_LOCAL_MACHINE, HiveName, HiveTarget );
|
|
if (rslt != ERROR_SUCCESS) {
|
|
#ifdef DBG
|
|
wsprintf( Dbg, TEXT("Couldn't RegLoadKey, ec = %d\n"), rslt );
|
|
OutputDebugString(Dbg);
|
|
#endif
|
|
//assert(FALSE);
|
|
goto e1;
|
|
}
|
|
|
|
rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszSetupReg,&hKey);
|
|
if (rslt != ERROR_SUCCESS) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Couldn't RegOpenKey\n"));
|
|
#endif
|
|
//assert(FALSE);
|
|
goto e2;
|
|
}
|
|
|
|
rslt = RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
|
|
if (rslt != ERROR_SUCCESS || Type != REG_BINARY) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Couldn't RegQueryValueEx\n"));
|
|
#endif
|
|
//assert(FALSE);
|
|
goto e3;
|
|
}
|
|
|
|
for (i = 0,tmp=Buffer[3]; i<SuiteArrayCount;i++) {
|
|
if (tmp & 1) {
|
|
pcd->InstallSuite |= SuiteArray[i];
|
|
}
|
|
tmp = tmp >> 1;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e3:
|
|
RegCloseKey( hKey );
|
|
e2:
|
|
RegUnLoadKey( HKEY_LOCAL_MACHINE, HiveName );
|
|
|
|
e1:
|
|
if (GetFileAttributes(HiveTarget) != 0xFFFFFFFF) {
|
|
SetFileAttributes(HiveTarget,FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile(HiveTarget);
|
|
}
|
|
#endif // USE_HIVE
|
|
e0:
|
|
|
|
return(RetVal);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetCurrentNtVersion(
|
|
LPDWORD CurrentInstallType,
|
|
LPDWORD CurrentInstallSuite
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines what type of NT you currently have installed, NTW or NTS,
|
|
as well as what product suite you have installed.
|
|
|
|
It looks in the registry for this data.
|
|
|
|
Arguments:
|
|
|
|
CurrentInstallType - receives a COMPLIANCE_INSTALLTYPE_* flag
|
|
CurrentInstallSuite - receives a COMPLIANCE_INSTALLSUITE_* flag
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
{
|
|
LPCTSTR lpszProductKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions");
|
|
LPCTSTR lpszProductType = TEXT("ProductType");
|
|
LPCTSTR lpszProductSuite = TEXT("ProductSuite");
|
|
LPCTSTR lpszProductSuites[] = { TEXT("Small Business"),
|
|
TEXT("Enterprise"),
|
|
TEXT("BackOffice"),
|
|
TEXT("CommunicationServer"),
|
|
TEXT("Terminal Server"),
|
|
TEXT("Small Business(Restricted)"),
|
|
TEXT("EmbeddedNT"),
|
|
TEXT("DataCenter"),
|
|
TEXT("Personal"),
|
|
TEXT("Blade")
|
|
};
|
|
|
|
LPCTSTR lpszProductPowered = TEXT("Server Appliance");
|
|
|
|
DWORD ProductSuites[] = { SUITE_VALUES };
|
|
|
|
#define CountProductSuites sizeof(ProductSuites)/sizeof(DWORD)
|
|
|
|
LPCTSTR lpszProductTypeNTW = TEXT("WinNT");
|
|
|
|
LPCTSTR lpszCitrixKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Citrix");
|
|
LPCTSTR lpszOemKey = TEXT("OemId");
|
|
LPCTSTR lpszProductVersion = TEXT("ProductVersion");
|
|
|
|
HKEY hKey;
|
|
long rslt;
|
|
DWORD Type;
|
|
LPTSTR p;
|
|
TCHAR Buffer[MAX_PATH];
|
|
DWORD BufferSize = sizeof(Buffer);
|
|
DWORD i;
|
|
BOOL retval = FALSE;
|
|
|
|
|
|
//
|
|
// default to NTW
|
|
//
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTW;
|
|
*CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
|
|
|
|
rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszProductKey,&hKey);
|
|
if (rslt != NO_ERROR) {
|
|
return(FALSE);
|
|
}
|
|
|
|
rslt = RegQueryValueEx(hKey, lpszProductType, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
|
|
if (rslt != NO_ERROR || Type != REG_SZ) {
|
|
goto exit;
|
|
}
|
|
|
|
if (lstrcmpi(Buffer,lpszProductTypeNTW) != 0) {
|
|
//
|
|
// we have some version of NTS
|
|
//
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTS;
|
|
}
|
|
|
|
retval = TRUE;
|
|
|
|
BufferSize = sizeof(Buffer);
|
|
ZeroMemory(Buffer,sizeof(Buffer));
|
|
rslt = RegQueryValueEx(hKey, lpszProductSuite, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
|
|
if (rslt != NO_ERROR || Type != REG_MULTI_SZ) {
|
|
//
|
|
// might not be there for NT 3.51, just succeed if it's not there
|
|
// Also, won't be there for Professional - aka WKS
|
|
//
|
|
goto exit;
|
|
}
|
|
|
|
p = &Buffer[0];
|
|
while (p && *p) {
|
|
for (i = 0; i < CountProductSuites; i++) {
|
|
if (lstrcmp(p, lpszProductSuites[i]) == 0) {
|
|
*CurrentInstallSuite |= ProductSuites[i];
|
|
}
|
|
// W2k powered windows uses the same bit as blade.
|
|
else if( lstrcmp(p, lpszProductPowered) == 0) {
|
|
*CurrentInstallSuite |= COMPLIANCE_INSTALLSUITE_BLADE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// point to the next product suite
|
|
//
|
|
p += lstrlen(p) + 1;
|
|
}
|
|
|
|
retval = TRUE;
|
|
|
|
if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_DTC)
|
|
&& *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
|
|
}
|
|
|
|
if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ENT)
|
|
&& *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
|
|
}
|
|
|
|
if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE)
|
|
&& *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSB;
|
|
}
|
|
|
|
if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_SBSR)
|
|
&& *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
|
|
}
|
|
|
|
if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_PER)
|
|
&& *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTW) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTWP;
|
|
}
|
|
|
|
// special case for powered windows which has enterprise and blade suite!
|
|
if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE)
|
|
&& (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ENT)
|
|
&& *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTSE) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSPOW;
|
|
}
|
|
|
|
if (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ANY) {
|
|
*CurrentInstallSuite = *CurrentInstallSuite & (~COMPLIANCE_INSTALLSUITE_NONE);
|
|
}
|
|
|
|
|
|
exit:
|
|
RegCloseKey(hKey);
|
|
|
|
//
|
|
// if we haven't found a product suite at this point, look for Citrix WinFrame,
|
|
// which we'll treat as terminal server
|
|
//
|
|
|
|
if (*CurrentInstallSuite == COMPLIANCE_INSTALLSUITE_NONE) {
|
|
|
|
rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszCitrixKey,&hKey);
|
|
if (rslt != NO_ERROR) {
|
|
return(TRUE);
|
|
}
|
|
|
|
BufferSize = sizeof(Buffer);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
lpszOemKey,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE) Buffer,
|
|
&BufferSize);
|
|
if (rslt == NO_ERROR && Type == REG_SZ) {
|
|
if (Buffer[0] != TEXT('\0')) {
|
|
BufferSize = sizeof(Buffer);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
lpszProductVersion,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE) Buffer,
|
|
&BufferSize);
|
|
|
|
if (rslt == NO_ERROR) {
|
|
*CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_HYDRA;
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
BOOL
|
|
GetCurrentInstallVariation(
|
|
OUT LPDWORD CurrentInstallVariation,
|
|
IN DWORD CurrentInstallType,
|
|
IN DWORD CurrentInstallBuildNT,
|
|
IN DWORD InstallVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines what "variation" you have installed (retail,oem, select,etc.)
|
|
|
|
Arguments:
|
|
|
|
CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
|
|
|
|
It looks at the product Id in the registry to determine this, assuming that the
|
|
product ID is a PID2.0 string. To check whether its a EVAL variation or not
|
|
it looks at "PriorityQuantumMatrix" value in registry
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPCTSTR lpszPidKeyWin = TEXT("Software\\Microsoft\\Windows\\CurrentVersion");
|
|
LPCTSTR lpszPidKeyWinNT = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
|
|
LPCTSTR lpszProductId = TEXT("ProductId");
|
|
LPCTSTR szEvalKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Executive");
|
|
LPCTSTR szPQMValue = TEXT("PriorityQuantumMatrix");
|
|
|
|
HKEY hKey = NULL;
|
|
long rslt;
|
|
DWORD Type;
|
|
LPTSTR p;
|
|
TCHAR Buffer[MAX_PATH];
|
|
DWORD BufferSize = sizeof(Buffer);
|
|
DWORD i;
|
|
BOOL bResult = FALSE;
|
|
BOOLEAN bDone = FALSE;
|
|
TCHAR Pid20Site[4];
|
|
TCHAR MPCCode[6] = {-1};
|
|
BYTE abPQM[64] = {-1};
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
|
|
rslt = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
ISNT() ? lpszPidKeyWinNT : lpszPidKeyWin,
|
|
&hKey);
|
|
|
|
if (rslt != NO_ERROR) {
|
|
goto exit;
|
|
}
|
|
|
|
rslt = RegQueryValueEx(hKey, lpszProductId, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
|
|
|
|
if (rslt != NO_ERROR || Type!=REG_SZ || (!IsWinPEMode() && (lstrlen(Buffer) < 20))) {
|
|
//
|
|
// nt 3.51 is pid 1.0 instead of pid 2.0. Just assume it's
|
|
// oem variation for now.
|
|
//
|
|
if (((CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) ||
|
|
(CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTW) ||
|
|
(CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTSTSE)) &&
|
|
(CurrentInstallBuildNT < 1381 )) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
|
|
bResult = TRUE;
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
// get the MPC code from PID
|
|
lstrcpyn(MPCCode, Buffer, 6);
|
|
|
|
//
|
|
// some versions of the product ID have hyphens in the registry, some do not
|
|
//
|
|
if (_tcschr(Buffer, TEXT('-'))) {
|
|
lstrcpyn(Pid20Site,&Buffer[6],4);
|
|
Pid20Site[3] = (TCHAR) NULL;
|
|
} else {
|
|
lstrcpyn(Pid20Site,&Buffer[5],4);
|
|
Pid20Site[3] = (TCHAR) NULL;
|
|
}
|
|
|
|
// OutputDebugString(Pid20Site);
|
|
// OutputDebugString(TEXT("\r\n"));
|
|
// OutputDebugString(MPCCode);
|
|
|
|
|
|
if (lstrcmp(Pid20Site, OEM_INSTALL_RPC)== 0) {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
|
|
|
|
} else if (lstrcmp(Pid20Site, SELECT_INSTALL_RPC)== 0) {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
|
|
|
|
} else if (lstrcmp(Pid20Site, MSDN_INSTALL_RPC)== 0) {
|
|
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
|
|
|
|
} else if ((lstrcmp(MPCCode, EVAL_MPC) == 0) || (lstrcmp(MPCCode, DOTNET_EVAL_MPC) == 0)) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
|
|
|
|
} else if ((lstrcmp(MPCCode, SRV_NFR_MPC) == 0) ||
|
|
(lstrcmp(MPCCode, ASRV_NFR_MPC) == 0) ||
|
|
(lstrcmp(MPCCode, NT4SRV_NFR_MPC) == 0)){
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
|
|
|
|
} else {
|
|
//
|
|
// find out if installation is of type EVAL variation (On NT install only)
|
|
// if timebomb is set we assume its EVAL except for DataCenter because
|
|
// there is no EVAL DataCenter SKU.
|
|
//
|
|
if (ISNT() && (CurrentInstallType != COMPLIANCE_INSTALLTYPE_NTSDTC) && (InstallVersion < 500)) {
|
|
HKEY hEvalKey = NULL;
|
|
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, szEvalKey, &hEvalKey) == ERROR_SUCCESS) {
|
|
DWORD dwSize = sizeof(abPQM);
|
|
|
|
if (RegQueryValueEx(hEvalKey, szPQMValue, NULL, &Type, abPQM, &dwSize)
|
|
== ERROR_SUCCESS) {
|
|
|
|
// any of bytes 4-7 (inclusive)
|
|
if ((Type == REG_BINARY) && (dwSize >= 8) && (*(ULONG *)(abPQM + 4))) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hEvalKey);
|
|
}
|
|
}
|
|
|
|
|
|
// last default assumption (since we could not find var type).
|
|
if (*CurrentInstallVariation == COMPLIANCE_INSTALLVAR_SELECT)
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
|
|
}
|
|
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
//
|
|
// If we couldn't find a PID, just treat the current OS as retail
|
|
//
|
|
if (!bResult) {
|
|
*CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
|
|
bResult = TRUE;
|
|
}
|
|
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DetermineCurrentInstallation(
|
|
LPDWORD CurrentInstallType,
|
|
LPDWORD CurrentInstallVariation,
|
|
LPDWORD CurrentInstallVersion,
|
|
LPDWORD CurrentInstallBuildNT,
|
|
LPDWORD CurrentInstallBuildWin9x,
|
|
LPDWORD CurrentInstallSuite,
|
|
LPDWORD CurrentInstallServicePack
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines the current installation you have installed, including
|
|
a) current install type (NTW,NTS,Win9x
|
|
b) current install variation (oem,select, retail)
|
|
c) current install version (for NT only!)
|
|
d) current install suite (SBS, ENTERPRISE,etc.)
|
|
|
|
Arguments:
|
|
|
|
CurrentInstallType - receives a COMPLIANCE_INSTALLTYPE_* flag
|
|
CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
|
|
CurrentInstallVersion - receives a representation of the build (major.minor * 100), ie., 3.51 == 351
|
|
CurrentInstallBuildNT - build number for an nt install
|
|
CurrentInstallBuildWin9 - build number for a win9x install
|
|
CurrentInstallSuite - receives a COMPLIANCE_INSTALLSUITE_* flag
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure.
|
|
|
|
--*/
|
|
{
|
|
BOOL useExtendedInfo;
|
|
union {
|
|
OSVERSIONINFO Normal;
|
|
OSVERSIONINFOEX Ex;
|
|
} Ovi;
|
|
|
|
|
|
#ifdef DBG
|
|
TCHAR dbg[1000];
|
|
#endif
|
|
|
|
if (!CurrentInstallType || !CurrentInstallVariation || !CurrentInstallVersion || !CurrentInstallSuite) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return(FALSE);
|
|
}
|
|
|
|
useExtendedInfo = TRUE;
|
|
Ovi.Ex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Ex) ) {
|
|
//
|
|
// EX size not available; try the normal one
|
|
//
|
|
|
|
Ovi.Normal.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Normal) ) {
|
|
assert(FALSE);
|
|
return(FALSE);
|
|
}
|
|
|
|
useExtendedInfo = FALSE;
|
|
}
|
|
|
|
switch (Ovi.Normal.dwPlatformId) {
|
|
case VER_PLATFORM_WIN32s:
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Win32s current installation!!!"));
|
|
#endif
|
|
//assert(FALSE);
|
|
return(FALSE);
|
|
break;
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_WIN9X;
|
|
*CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
|
|
*CurrentInstallBuildNT = 0;
|
|
*CurrentInstallBuildWin9x = Ovi.Normal.dwBuildNumber;
|
|
#ifdef DBG
|
|
wsprintf(dbg, TEXT("%d\n"), *CurrentInstallBuildWin9x);
|
|
OutputDebugString(dbg);
|
|
#endif
|
|
//
|
|
// Need to know what version of windows is installed so we can block upgrade
|
|
// from win95.
|
|
//
|
|
*CurrentInstallVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion;
|
|
|
|
if (useExtendedInfo) {
|
|
*CurrentInstallServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor;
|
|
} else {
|
|
*CurrentInstallServicePack = 0;
|
|
}
|
|
break;
|
|
case VER_PLATFORM_WIN32_NT:
|
|
if (!GetCurrentNtVersion(
|
|
CurrentInstallType,
|
|
CurrentInstallSuite)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
*CurrentInstallVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion;
|
|
|
|
if (useExtendedInfo) {
|
|
*CurrentInstallServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor;
|
|
} else {
|
|
*CurrentInstallServicePack = 0;
|
|
}
|
|
|
|
*CurrentInstallBuildWin9x = 0;
|
|
*CurrentInstallBuildNT = Ovi.Normal.dwBuildNumber;
|
|
|
|
if (*CurrentInstallBuildNT <= 1381
|
|
&& *CurrentInstallSuite == COMPLIANCE_INSTALLSUITE_HYDRA) {
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("unknown installation!!!"));
|
|
#endif
|
|
assert(FALSE);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!GetCurrentInstallVariation(CurrentInstallVariation,*CurrentInstallType,*CurrentInstallBuildNT, *CurrentInstallVersion)) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("GetCurrentInstallVariation failed\n"));
|
|
#endif
|
|
//assert(FALSE);
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsCompliant(
|
|
PBOOL UpgradeOnly,
|
|
PBOOL NoUpgradeAllowed,
|
|
PUINT SrcSku,
|
|
PUINT CurrentInstallType,
|
|
PUINT CurrentInstallVersion,
|
|
PUINT Reason
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routines determines if your current installation is compliant (if you are allowed to proceed with your installation).
|
|
|
|
To do this, it retreives your current installation and determines the sku for your source installation.
|
|
|
|
It then compares the target against the source to determine if the source sku allows an upgrade/clean install
|
|
from your target installation.
|
|
|
|
Arguments:
|
|
|
|
UpgradeOnly - This flag gets set to TRUE if the current SKU only allows upgrades. This
|
|
lets winnt32 know that it should not allow a clean install from the current
|
|
media. This get's set correctly regardless of the compliance check passing
|
|
SrcSku - COMPLIANCE_SKU flag indicating source sku (for error msg's)
|
|
Reason - COMPLIANCEERR flag indicating why compliance check failed.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the install is compliant, FALSE if it isn't allowed
|
|
|
|
--*/
|
|
{
|
|
DWORD SourceSku;
|
|
DWORD SourceSkuVariation;
|
|
DWORD SourceVersion;
|
|
DWORD SourceBuildNum;
|
|
TCHAR DosnetPath[MAX_PATH] = {0};
|
|
|
|
COMPLIANCE_DATA TargetData;
|
|
|
|
ZeroMemory(&TargetData, sizeof(TargetData) );
|
|
|
|
*UpgradeOnly = FALSE;
|
|
*NoUpgradeAllowed = TRUE;
|
|
*Reason = COMPLIANCEERR_UNKNOWN;
|
|
*SrcSku = COMPLIANCE_SKU_NONE;
|
|
*CurrentInstallType = COMPLIANCE_INSTALLTYPE_UNKNOWN;
|
|
*CurrentInstallVersion = 0;
|
|
|
|
if (!DetermineCurrentInstallation(&TargetData.InstallType,
|
|
&TargetData.InstallVariation,
|
|
&TargetData.MinimumVersion,
|
|
&TargetData.BuildNumberNt,
|
|
&TargetData.BuildNumberWin9x,
|
|
&TargetData.InstallSuite,
|
|
&TargetData.InstallServicePack)) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("Error determining current installation"));
|
|
#endif
|
|
*Reason = COMPLIANCEERR_UNKNOWNTARGET;
|
|
return(FALSE);
|
|
}
|
|
|
|
*CurrentInstallType = TargetData.InstallType;
|
|
if (TargetData.InstallType & COMPLIANCE_INSTALLTYPE_WIN9X) {
|
|
*CurrentInstallVersion = TargetData.BuildNumberWin9x;
|
|
} else {
|
|
*CurrentInstallVersion = TargetData.BuildNumberNt;
|
|
}
|
|
|
|
if ((SourceSku = DetermineSourceProduct(&SourceSkuVariation,&TargetData)) == COMPLIANCE_SKU_NONE) {
|
|
#ifdef DBG
|
|
OutputDebugString(TEXT("couldn't determine source sku!"));
|
|
#endif
|
|
*Reason = COMPLIANCEERR_UNKNOWNSOURCE;
|
|
return(FALSE);
|
|
}
|
|
|
|
wsprintf(DosnetPath, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
|
|
|
|
if (!DetermineSourceVersionInfo(DosnetPath, &SourceVersion, &SourceBuildNum)) {
|
|
*Reason = COMPLIANCEERR_UNKNOWNSOURCE;
|
|
return(FALSE);
|
|
}
|
|
|
|
switch (SourceSku) {
|
|
case COMPLIANCE_SKU_NTW32U:
|
|
//case COMPLIANCE_SKU_NTWU:
|
|
//case COMPLIANCE_SKU_NTSEU:
|
|
case COMPLIANCE_SKU_NTSU:
|
|
case COMPLIANCE_SKU_NTSEU:
|
|
case COMPLIANCE_SKU_NTWPU:
|
|
case COMPLIANCE_SKU_NTSBU:
|
|
case COMPLIANCE_SKU_NTSBSU:
|
|
*UpgradeOnly = TRUE;
|
|
break;
|
|
default:
|
|
*UpgradeOnly = FALSE;
|
|
}
|
|
|
|
*SrcSku = SourceSku;
|
|
|
|
if( ISNT() && TargetData.MinimumVersion == 400 && TargetData.InstallServicePack < 500) {
|
|
*Reason = COMPLIANCEERR_SERVICEPACK5;
|
|
*NoUpgradeAllowed = TRUE;
|
|
return(FALSE);
|
|
}
|
|
|
|
return CheckCompliance(SourceSku, SourceSkuVariation, SourceVersion,
|
|
SourceBuildNum, &TargetData, Reason, NoUpgradeAllowed);
|
|
}
|
|
|
|
BOOL
|
|
IsWinPEMode(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out if we are running under WinPE environment.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return value:
|
|
|
|
TRUE or FALSE
|
|
|
|
--*/
|
|
{
|
|
static BOOL Initialized = FALSE;
|
|
static BOOL WinPEMode = FALSE;
|
|
|
|
|
|
if (!Initialized) {
|
|
TCHAR *MiniNTKeyName = TEXT("SYSTEM\\CurrentControlSet\\Control\\MiniNT");
|
|
HKEY MiniNTKey = NULL;
|
|
LONG RegResult;
|
|
|
|
|
|
RegResult = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
MiniNTKeyName,
|
|
&MiniNTKey);
|
|
|
|
if (RegResult == ERROR_SUCCESS) {
|
|
WinPEMode = TRUE;
|
|
RegCloseKey(MiniNTKey);
|
|
}
|
|
|
|
Initialized = TRUE;
|
|
}
|
|
|
|
return WinPEMode;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|