Source code of Windows XP (NT5)
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.

2204 lines
58 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. compliance.c
  5. Abstract:
  6. compliance checking routines.
  7. Author:
  8. Andrew Ritz (andrewr) 2-Sept-1998
  9. Revision History:
  10. 2-Sept-1998 (andrewr) - created
  11. Notes:
  12. These routines are for compliance checking:
  13. They check to see if an upgrade is allowed from the specified source to the destination.
  14. Since there are so many SKUs to be supported, it's necessary to have a small framework
  15. in place to handle all of these cases. There are generally three parts to the compliance
  16. check:
  17. 1) retreive source information and determine what SKU you want to install
  18. 2) retrieve target information and determine what you are installing over
  19. 3) do the actual compliance check of the target against the source to determine if upgrades
  20. are allowed, or if any installations are allowed from the target to the source.
  21. These types of checks need to be run in both kernel-mode and user-mode installations, so this
  22. common code library was created. The kernel-mode specific code is in an #ifdef KERNEL_MODE
  23. block, and the usermode-specific code is in the #else branch. Common code is outside of
  24. any #ifdef. This library is only to be run (will only link with) setupdd.sys or winnt32a|u.dll.
  25. So when you change this code, keep in mind that it needs to run in both kernel mode and user mode.
  26. Also note that we have to do a bunch of handwaving since NT supports upgrades from win95. Because of
  27. this, we cannot simply read the setupreg.hiv for some information about the installation. Instead, we
  28. encode some additional information into setupp.ini (which is encoded in such a way as to discourage
  29. tinkering with it, but it by no means secure. It provides about the same level of security (obscurity?!?)
  30. as setupreg.hiv gave us in the past.)
  31. --*/
  32. #ifdef KERNEL_MODE
  33. #include "textmode.h"
  34. #else
  35. #include "winnt32.h"
  36. #include <stdio.h>
  37. #endif
  38. #include "COMPLIANCE.H"
  39. #include "crcmodel.h"
  40. #ifdef KERNEL_MODE
  41. #define assert(x) ASSERT(x);
  42. #else
  43. #if DBG
  44. #define assert(x) if (!(x)) DebugBreak();
  45. #else
  46. #define assert(x)
  47. #endif
  48. #endif
  49. //
  50. // NOTE - this MUST match setup\textmode\kernel\spconfig.c's array of product suites
  51. // NOTE - need to handle terminal server, as well as citrix terminal server on NT3.51
  52. //
  53. #define SUITE_VALUES COMPLIANCE_INSTALLSUITE_SBS, \
  54. COMPLIANCE_INSTALLSUITE_ENT, \
  55. COMPLIANCE_INSTALLSUITE_BACK, \
  56. COMPLIANCE_INSTALLSUITE_COMM, \
  57. COMPLIANCE_INSTALLSUITE_HYDRA, \
  58. COMPLIANCE_INSTALLSUITE_SBSR, \
  59. COMPLIANCE_INSTALLSUITE_EMBED, \
  60. COMPLIANCE_INSTALLSUITE_DTC, \
  61. COMPLIANCE_INSTALLSUITE_PER, \
  62. COMPLIANCE_INSTALLSUITE_BLADE
  63. //
  64. // globals
  65. //
  66. //
  67. // Common functions shared between user-mode and kernel mode
  68. //
  69. DWORD
  70. CRC_32(LPBYTE pb, DWORD cb)
  71. {
  72. // CRC-32 algorithm used in PKZip, AUTODIN II, Ethernet, and FDDI
  73. // but xor out (xorot) has been changed from 0xFFFFFFFF to 0 so
  74. // we can store the CRC at the end of the block and expect 0 to be
  75. // the value of the CRC of the resulting block (including the stored
  76. // CRC).
  77. cm_t cmt = {
  78. 32, // cm_width Parameter: Width in bits [8,32].
  79. 0x04C11DB7, // cm_poly Parameter: The algorithm's polynomial.
  80. 0xFFFFFFFF, // cm_init Parameter: Initial register value.
  81. TRUE, // cm_refin Parameter: Reflect input bytes?
  82. TRUE, // cm_refot Parameter: Reflect output CRC?
  83. 0, // cm_xorot Parameter: XOR this to output CRC.
  84. 0 // cm_reg Context: Context during execution.
  85. };
  86. // Documented test case for CRC-32:
  87. // Checking "123456789" should return 0xCBF43926
  88. cm_ini(&cmt);
  89. cm_blk(&cmt, pb, cb);
  90. return cm_crc(&cmt);
  91. }
  92. #ifdef KERNEL_MODE
  93. BOOLEAN
  94. PsGetVersion(
  95. PULONG MajorVersion OPTIONAL,
  96. PULONG MinorVersion OPTIONAL,
  97. PULONG BuildNumber OPTIONAL,
  98. PUNICODE_STRING CSDVersion OPTIONAL
  99. );
  100. BOOLEAN
  101. DetermineSourceVersionInfo(
  102. OUT PDWORD Version,
  103. OUT PDWORD BuildNumber
  104. )
  105. /*++
  106. Routine Description:
  107. Finds the version and build number from
  108. Arguments:
  109. InfPath - Fully qualified path to a inf file containing
  110. [version] section.
  111. Version - Place holder for version information
  112. BuildNumber - Place holder for build number
  113. Return Value:
  114. Returns TRUE if Version and Build number are successfully extracted, otherwise
  115. returns FALSE
  116. --*/
  117. {
  118. BOOLEAN Result = FALSE;
  119. ULONG Major = 0, Minor = 0, Build = 0;
  120. //
  121. // We use PsGetVersion(...) API exported by the kernel
  122. //
  123. PsGetVersion(&Major, &Minor, &Build, NULL);
  124. if ((Major > 0) || (Minor > 0) || (Build > 0)) {
  125. Result = TRUE;
  126. if (Version)
  127. *Version = Major * 100 + Minor;
  128. if (BuildNumber)
  129. *BuildNumber = Build;
  130. }
  131. return Result;
  132. }
  133. #else
  134. BOOLEAN
  135. pGetVersionFromStr(
  136. TCHAR *VersionStr,
  137. DWORD *Version,
  138. DWORD *BuildNumber
  139. )
  140. /*++
  141. Routine Description:
  142. Parses a string with version information like "5.0.2195.1"
  143. and returns the values.
  144. Arguments:
  145. VersionStr - The version string (most of the time its DriverVer string
  146. from the [Version] section in a inf like dosnet.inf)
  147. Version - The version (i.e. major * 100 + minor)
  148. BuildNumber - The build number like 2195
  149. Return Value:
  150. Returns TRUE if Version and Build number are successfully extracted, otherwise
  151. returns FALSE
  152. --*/
  153. {
  154. BOOLEAN Result = FALSE;
  155. DWORD MajorVer = 0, MinorVer = 0, BuildNum = 0;
  156. TCHAR *EndPtr;
  157. TCHAR *EndChar;
  158. TCHAR TempBuff[64] = {0};
  159. if (VersionStr) {
  160. EndPtr = _tcschr(VersionStr, TEXT('.'));
  161. if (EndPtr) {
  162. _tcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
  163. MajorVer = _tcstol(TempBuff, &EndChar, 10);
  164. VersionStr = EndPtr + 1;
  165. if (VersionStr) {
  166. EndPtr = _tcschr(VersionStr, TEXT('.'));
  167. if (EndPtr) {
  168. memset(TempBuff, 0, sizeof(TempBuff));
  169. _tcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
  170. MinorVer = _tcstol(TempBuff, &EndChar, 10);
  171. VersionStr = EndPtr + 1;
  172. if (VersionStr) {
  173. EndPtr = _tcschr(VersionStr, TEXT('.'));
  174. if (EndPtr) {
  175. memset(TempBuff, 0, sizeof(TempBuff));
  176. _tcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
  177. BuildNum = _tcstol(TempBuff, &EndChar, 10);
  178. }
  179. }
  180. }
  181. }
  182. }
  183. }
  184. if ((MajorVer > 0) || (MinorVer > 0) || (BuildNum > 0))
  185. Result = TRUE;
  186. if (Result) {
  187. if (Version)
  188. *Version = (MajorVer * 100) + MinorVer;
  189. if (BuildNumber)
  190. *BuildNumber = BuildNum;
  191. }
  192. return Result;
  193. }
  194. BOOLEAN
  195. DetermineSourceVersionInfo(
  196. IN TCHAR *InfPath,
  197. OUT PDWORD Version,
  198. OUT PDWORD BuildNumber
  199. )
  200. /*++
  201. Routine Description:
  202. Finds the version and build number from
  203. Arguments:
  204. InfPath - Fully qualified path to inf file containing
  205. [version] section.
  206. Version - Place holder for version information
  207. BuildNumber - Place holder for build number
  208. Return Value:
  209. Returns TRUE if Version and Build number are successfully extracted, otherwise
  210. returns FALSE
  211. --*/
  212. {
  213. BOOLEAN Result = FALSE;
  214. TCHAR FileName[MAX_PATH];
  215. TCHAR Buffer[64] = {0};
  216. DWORD CharCount;
  217. CharCount = GetPrivateProfileString(TEXT("Version"), TEXT("DriverVer"), TEXT("0"),
  218. Buffer, sizeof(Buffer)/sizeof(TCHAR), InfPath);
  219. if (CharCount) {
  220. TCHAR *TempPtr = _tcschr(Buffer, TEXT(','));
  221. if (TempPtr) {
  222. TempPtr++;
  223. Result = pGetVersionFromStr(TempPtr, Version, BuildNumber);
  224. }
  225. }
  226. return Result;
  227. }
  228. #endif
  229. DWORD
  230. DetermineSourceProduct(
  231. OUT DWORD *SourceSkuVariation,
  232. IN PCOMPLIANCE_DATA Target
  233. )
  234. /*++
  235. Routine Description:
  236. This routine determines which sku you are installing.
  237. It does this by looking at
  238. a) the source install type
  239. b) the source install "sku" (stepup or full install)
  240. c) source suite type
  241. Arguments:
  242. None.
  243. Return Value:
  244. a COMPLIANCE_SKU_* flag indicating what sku you are installing, and COMPLIANCE_SKU_NONE for error
  245. --*/
  246. {
  247. COMPLIANCE_DATA cd;
  248. DWORD sku = COMPLIANCE_SKU_NONE;
  249. *SourceSkuVariation = COMPLIANCE_INSTALLVAR_SELECT;
  250. #ifdef KERNEL_MODE
  251. if (!pSpGetCurrentInstallVariation(PidString,SourceSkuVariation)) {
  252. return(COMPLIANCE_SKU_NONE);
  253. }
  254. if (!pSpDetermineSourceProduct(&cd)) {
  255. return(COMPLIANCE_SKU_NONE);
  256. }
  257. #else
  258. if (!GetSourceInstallVariation(SourceSkuVariation)) {
  259. return(COMPLIANCE_SKU_NONE);
  260. }
  261. if (!GetSourceComplianceData(&cd,Target)){
  262. return(COMPLIANCE_SKU_NONE);
  263. }
  264. #endif
  265. switch (cd.InstallType) {
  266. case COMPLIANCE_INSTALLTYPE_NTW:
  267. // suite check is done because kernel mode does not detect personal for the type.
  268. if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_PER) {
  269. if (cd.RequiresValidation) {
  270. sku = COMPLIANCE_SKU_NTWPU;
  271. } else {
  272. sku = COMPLIANCE_SKU_NTWPFULL;
  273. }
  274. } else {
  275. if (cd.RequiresValidation) {
  276. sku = COMPLIANCE_SKU_NTW32U;
  277. } else {
  278. sku = COMPLIANCE_SKU_NTWFULL;
  279. }
  280. }
  281. break;
  282. case COMPLIANCE_INSTALLTYPE_NTWP:
  283. if (cd.RequiresValidation) {
  284. sku = COMPLIANCE_SKU_NTWPU;
  285. } else {
  286. sku = COMPLIANCE_SKU_NTWPFULL;
  287. }
  288. break;
  289. case COMPLIANCE_INSTALLTYPE_NTS:
  290. // suite checks are done because kernel mode does not detect dtc or ent for the type.
  291. if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_DTC) {
  292. sku = COMPLIANCE_SKU_NTSDTC;
  293. } else if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_BLADE) {
  294. if (cd.RequiresValidation) {
  295. sku = COMPLIANCE_SKU_NTSBU;
  296. } else {
  297. sku = COMPLIANCE_SKU_NTSB;
  298. }
  299. } else if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_SBSR) {
  300. if (cd.RequiresValidation) {
  301. sku = COMPLIANCE_SKU_NTSBSU;
  302. } else {
  303. sku = COMPLIANCE_SKU_NTSBS;
  304. }
  305. } else if (cd.InstallSuite & COMPLIANCE_INSTALLSUITE_ENT) {
  306. if (cd.RequiresValidation) {
  307. sku = COMPLIANCE_SKU_NTSEU;
  308. } else {
  309. sku = COMPLIANCE_SKU_NTSEFULL;
  310. }
  311. } else {
  312. if (cd.RequiresValidation) {
  313. sku = COMPLIANCE_SKU_NTSU;
  314. } else {
  315. sku = COMPLIANCE_SKU_NTSFULL;
  316. }
  317. }
  318. break;
  319. case COMPLIANCE_INSTALLTYPE_NTSB:
  320. if (cd.RequiresValidation) {
  321. sku = COMPLIANCE_SKU_NTSBU;
  322. } else {
  323. sku = COMPLIANCE_SKU_NTSB;
  324. }
  325. break;
  326. case COMPLIANCE_INSTALLTYPE_NTSBS:
  327. if (cd.RequiresValidation) {
  328. sku = COMPLIANCE_SKU_NTSBSU;
  329. } else {
  330. sku = COMPLIANCE_SKU_NTSBS;
  331. }
  332. break;
  333. case COMPLIANCE_INSTALLTYPE_NTSE:
  334. if (cd.RequiresValidation) {
  335. sku = COMPLIANCE_SKU_NTSEU;
  336. } else {
  337. sku = COMPLIANCE_SKU_NTSEFULL;
  338. }
  339. break;
  340. case COMPLIANCE_INSTALLTYPE_NTSDTC:
  341. sku = COMPLIANCE_SKU_NTSDTC;
  342. break;
  343. default:
  344. sku = COMPLIANCE_SKU_NONE;
  345. }
  346. return( sku );
  347. }
  348. BOOLEAN
  349. CheckCompliance(
  350. IN DWORD SourceSku,
  351. IN DWORD SourceSkuVariation,
  352. IN DWORD SourceVersion,
  353. IN DWORD SourceBuildNum,
  354. IN PCOMPLIANCE_DATA pcd,
  355. OUT PUINT Reason,
  356. OUT PBOOL NoUpgradeAllowed
  357. )
  358. /*++
  359. Routine Description:
  360. This routines determines if your current installation is compliant (if you are allowed to proceed with your installation).
  361. To do this, it retreives your current installation and determines the sku for your source installation.
  362. It then compares the target against the source to determine if the source sku allows an upgrade/clean install
  363. from your target installation.
  364. Arguments:
  365. SourceSku - a COMPLIANCE_SKU_* flag indicating the source type
  366. SourceSkuVariation - a COMPLIANCE_VARIATION_* flag indicating what variation the source is
  367. pcd - pointer to a COMPLIANCE_DATA structure describing the current source
  368. Reason - COMPLIANCEERR_ flag indicating why compliance check fails
  369. Return Value:
  370. TRUE if the install is compliant, FALSE if it isn't allowed
  371. NOTE : The error value could be set irrespective of return value of TRUE or false. For full media
  372. the return value is always true and only the "NoUpgradeAllowed" variable gets set indicating
  373. whether upgrade is allowed or not.
  374. --*/
  375. {
  376. PCCMEDIA SourceMedia = 0;
  377. BOOL UpgradeAllowed = FALSE;
  378. BOOLEAN Result;
  379. TCHAR DebugStr[1024];
  380. if (pcd) {
  381. SourceMedia = CCMediaCreate(SourceSku, SourceSkuVariation,
  382. SourceVersion, SourceBuildNum);
  383. if (SourceMedia) {
  384. Result = SourceMedia->CheckInstall(SourceMedia, pcd, Reason, &UpgradeAllowed);
  385. *NoUpgradeAllowed = (UpgradeAllowed) ? FALSE : TRUE;
  386. CCMemFree(SourceMedia);
  387. } else {
  388. *Reason = COMPLIANCEERR_UNKNOWNSOURCE;
  389. *NoUpgradeAllowed = TRUE;
  390. Result = FALSE;
  391. }
  392. } else {
  393. *Reason = COMPLIANCEERR_UNKNOWNTARGET;
  394. *NoUpgradeAllowed = TRUE;
  395. Result = FALSE;
  396. }
  397. return Result;
  398. }
  399. BOOL IsValidStepUpMode(
  400. CHAR *StepUpArray,
  401. ULONG *StepUpMode
  402. )
  403. {
  404. DWORD crcvalue,outval;
  405. #define BASE 'a'
  406. crcvalue = CRC_32( (LPBYTE)StepUpArray, 10 );
  407. RtlCopyMemory(&outval,&StepUpArray[10],sizeof(DWORD));
  408. if (crcvalue != outval ) {
  409. #ifdef DBG
  410. #ifdef KERNEL_MODE
  411. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Setup: SpGetStepUpMode CRC didn't match for StepUpArray: %x %x\n", crcvalue, outval ));
  412. #else
  413. OutputDebugString(TEXT("IsValidStepUpMode CRC failed\n"));
  414. #endif
  415. #endif // DBG
  416. return(FALSE);
  417. }
  418. if ((StepUpArray[3]-BASE)%2) {
  419. if ((StepUpArray[5]-BASE)%2) {
  420. #ifdef DBG
  421. #ifdef KERNEL_MODE
  422. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "setup: this is stepup mode\n"));
  423. #else
  424. OutputDebugString(TEXT("this is stepup mode\n"));
  425. #endif
  426. #endif //DBG
  427. *StepUpMode = 1;
  428. return(TRUE);
  429. } else {
  430. #ifdef DBG
  431. #ifdef KERNEL_MODE
  432. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "setup: bad pid signature\n"));
  433. #else
  434. OutputDebugString(TEXT("bad pid signature\n"));
  435. #endif
  436. #endif //DBG
  437. return(FALSE);
  438. }
  439. } else
  440. if ((StepUpArray[5]-BASE)%2) {
  441. #ifdef DBG
  442. #ifdef KERNEL_MODE
  443. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "setup: bad pid signature\n"));
  444. #else
  445. OutputDebugString(TEXT("bad pid signature\n"));
  446. #endif
  447. #endif //DBG
  448. return(FALSE);
  449. } else {
  450. *StepUpMode = 0;
  451. return(TRUE);
  452. }
  453. //
  454. // should never make it here
  455. //
  456. assert(FALSE);
  457. return(TRUE);
  458. }
  459. //
  460. // Kernel mode only functions
  461. //
  462. #ifdef KERNEL_MODE
  463. BOOL
  464. pSpDetermineSourceProduct(
  465. PCOMPLIANCE_DATA pcd
  466. )
  467. {
  468. ULONG i,tmp;
  469. TCHAR Dbg[1000];
  470. DWORD SuiteArray[] = { SUITE_VALUES };
  471. #define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
  472. RtlZeroMemory(pcd,sizeof(COMPLIANCE_DATA));
  473. pcd->InstallType = AdvancedServer ?
  474. COMPLIANCE_INSTALLTYPE_NTS :
  475. COMPLIANCE_INSTALLTYPE_NTW ;
  476. pcd->RequiresValidation = (StepUpMode) ? TRUE : FALSE;
  477. for (i = 0,tmp=SuiteType; i<SuiteArrayCount;i++) {
  478. if (tmp&1) {
  479. pcd->InstallSuite |= SuiteArray[i];
  480. }
  481. tmp = tmp >> 1;
  482. }
  483. if (pcd->InstallSuite == COMPLIANCE_INSTALLSUITE_UNKNOWN) {
  484. pcd->InstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
  485. }
  486. return TRUE;
  487. }
  488. BOOLEAN
  489. pSpGetCurrentInstallVariation(
  490. IN PWSTR szPid20,
  491. OUT LPDWORD CurrentInstallVariation
  492. )
  493. /*++
  494. Routine Description:
  495. This routine determines what "variation" you have installed (retail,oem, select,etc.)
  496. Arguments:
  497. CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
  498. It looks at the product Id in the registry to determine this, assuming that the
  499. product ID is a PID2.0 string.
  500. Return Value:
  501. None.
  502. --*/
  503. {
  504. BOOLEAN retval = FALSE;
  505. WCHAR Pid20Site[4] = {0};
  506. assert(CurrentInstallVariation != NULL);
  507. assert(szPid20 != NULL);
  508. if (!CurrentInstallVariation) {
  509. return(FALSE);
  510. }
  511. if (!szPid20 || (wcslen(szPid20) < 5)) {
  512. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  513. return(TRUE);
  514. }
  515. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  516. //
  517. // some versions of the product ID have hyphens in the registry, some do not
  518. //
  519. if (wcslen(szPid20) >= 8) {
  520. if (wcschr(szPid20, '-')) {
  521. wcsncpy(Pid20Site, szPid20 + 6, 3);
  522. } else {
  523. wcsncpy(Pid20Site, szPid20 + 5, 3);
  524. }
  525. }
  526. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Current site code: %S\n", Pid20Site ));
  527. if (wcscmp(Pid20Site, OEM_INSTALL_RPC)== 0) {
  528. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  529. } else if (wcscmp(Pid20Site, SELECT_INSTALL_RPC)== 0) {
  530. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  531. } else if (wcscmp(Pid20Site, MSDN_INSTALL_RPC)== 0) {
  532. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
  533. } else if (wcsncmp(szPid20, EVAL_MPC, 5) == 0) {
  534. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  535. } else if ((wcsncmp(szPid20, SRV_NFR_MPC, 5) == 0) ||
  536. (wcsncmp(szPid20, ASRV_NFR_MPC, 5) == 0) ||
  537. (wcsncmp(szPid20, NT4SRV_NFR_MPC, 5) == 0)) {
  538. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
  539. } else {
  540. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  541. }
  542. return(TRUE);
  543. }
  544. BOOLEAN
  545. pSpDetermineCurrentInstallation(
  546. IN PDISK_REGION OsPartRegion,
  547. IN PWSTR SystemRoot,
  548. OUT PCOMPLIANCE_DATA pcd
  549. )
  550. /*++
  551. Routine Description:
  552. This routine determines the sku you have currently have installed
  553. Arguments:
  554. OsPartRegion - what region we're interested in looking at
  555. SystemRoot - systemroot we want to look at
  556. pcd - pointer to COMPLIANCE_DATA structure that gets filled in with info about the
  557. installation the first params point to
  558. Return Value:
  559. None.
  560. --*/
  561. {
  562. ULONG MajorVersion, MinorVersion,
  563. BuildNumber, ProductSuiteMask, ServicePack;
  564. NT_PRODUCT_TYPE ProductType;
  565. UPG_PROGRESS_TYPE UpgradeProgressValue;
  566. PWSTR UniqueIdFromReg = NULL, Pid = NULL;
  567. NTSTATUS NtStatus;
  568. ULONG i,tmp;
  569. BOOLEAN bIsEvalVariation = FALSE;
  570. DWORD *pInstallSuite = 0;
  571. DWORD *pInstallType = 0;
  572. DWORD SuiteArray[] = { SUITE_VALUES };
  573. #define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
  574. assert( pcd != NULL ) ;
  575. RtlZeroMemory(pcd,sizeof(COMPLIANCE_DATA));
  576. NtStatus = SpDetermineProduct(OsPartRegion,
  577. SystemRoot,
  578. &ProductType,
  579. &MajorVersion,
  580. &MinorVersion,
  581. &BuildNumber,
  582. &ProductSuiteMask,
  583. &UpgradeProgressValue,
  584. &UniqueIdFromReg,
  585. &Pid,
  586. &bIsEvalVariation,
  587. NULL,
  588. &ServicePack);
  589. if (!NT_SUCCESS(NtStatus)) {
  590. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: pSpIsCompliant couldn't SpDetermineProduct(), ec = %x\n", NtStatus ));
  591. return(FALSE);
  592. }
  593. /*
  594. //
  595. // Note that we don't handle the case of upgrading from win9x here
  596. // this is because the compliance check for win9x is *always* completed in
  597. // winnt32; you can't upgrade to NT from win9x without running winnt32.
  598. //
  599. pcd->InstallType = AdvancedServer ? COMPLIANCE_INSTALLTYPE_NTS : COMPLIANCE_INSTALLTYPE_NTW;
  600. */
  601. switch (ProductType) {
  602. case NtProductWinNt:
  603. pcd->InstallType = COMPLIANCE_INSTALLTYPE_NTW;
  604. break;
  605. case NtProductLanManNt:
  606. case NtProductServer:
  607. pcd->InstallType = COMPLIANCE_INSTALLTYPE_NTS;
  608. break;
  609. default:
  610. // by default assume the installation type to be
  611. // NT workstation
  612. pcd->InstallType = COMPLIANCE_INSTALLTYPE_NTW;
  613. break;
  614. }
  615. pSpGetCurrentInstallVariation(Pid, &pcd->InstallVariation);
  616. //
  617. // if we defaulted in previous call and installation has time bomb
  618. // then assume the var is of type EVAL
  619. //
  620. if ((pcd->InstallVariation == COMPLIANCE_INSTALLVAR_CDRETAIL) && bIsEvalVariation)
  621. pcd->InstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  622. pcd->RequiresValidation = StepUpMode ? TRUE : FALSE;
  623. pcd->MinimumVersion = MajorVersion * 100 + MinorVersion*10;
  624. pcd->InstallServicePack = ServicePack;
  625. pcd->BuildNumberNt = BuildNumber;
  626. pcd->BuildNumberWin9x = 0;
  627. for (i = 0,tmp=ProductSuiteMask; i<SuiteArrayCount;i++) {
  628. if (tmp&1) {
  629. pcd->InstallSuite |= SuiteArray[i];
  630. }
  631. tmp = tmp >> 1;
  632. }
  633. pInstallSuite = &(pcd->InstallSuite);
  634. pInstallType = &(pcd->InstallType);
  635. //
  636. // from the install suite find the correct type of install
  637. // type for the server (i.e. NTS, NTSE, NTSDTC or NTSTSE)
  638. //
  639. if (*pInstallSuite == COMPLIANCE_INSTALLSUITE_UNKNOWN)
  640. *pInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
  641. else {
  642. if (*pInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  643. if ((BuildNumber <= 1381) &&
  644. *pInstallSuite == COMPLIANCE_INSTALLSUITE_HYDRA) {
  645. *pInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
  646. } else {
  647. if (*pInstallSuite & COMPLIANCE_INSTALLSUITE_DTC) {
  648. *pInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
  649. } else {
  650. if (*pInstallSuite & COMPLIANCE_INSTALLSUITE_ENT) {
  651. *pInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
  652. }
  653. }
  654. }
  655. }
  656. }
  657. //
  658. // since there is no data center EVAL type if we detect its eval
  659. // because of time bomb set, we assume it to be CD-Retail.
  660. //
  661. if((pcd->InstallVariation == COMPLIANCE_INSTALLVAR_EVAL) &&
  662. (*pInstallType == COMPLIANCE_INSTALLTYPE_NTSDTC)) {
  663. pcd->InstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  664. }
  665. //
  666. // Free up the allocated memory
  667. //
  668. if (UniqueIdFromReg)
  669. SpMemFree(UniqueIdFromReg);
  670. if (Pid)
  671. SpMemFree(Pid);
  672. return(TRUE);
  673. }
  674. BOOLEAN
  675. pSpIsCompliant(
  676. IN DWORD SourceVersion,
  677. IN DWORD SourceBuildNum,
  678. IN PDISK_REGION OsPartRegion,
  679. IN PWSTR SystemRoot,
  680. OUT PBOOLEAN UpgradeOnlyCompliant
  681. )
  682. /*++
  683. Routine Description:
  684. This routine determines if the current specified installation is compliant for the
  685. source we want to install
  686. Arguments:
  687. InfPath - inf file path containing [Version] section with DriverVer data
  688. OsPartRegion - points to target
  689. SystemRoot - points to target
  690. UpgradeOnlyCompliant - set to TRUE if we can only allow upgrades from the source SKU
  691. Return Value:
  692. TRUE if the current target is compliant for the source.
  693. --*/
  694. {
  695. ULONG MajorVersion, MinorVersion, BuildNumber, ProductSuiteMask;
  696. NT_PRODUCT_TYPE ProductType;
  697. UPG_PROGRESS_TYPE UpgradeProgressValue;
  698. PWSTR UniqueIdFromReg, Pid;
  699. NTSTATUS NtStatus;
  700. BOOLEAN Rslt;
  701. BOOL UpgOnly = FALSE;
  702. COMPLIANCE_DATA TargetData;
  703. DWORD SourceData,SourceSkuVariation;
  704. UINT dontcare;
  705. BOOL dontcare2;
  706. assert(UpgradeOnlyCompliant != NULL);
  707. if ((SourceData = DetermineSourceProduct(&SourceSkuVariation,NULL))== COMPLIANCE_SKU_NONE) {
  708. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "setup: Couldnt' determine source SKU\n" ));
  709. return(FALSE);
  710. }
  711. if (!pSpDetermineCurrentInstallation( OsPartRegion, SystemRoot, &TargetData)) {
  712. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "setup: pSpDetermineCurrentInstallation failed\n" ));
  713. return(FALSE);
  714. }
  715. UpgOnly = TargetData.RequiresValidation;
  716. Rslt = CheckCompliance(SourceData, SourceSkuVariation, SourceVersion,
  717. SourceBuildNum, &TargetData,&dontcare,&dontcare2);
  718. *UpgradeOnlyCompliant = (UpgOnly != 0);
  719. return(Rslt);
  720. }
  721. #define NibbleToChar(x) (N2C[x])
  722. #define CharToNibble(x) ((x)>='0'&&(x)<='9' ? (x)-'0' : ((10+(x)-'A')&0x000f))
  723. char N2C[] = {
  724. '0', '1', '2', '3', '4', '5', '6', '7',
  725. '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  726. };
  727. BOOLEAN
  728. MyTranslatePrivateProfileStruct(
  729. PSTR InputString,
  730. LPVOID lpStruct,
  731. UINT uSizeStruct
  732. )
  733. /*++
  734. Routine Description:
  735. translates a string from an encoded checksummed version into the real structure.
  736. stolen from GetPrivateProfileStructA
  737. Arguments:
  738. InputString - pointer to input string to convert
  739. lpStruct - point to structure that receives the converted data
  740. uSizeStruct - size of the input structure
  741. Return Value:
  742. TRUE if it succeeds in translating into the specified structure, FALSE otherwise.
  743. --*/
  744. {
  745. CHAR szBuf[256] = {0};
  746. PSTR lpBuf, lpBufTemp, lpFreeBuffer;
  747. UINT nLen,tmp;
  748. BYTE checksum;
  749. BOOLEAN Result;
  750. lpFreeBuffer = NULL;
  751. lpBuf = (PSTR)szBuf;
  752. Result = FALSE;
  753. nLen = strlen( InputString );
  754. RtlCopyMemory( lpBuf, InputString, nLen );
  755. if (nLen == uSizeStruct*2+2) {
  756. /* Room for the one byte check sum */
  757. uSizeStruct+=1;
  758. checksum = 0;
  759. for (lpBufTemp=lpBuf; uSizeStruct!=0; --uSizeStruct) {
  760. BYTE bStruct;
  761. BYTE cTemp;
  762. cTemp = *lpBufTemp++;
  763. bStruct = (BYTE)CharToNibble(cTemp);
  764. cTemp = *lpBufTemp++;
  765. bStruct = (BYTE)((bStruct<<4) | CharToNibble(cTemp));
  766. if (uSizeStruct == 1) {
  767. if (checksum == bStruct) {
  768. Result = TRUE;
  769. }
  770. break;
  771. }
  772. checksum += bStruct;
  773. *((LPBYTE)lpStruct)++ = bStruct;
  774. }
  775. }
  776. return Result;
  777. }
  778. BOOLEAN
  779. SpGetStepUpMode(
  780. PWSTR PidExtraData,
  781. BOOLEAN *StepUpMode
  782. )
  783. /*++
  784. Routine Description:
  785. This routine determines if the specified source is in Step Up Mode or
  786. if it's a full retail install.
  787. Arguments:
  788. PidExtraData - checksummed encoded data read out of setupp.ini
  789. StepUpMode - set to TRUE if we're in stepup mode. value is undefined if
  790. we fail to translate the input data.
  791. This routine assumes that the data passed in is a string set by the "pidinit"
  792. program. It decodes this data and makes sure the checksum is correct.
  793. It then checks the CRC value tacked onto the string to determine if the
  794. data has been tampered with.
  795. If both of these checks pass, then it looks at the actual data.
  796. The actual check is this: If the 3rd and 5th bytes are modulo 2 (when
  797. subtracted from the base value 'a'), then we're in stepup mode. Otherwise
  798. we're in full retail mode.
  799. Note that the intent of this algorithm isn't to provide alot of security
  800. (it will be trivial to copy the desired setupp.ini over the current one),
  801. it's main intent is to discourage people from tampering with these values
  802. in the same manner that data is set in the default hives to discourage
  803. tampering.
  804. Return Value:
  805. TRUE if we're able to determine the stepupmode. FALSE if the input data is bogus.
  806. --*/
  807. {
  808. CHAR Buffer[64] = {0};
  809. CHAR StepUpArray[14];
  810. ULONG Needed;
  811. BOOL Mode;
  812. NTSTATUS NtStatus;
  813. NtStatus = RtlUnicodeToOemN(Buffer,
  814. sizeof(Buffer),
  815. &Needed,
  816. PidExtraData,
  817. wcslen(PidExtraData)*sizeof(WCHAR)
  818. );
  819. if (! NT_SUCCESS(NtStatus)) {
  820. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: SpGetStepUpMode couldn't RtlUnicodeToOemN failed, ec = %x\n", NtStatus ));
  821. return(FALSE);
  822. }
  823. if (!MyTranslatePrivateProfileStruct(Buffer,StepUpArray,sizeof(StepUpArray))) {
  824. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: SpGetStepUpMode couldn't MyTranslatePrivateProfileStruct\n" ));
  825. return(FALSE);
  826. }
  827. if (!IsValidStepUpMode( StepUpArray , &Mode )) {
  828. return(FALSE);
  829. }
  830. *StepUpMode = Mode ? TRUE : FALSE;
  831. return(TRUE);
  832. }
  833. #endif
  834. //
  835. // User mode only functions
  836. //
  837. #ifndef KERNEL_MODE
  838. BOOL
  839. GetCdSourceInstallType(
  840. LPDWORD SourceInstallType
  841. )
  842. /*++
  843. Routine Description:
  844. This routine determines what version of NT you are installing, NTW or NTS. It does this by looking in
  845. dosnet.inf
  846. Arguments:
  847. SourceInstallType -- receives a COMPLIANCE_INSTALLTYPE flag indicating what type you are installing
  848. Return Value:
  849. TRUE for success, FALSE for failure
  850. --*/
  851. {
  852. TCHAR FileName[MAX_PATH];
  853. TCHAR Buffer[10];
  854. TCHAR ptr[1] = {0};
  855. LPTSTR p = &ptr[1];
  856. wsprintf( FileName, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
  857. GetPrivateProfileString(TEXT("Miscellaneous"), TEXT("ProductType"), TEXT("0"),
  858. Buffer, sizeof(Buffer)/sizeof(TCHAR), FileName);
  859. switch (_tcstoul(Buffer, &p, 10) ) {
  860. case 0:
  861. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTW;
  862. break;
  863. case 1:
  864. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTS;
  865. break;
  866. case 2:
  867. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
  868. break;
  869. case 3:
  870. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
  871. break;
  872. case 4:
  873. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTWP;
  874. break;
  875. case 5:
  876. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSB;
  877. break;
  878. case 6:
  879. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
  880. break;
  881. default:
  882. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTW;
  883. return(FALSE);
  884. }
  885. return(TRUE);
  886. }
  887. BOOL
  888. GetStepUpMode(
  889. BOOL *StepUpMode
  890. )
  891. /*++
  892. Routine Description:
  893. This routine determines if the specified source is in Step Up Mode or
  894. if it's a full retail install.
  895. Arguments:
  896. StepUpMode - set to TRUE if we're in stepup mode. value is undefined if
  897. we fail to translate the input data.
  898. This routine assumes that the data passed in is a string set by the "pidinit"
  899. program. It decodes this data and makes sure the checksum is correct.
  900. It then checks the CRC value tacked onto the string to determine if the
  901. data has been tampered with.
  902. If both of these checks pass, then it looks at the actual data.
  903. The actual check is this: If the 3rd and 5th bytes are modulo 2 (when
  904. subtracted from the base value 'a'), then we're in stepup mode. Otherwise
  905. we're in full retail mode.
  906. Note that the intent of this algorithm isn't to provide alot of security
  907. (it will be trivial to copy the desired setupp.ini over the current one),
  908. it's main intent is to discourage people from tampering with these values
  909. in the same manner that data is set in the default hives to discourage
  910. tampering.
  911. Return Value:
  912. TRUE if we're able to determine the stepupmode. FALSE if the input data is bogus.
  913. --*/
  914. {
  915. char FileName[MAX_PATH];
  916. char data[14];
  917. TCHAR ptr[1] = {0};
  918. LPTSTR p = &ptr[1];
  919. #ifdef UNICODE
  920. char SourcePath[MAX_PATH];
  921. BOOL changed = FALSE;
  922. WideCharToMultiByte(CP_ACP,
  923. 0,
  924. NativeSourcePaths[0],
  925. MAX_PATH,
  926. SourcePath,
  927. sizeof(SourcePath),
  928. "?",
  929. &changed);
  930. sprintf( FileName, "%s\\setupp.ini", SourcePath);
  931. #else
  932. sprintf( FileName, "%s\\setupp.ini", NativeSourcePaths[0]);
  933. #endif
  934. GetPrivateProfileStructA("Pid",
  935. "ExtraData",
  936. data,
  937. sizeof(data),
  938. FileName);
  939. if (!IsValidStepUpMode(data,StepUpMode)) {
  940. return(FALSE);
  941. }
  942. return(TRUE);
  943. }
  944. BOOL
  945. GetSuiteInfoFromDosnet(
  946. OUT LPDWORD Suite
  947. )
  948. /*++
  949. Routine Description:
  950. This routine determines what suite you are installing
  951. It does this by looking at dosnet.inf
  952. Arguments:
  953. Suite -- receives a COMPLIANCE_INSTALLSUITE flag
  954. Return Value:
  955. TRUE for success, FALSE for failure
  956. --*/
  957. {
  958. TCHAR FileName[MAX_PATH];
  959. TCHAR Buffer[10];
  960. TCHAR ptr[1] = {0};
  961. LPTSTR p = &ptr[1];
  962. *Suite = COMPLIANCE_INSTALLSUITE_ANY;
  963. wsprintf( FileName, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
  964. GetPrivateProfileString(TEXT("Miscellaneous"), TEXT("ProductType"), TEXT("0"),
  965. Buffer, sizeof(Buffer)/sizeof(TCHAR), FileName);
  966. switch (_tcstoul(Buffer, &p, 10) ) {
  967. case 0:
  968. case 1:
  969. *Suite = COMPLIANCE_INSTALLSUITE_NONE;
  970. break;
  971. case 2:
  972. *Suite = COMPLIANCE_INSTALLSUITE_ENT;
  973. break;
  974. case 3:
  975. *Suite = COMPLIANCE_INSTALLSUITE_DTC;
  976. break;
  977. case 4:
  978. *Suite = COMPLIANCE_INSTALLSUITE_PER;
  979. break;
  980. case 5:
  981. *Suite = COMPLIANCE_INSTALLSUITE_BLADE;
  982. break;
  983. default:
  984. ;
  985. #ifdef DBG
  986. OutputDebugString( TEXT("Invalid ProductType!\n"));
  987. #endif
  988. return(FALSE);
  989. }
  990. return (TRUE);
  991. }
  992. BOOL
  993. GetSourceInstallVariation(
  994. LPDWORD SourceInstallVariation
  995. )
  996. /*++
  997. Routine Description:
  998. This routine determines what variation of NT you are installing, SELECT,OEM,retail...
  999. Arguments:
  1000. SourceInstallVariation -- receives a COMPLIANCE_INSTALLVAR flag indicating what var
  1001. type you are installing
  1002. Return Value:
  1003. TRUE for success, FALSE for failure
  1004. --*/
  1005. {
  1006. GetSourceInstallType(SourceInstallVariation);
  1007. /*
  1008. switch(SourceInstallType) {
  1009. case SelectInstall:
  1010. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1011. break;
  1012. case OEMInstall:
  1013. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  1014. break;
  1015. case RetailInstall:
  1016. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  1017. break;
  1018. case MSDNInstall:
  1019. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
  1020. break;
  1021. case EvalInstall:
  1022. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  1023. break;
  1024. case NFRInstall:
  1025. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
  1026. break;
  1027. default:
  1028. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1029. break;
  1030. }
  1031. */
  1032. return(TRUE);
  1033. }
  1034. BOOL
  1035. GetSourceComplianceData(
  1036. OUT PCOMPLIANCE_DATA pcd,
  1037. IN PCOMPLIANCE_DATA Target
  1038. )
  1039. {
  1040. #ifdef USE_HIVE
  1041. TCHAR HiveLocation[MAX_PATH];
  1042. TCHAR HiveTarget[MAX_PATH];
  1043. TCHAR HivePath[MAX_PATH];
  1044. TCHAR HiveName[MAX_PATH] = TEXT("xSETREG");
  1045. TCHAR lpszSetupReg[MAX_PATH] = TEXT("xSETREG\\ControlSet001\\Services\\setupdd");
  1046. TCHAR TargetPath[MAX_PATH];
  1047. LONG rslt;
  1048. HKEY hKey;
  1049. DWORD Type;
  1050. DWORD Buffer[4];
  1051. DWORD BufferSize = sizeof(Buffer);
  1052. DWORD tmp,i;
  1053. #endif
  1054. BOOL RetVal = FALSE;
  1055. #ifdef DBG
  1056. TCHAR Dbg[1000];
  1057. #endif
  1058. #ifdef USE_HIVE
  1059. DWORD SuiteArray[] = { SUITE_VALUES };
  1060. #define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
  1061. #endif
  1062. ZeroMemory( pcd, sizeof(COMPLIANCE_DATA) );
  1063. if (!GetCdSourceInstallType(&pcd->InstallType)) {
  1064. #ifdef DBG
  1065. OutputDebugString(TEXT("Couldn't getcdsourceinstalltype\n"));
  1066. #endif
  1067. goto e0;
  1068. }
  1069. if (!GetSourceInstallVariation(&pcd->InstallVariation)) {
  1070. #ifdef DBG
  1071. OutputDebugString(TEXT("Couldn't getsourceinstallvariation\n"));
  1072. #endif
  1073. goto e0;
  1074. }
  1075. if (!GetStepUpMode(&pcd->RequiresValidation)) {
  1076. #ifdef DBG
  1077. OutputDebugString(TEXT("Couldn't getstepupmode\n"));
  1078. #endif
  1079. goto e0;
  1080. }
  1081. RetVal = GetSuiteInfoFromDosnet( &pcd->InstallSuite ) ;
  1082. goto e0;
  1083. #ifdef USE_HIVE
  1084. //
  1085. // now we need to determine if we are installing enterprise or datacenter
  1086. // To do this, we try to load the registry hive, but this won't work on
  1087. // win9x or nt 3.51. So we use dosnet.inf to get the information we need
  1088. // in those cases.
  1089. //
  1090. if ( (Target->InstallType &
  1091. (COMPLIANCE_INSTALLTYPE_WIN31 | COMPLIANCE_INSTALLTYPE_WIN9X)) ||
  1092. (Target->BuildNumberNt < 1381) ) {
  1093. RetVal = GetSuiteInfoFromDosnet( &pcd->InstallSuite ) ;
  1094. goto e0;
  1095. }
  1096. //
  1097. // copy the hive locally since you can only have one open on a hive at a time
  1098. //
  1099. wsprintf( HiveLocation, TEXT("%s\\setupreg.hiv"), NativeSourcePaths[0]);
  1100. GetTempPath(MAX_PATH,TargetPath);
  1101. GetTempFileName(TargetPath,TEXT("set"),0,HiveTarget);
  1102. CopyFile(HiveLocation,HiveTarget,FALSE);
  1103. SetFileAttributes(HiveTarget,FILE_ATTRIBUTE_NORMAL);
  1104. #ifdef DBG
  1105. OutputDebugString(HiveLocation);
  1106. OutputDebugString(TEXT("\n"));
  1107. OutputDebugString(HiveTarget);
  1108. #endif
  1109. //
  1110. // try to unload this first in case we faulted or something and the key is still loaded
  1111. //
  1112. RegUnLoadKey( HKEY_LOCAL_MACHINE, HiveName );
  1113. //
  1114. // need SE_RESTORE_NAME priviledge to call this API!
  1115. //
  1116. rslt = RegLoadKey( HKEY_LOCAL_MACHINE, HiveName, HiveTarget );
  1117. if (rslt != ERROR_SUCCESS) {
  1118. #ifdef DBG
  1119. wsprintf( Dbg, TEXT("Couldn't RegLoadKey, ec = %d\n"), rslt );
  1120. OutputDebugString(Dbg);
  1121. #endif
  1122. //assert(FALSE);
  1123. goto e1;
  1124. }
  1125. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszSetupReg,&hKey);
  1126. if (rslt != ERROR_SUCCESS) {
  1127. #ifdef DBG
  1128. OutputDebugString(TEXT("Couldn't RegOpenKey\n"));
  1129. #endif
  1130. //assert(FALSE);
  1131. goto e2;
  1132. }
  1133. rslt = RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1134. if (rslt != ERROR_SUCCESS || Type != REG_BINARY) {
  1135. #ifdef DBG
  1136. OutputDebugString(TEXT("Couldn't RegQueryValueEx\n"));
  1137. #endif
  1138. //assert(FALSE);
  1139. goto e3;
  1140. }
  1141. for (i = 0,tmp=Buffer[3]; i<SuiteArrayCount;i++) {
  1142. if (tmp & 1) {
  1143. pcd->InstallSuite |= SuiteArray[i];
  1144. }
  1145. tmp = tmp >> 1;
  1146. }
  1147. RetVal = TRUE;
  1148. e3:
  1149. RegCloseKey( hKey );
  1150. e2:
  1151. RegUnLoadKey( HKEY_LOCAL_MACHINE, HiveName );
  1152. e1:
  1153. if (GetFileAttributes(HiveTarget) != 0xFFFFFFFF) {
  1154. SetFileAttributes(HiveTarget,FILE_ATTRIBUTE_NORMAL);
  1155. DeleteFile(HiveTarget);
  1156. }
  1157. #endif // USE_HIVE
  1158. e0:
  1159. return(RetVal);
  1160. }
  1161. BOOL
  1162. GetCurrentNtVersion(
  1163. LPDWORD CurrentInstallType,
  1164. LPDWORD CurrentInstallSuite
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. This routine determines what type of NT you currently have installed, NTW or NTS,
  1169. as well as what product suite you have installed.
  1170. It looks in the registry for this data.
  1171. Arguments:
  1172. CurrentInstallType - receives a COMPLIANCE_INSTALLTYPE_* flag
  1173. CurrentInstallSuite - receives a COMPLIANCE_INSTALLSUITE_* flag
  1174. Return Value:
  1175. TRUE for success, FALSE for failure
  1176. --*/
  1177. {
  1178. LPCTSTR lpszProductKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions");
  1179. LPCTSTR lpszProductType = TEXT("ProductType");
  1180. LPCTSTR lpszProductSuite = TEXT("ProductSuite");
  1181. LPCTSTR lpszProductSuites[] = { TEXT("Small Business"),
  1182. TEXT("Enterprise"),
  1183. TEXT("BackOffice"),
  1184. TEXT("CommunicationServer"),
  1185. TEXT("Terminal Server"),
  1186. TEXT("Small Business(Restricted)"),
  1187. TEXT("EmbeddedNT"),
  1188. TEXT("DataCenter"),
  1189. TEXT("Personal"),
  1190. TEXT("Blade")
  1191. };
  1192. DWORD ProductSuites[] = { SUITE_VALUES };
  1193. #define CountProductSuites sizeof(ProductSuites)/sizeof(DWORD)
  1194. LPCTSTR lpszProductTypeNTW = TEXT("WinNT");
  1195. LPCTSTR lpszCitrixKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Citrix");
  1196. LPCTSTR lpszOemKey = TEXT("OemId");
  1197. LPCTSTR lpszProductVersion = TEXT("ProductVersion");
  1198. HKEY hKey;
  1199. long rslt;
  1200. DWORD Type;
  1201. LPTSTR p;
  1202. TCHAR Buffer[MAX_PATH];
  1203. DWORD BufferSize = sizeof(Buffer);
  1204. DWORD i;
  1205. BOOL retval = FALSE;
  1206. //
  1207. // default to NTW
  1208. //
  1209. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTW;
  1210. *CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
  1211. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszProductKey,&hKey);
  1212. if (rslt != NO_ERROR) {
  1213. return(FALSE);
  1214. }
  1215. rslt = RegQueryValueEx(hKey, lpszProductType, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1216. if (rslt != NO_ERROR || Type != REG_SZ) {
  1217. goto exit;
  1218. }
  1219. if (lstrcmpi(Buffer,lpszProductTypeNTW) != 0) {
  1220. //
  1221. // we have some version of NTS
  1222. //
  1223. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTS;
  1224. }
  1225. retval = TRUE;
  1226. BufferSize = sizeof(Buffer);
  1227. ZeroMemory(Buffer,sizeof(Buffer));
  1228. rslt = RegQueryValueEx(hKey, lpszProductSuite, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1229. if (rslt != NO_ERROR || Type != REG_MULTI_SZ) {
  1230. //
  1231. // might not be there for NT 3.51, just succeed if it's not there
  1232. // Also, won't be there for Professional - aka WKS
  1233. //
  1234. goto exit;
  1235. }
  1236. p = &Buffer[0];
  1237. while (p && *p) {
  1238. for (i = 0; i < CountProductSuites; i++) {
  1239. if (lstrcmp(p, lpszProductSuites[i]) == 0) {
  1240. *CurrentInstallSuite |= ProductSuites[i];
  1241. }
  1242. }
  1243. //
  1244. // point to the next product suite
  1245. //
  1246. p += lstrlen(p) + 1;
  1247. }
  1248. retval = TRUE;
  1249. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_DTC)
  1250. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1251. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
  1252. }
  1253. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ENT)
  1254. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1255. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
  1256. }
  1257. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE)
  1258. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1259. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSB;
  1260. }
  1261. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_SBSR)
  1262. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1263. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
  1264. }
  1265. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_PER)
  1266. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTW) {
  1267. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTWP;
  1268. }
  1269. if (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ANY) {
  1270. *CurrentInstallSuite = *CurrentInstallSuite & (~COMPLIANCE_INSTALLSUITE_NONE);
  1271. }
  1272. exit:
  1273. RegCloseKey(hKey);
  1274. //
  1275. // if we haven't found a product suite at this point, look for Citrix WinFrame,
  1276. // which we'll treat as terminal server
  1277. //
  1278. if (*CurrentInstallSuite == COMPLIANCE_INSTALLSUITE_NONE) {
  1279. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszCitrixKey,&hKey);
  1280. if (rslt != NO_ERROR) {
  1281. return(TRUE);
  1282. }
  1283. BufferSize = sizeof(Buffer);
  1284. rslt = RegQueryValueEx(
  1285. hKey,
  1286. lpszOemKey,
  1287. NULL,
  1288. &Type,
  1289. (LPBYTE) Buffer,
  1290. &BufferSize);
  1291. if (rslt == NO_ERROR && Type == REG_SZ) {
  1292. if (Buffer[0] != TEXT('\0')) {
  1293. BufferSize = sizeof(Buffer);
  1294. rslt = RegQueryValueEx(
  1295. hKey,
  1296. lpszProductVersion,
  1297. NULL,
  1298. &Type,
  1299. (LPBYTE) Buffer,
  1300. &BufferSize);
  1301. if (rslt == NO_ERROR) {
  1302. *CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_HYDRA;
  1303. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
  1304. }
  1305. }
  1306. }
  1307. RegCloseKey(hKey);
  1308. }
  1309. return(retval);
  1310. }
  1311. BOOL
  1312. GetCurrentInstallVariation(
  1313. OUT LPDWORD CurrentInstallVariation,
  1314. IN DWORD CurrentInstallType,
  1315. IN DWORD CurrentInstallBuildNT,
  1316. IN DWORD InstallVersion
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. This routine determines what "variation" you have installed (retail,oem, select,etc.)
  1321. Arguments:
  1322. CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
  1323. It looks at the product Id in the registry to determine this, assuming that the
  1324. product ID is a PID2.0 string. To check whether its a EVAL variation or not
  1325. it looks at "PriorityQuantumMatrix" value in registry
  1326. Return Value:
  1327. None.
  1328. --*/
  1329. {
  1330. LPCTSTR lpszPidKeyWin = TEXT("Software\\Microsoft\\Windows\\CurrentVersion");
  1331. LPCTSTR lpszPidKeyWinNT = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
  1332. LPCTSTR lpszProductId = TEXT("ProductId");
  1333. LPCTSTR szEvalKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Executive");
  1334. LPCTSTR szPQMValue = TEXT("PriorityQuantumMatrix");
  1335. HKEY hKey = NULL;
  1336. long rslt;
  1337. DWORD Type;
  1338. LPTSTR p;
  1339. TCHAR Buffer[MAX_PATH];
  1340. DWORD BufferSize = sizeof(Buffer);
  1341. DWORD i;
  1342. BOOL bResult = FALSE;
  1343. BOOLEAN bDone = FALSE;
  1344. TCHAR Pid20Site[4];
  1345. TCHAR MPCCode[6] = {-1};
  1346. BYTE abPQM[64] = {-1};
  1347. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1348. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,
  1349. ISNT() ? lpszPidKeyWinNT : lpszPidKeyWin,
  1350. &hKey);
  1351. if (rslt != NO_ERROR) {
  1352. goto exit;
  1353. }
  1354. rslt = RegQueryValueEx(hKey, lpszProductId, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1355. if (rslt != NO_ERROR || Type!=REG_SZ || (!IsWinPEMode() && (lstrlen(Buffer) < 20))) {
  1356. //
  1357. // nt 3.51 is pid 1.0 instead of pid 2.0. Just assume it's
  1358. // oem variation for now.
  1359. //
  1360. if (((CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) ||
  1361. (CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTW) ||
  1362. (CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTSTSE)) &&
  1363. (CurrentInstallBuildNT < 1381 )) {
  1364. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  1365. bResult = TRUE;
  1366. }
  1367. goto exit;
  1368. }
  1369. // get the MPC code from PID
  1370. lstrcpyn(MPCCode, Buffer, 6);
  1371. //
  1372. // some versions of the product ID have hyphens in the registry, some do not
  1373. //
  1374. if (_tcschr(Buffer, TEXT('-'))) {
  1375. lstrcpyn(Pid20Site,&Buffer[6],4);
  1376. Pid20Site[3] = (TCHAR) NULL;
  1377. } else {
  1378. lstrcpyn(Pid20Site,&Buffer[5],4);
  1379. Pid20Site[3] = (TCHAR) NULL;
  1380. }
  1381. // OutputDebugString(Pid20Site);
  1382. // OutputDebugString(TEXT("\r\n"));
  1383. // OutputDebugString(MPCCode);
  1384. if (lstrcmp(Pid20Site, OEM_INSTALL_RPC)== 0) {
  1385. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  1386. } else if (lstrcmp(Pid20Site, SELECT_INSTALL_RPC)== 0) {
  1387. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1388. } else if (lstrcmp(Pid20Site, MSDN_INSTALL_RPC)== 0) {
  1389. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
  1390. } else if (lstrcmp(MPCCode, EVAL_MPC) == 0) {
  1391. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  1392. } else if ((lstrcmp(MPCCode, SRV_NFR_MPC) == 0) ||
  1393. (lstrcmp(MPCCode, ASRV_NFR_MPC) == 0) ||
  1394. (lstrcmp(MPCCode, NT4SRV_NFR_MPC) == 0)){
  1395. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
  1396. } else {
  1397. //
  1398. // find out if installation is of type EVAL variation (On NT install only)
  1399. // if timebomb is set we assume its EVAL except for DataCenter because
  1400. // there is no EVAL DataCenter SKU.
  1401. //
  1402. if (ISNT() && (CurrentInstallType != COMPLIANCE_INSTALLTYPE_NTSDTC) && (InstallVersion < 500)) {
  1403. HKEY hEvalKey = NULL;
  1404. if (RegOpenKey(HKEY_LOCAL_MACHINE, szEvalKey, &hEvalKey) == ERROR_SUCCESS) {
  1405. DWORD dwSize = sizeof(abPQM);
  1406. if (RegQueryValueEx(hEvalKey, szPQMValue, NULL, &Type, abPQM, &dwSize)
  1407. == ERROR_SUCCESS) {
  1408. // any of bytes 4-7 (inclusive)
  1409. if ((Type == REG_BINARY) && (dwSize >= 8) && (*(ULONG *)(abPQM + 4))) {
  1410. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  1411. }
  1412. }
  1413. RegCloseKey(hEvalKey);
  1414. }
  1415. }
  1416. // last default assumption (since we could not find var type).
  1417. if (*CurrentInstallVariation == COMPLIANCE_INSTALLVAR_SELECT)
  1418. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  1419. }
  1420. bResult = TRUE;
  1421. exit:
  1422. //
  1423. // If we couldn't find a PID, just treat the current OS as retail
  1424. //
  1425. if (!bResult) {
  1426. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  1427. bResult = TRUE;
  1428. }
  1429. if (hKey)
  1430. RegCloseKey(hKey);
  1431. return bResult;
  1432. }
  1433. BOOL
  1434. DetermineCurrentInstallation(
  1435. LPDWORD CurrentInstallType,
  1436. LPDWORD CurrentInstallVariation,
  1437. LPDWORD CurrentInstallVersion,
  1438. LPDWORD CurrentInstallBuildNT,
  1439. LPDWORD CurrentInstallBuildWin9x,
  1440. LPDWORD CurrentInstallSuite,
  1441. LPDWORD CurrentInstallServicePack
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. This routine determines the current installation you have installed, including
  1446. a) current install type (NTW,NTS,Win9x
  1447. b) current install variation (oem,select, retail)
  1448. c) current install version (for NT only!)
  1449. d) current install suite (SBS, ENTERPRISE,etc.)
  1450. Arguments:
  1451. CurrentInstallType - receives a COMPLIANCE_INSTALLTYPE_* flag
  1452. CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
  1453. CurrentInstallVersion - receives a representation of the build (major.minor * 100), ie., 3.51 == 351
  1454. CurrentInstallBuildNT - build number for an nt install
  1455. CurrentInstallBuildWin9 - build number for a win9x install
  1456. CurrentInstallSuite - receives a COMPLIANCE_INSTALLSUITE_* flag
  1457. Return Value:
  1458. TRUE for success, FALSE for failure.
  1459. --*/
  1460. {
  1461. BOOL useExtendedInfo;
  1462. union {
  1463. OSVERSIONINFO Normal;
  1464. OSVERSIONINFOEX Ex;
  1465. } Ovi;
  1466. #ifdef DBG
  1467. TCHAR dbg[1000];
  1468. #endif
  1469. if (!CurrentInstallType || !CurrentInstallVariation || !CurrentInstallVersion || !CurrentInstallSuite) {
  1470. SetLastError( ERROR_INVALID_PARAMETER );
  1471. return(FALSE);
  1472. }
  1473. useExtendedInfo = TRUE;
  1474. Ovi.Ex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1475. if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Ex) ) {
  1476. //
  1477. // EX size not available; try the normal one
  1478. //
  1479. Ovi.Normal.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1480. if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Normal) ) {
  1481. assert(FALSE);
  1482. return(FALSE);
  1483. }
  1484. useExtendedInfo = FALSE;
  1485. }
  1486. switch (Ovi.Normal.dwPlatformId) {
  1487. case VER_PLATFORM_WIN32s:
  1488. #ifdef DBG
  1489. OutputDebugString(TEXT("Win32s current installation!!!"));
  1490. #endif
  1491. //assert(FALSE);
  1492. return(FALSE);
  1493. break;
  1494. case VER_PLATFORM_WIN32_WINDOWS:
  1495. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_WIN9X;
  1496. *CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
  1497. *CurrentInstallBuildNT = 0;
  1498. *CurrentInstallBuildWin9x = Ovi.Normal.dwBuildNumber;
  1499. #ifdef DBG
  1500. wsprintf(dbg, TEXT("%d\n"), *CurrentInstallBuildWin9x);
  1501. OutputDebugString(dbg);
  1502. #endif
  1503. //
  1504. // Need to know what version of windows is installed so we can block upgrade
  1505. // from win95.
  1506. //
  1507. *CurrentInstallVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion;
  1508. if (useExtendedInfo) {
  1509. *CurrentInstallServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor;
  1510. } else {
  1511. *CurrentInstallServicePack = 0;
  1512. }
  1513. break;
  1514. case VER_PLATFORM_WIN32_NT:
  1515. if (!GetCurrentNtVersion(
  1516. CurrentInstallType,
  1517. CurrentInstallSuite)) {
  1518. return(FALSE);
  1519. }
  1520. *CurrentInstallVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion;
  1521. if (useExtendedInfo) {
  1522. *CurrentInstallServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor;
  1523. } else {
  1524. *CurrentInstallServicePack = 0;
  1525. }
  1526. *CurrentInstallBuildWin9x = 0;
  1527. *CurrentInstallBuildNT = Ovi.Normal.dwBuildNumber;
  1528. if (*CurrentInstallBuildNT <= 1381
  1529. && *CurrentInstallSuite == COMPLIANCE_INSTALLSUITE_HYDRA) {
  1530. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
  1531. }
  1532. break;
  1533. default:
  1534. #ifdef DBG
  1535. OutputDebugString(TEXT("unknown installation!!!"));
  1536. #endif
  1537. assert(FALSE);
  1538. return(FALSE);
  1539. }
  1540. if (!GetCurrentInstallVariation(CurrentInstallVariation,*CurrentInstallType,*CurrentInstallBuildNT, *CurrentInstallVersion)) {
  1541. #ifdef DBG
  1542. OutputDebugString(TEXT("GetCurrentInstallVariation failed\n"));
  1543. #endif
  1544. //assert(FALSE);
  1545. return(FALSE);
  1546. }
  1547. return(TRUE);
  1548. }
  1549. BOOL
  1550. IsCompliant(
  1551. PBOOL UpgradeOnly,
  1552. PBOOL NoUpgradeAllowed,
  1553. PUINT SrcSku,
  1554. PUINT CurrentInstallType,
  1555. PUINT CurrentInstallVersion,
  1556. PUINT Reason
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. This routines determines if your current installation is compliant (if you are allowed to proceed with your installation).
  1561. To do this, it retreives your current installation and determines the sku for your source installation.
  1562. It then compares the target against the source to determine if the source sku allows an upgrade/clean install
  1563. from your target installation.
  1564. Arguments:
  1565. UpgradeOnly - This flag gets set to TRUE if the current SKU only allows upgrades. This
  1566. lets winnt32 know that it should not allow a clean install from the current
  1567. media. This get's set correctly regardless of the compliance check passing
  1568. SrcSku - COMPLIANCE_SKU flag indicating source sku (for error msg's)
  1569. Reason - COMPLIANCEERR flag indicating why compliance check failed.
  1570. Return Value:
  1571. TRUE if the install is compliant, FALSE if it isn't allowed
  1572. --*/
  1573. {
  1574. DWORD SourceSku;
  1575. DWORD SourceSkuVariation;
  1576. DWORD SourceVersion;
  1577. DWORD SourceBuildNum;
  1578. TCHAR DosnetPath[MAX_PATH] = {0};
  1579. COMPLIANCE_DATA TargetData;
  1580. ZeroMemory(&TargetData, sizeof(TargetData) );
  1581. *UpgradeOnly = FALSE;
  1582. *NoUpgradeAllowed = TRUE;
  1583. *Reason = COMPLIANCEERR_UNKNOWN;
  1584. *SrcSku = COMPLIANCE_SKU_NONE;
  1585. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_UNKNOWN;
  1586. *CurrentInstallVersion = 0;
  1587. if (!DetermineCurrentInstallation(&TargetData.InstallType,
  1588. &TargetData.InstallVariation,
  1589. &TargetData.MinimumVersion,
  1590. &TargetData.BuildNumberNt,
  1591. &TargetData.BuildNumberWin9x,
  1592. &TargetData.InstallSuite,
  1593. &TargetData.InstallServicePack)) {
  1594. #ifdef DBG
  1595. OutputDebugString(TEXT("Error determining current installation"));
  1596. #endif
  1597. *Reason = COMPLIANCEERR_UNKNOWNTARGET;
  1598. return(FALSE);
  1599. }
  1600. *CurrentInstallType = TargetData.InstallType;
  1601. if (TargetData.InstallType & COMPLIANCE_INSTALLTYPE_WIN9X) {
  1602. *CurrentInstallVersion = TargetData.BuildNumberWin9x;
  1603. } else {
  1604. *CurrentInstallVersion = TargetData.BuildNumberNt;
  1605. }
  1606. if ((SourceSku = DetermineSourceProduct(&SourceSkuVariation,&TargetData)) == COMPLIANCE_SKU_NONE) {
  1607. #ifdef DBG
  1608. OutputDebugString(TEXT("couldn't determine source sku!"));
  1609. #endif
  1610. *Reason = COMPLIANCEERR_UNKNOWNSOURCE;
  1611. return(FALSE);
  1612. }
  1613. wsprintf(DosnetPath, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
  1614. if (!DetermineSourceVersionInfo(DosnetPath, &SourceVersion, &SourceBuildNum)) {
  1615. *Reason = COMPLIANCEERR_UNKNOWNSOURCE;
  1616. return(FALSE);
  1617. }
  1618. switch (SourceSku) {
  1619. case COMPLIANCE_SKU_NTW32U:
  1620. //case COMPLIANCE_SKU_NTWU:
  1621. //case COMPLIANCE_SKU_NTSEU:
  1622. case COMPLIANCE_SKU_NTSU:
  1623. case COMPLIANCE_SKU_NTSEU:
  1624. case COMPLIANCE_SKU_NTWPU:
  1625. case COMPLIANCE_SKU_NTSBU:
  1626. case COMPLIANCE_SKU_NTSBSU:
  1627. *UpgradeOnly = TRUE;
  1628. break;
  1629. default:
  1630. *UpgradeOnly = FALSE;
  1631. }
  1632. *SrcSku = SourceSku;
  1633. if( ISNT() && TargetData.MinimumVersion == 400 && TargetData.InstallServicePack < 500) {
  1634. *Reason = COMPLIANCEERR_SERVICEPACK5;
  1635. *NoUpgradeAllowed = TRUE;
  1636. return(FALSE);
  1637. }
  1638. return CheckCompliance(SourceSku, SourceSkuVariation, SourceVersion,
  1639. SourceBuildNum, &TargetData, Reason, NoUpgradeAllowed);
  1640. }
  1641. BOOL
  1642. IsWinPEMode(
  1643. VOID
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. Finds out if we are running under WinPE environment.
  1648. Arguments:
  1649. None
  1650. Return value:
  1651. TRUE or FALSE
  1652. --*/
  1653. {
  1654. static BOOL Initialized = FALSE;
  1655. static BOOL WinPEMode = FALSE;
  1656. if (!Initialized) {
  1657. TCHAR *MiniNTKeyName = TEXT("SYSTEM\\CurrentControlSet\\Control\\MiniNT");
  1658. HKEY MiniNTKey = NULL;
  1659. LONG RegResult;
  1660. RegResult = RegOpenKey(HKEY_LOCAL_MACHINE,
  1661. MiniNTKeyName,
  1662. &MiniNTKey);
  1663. if (RegResult == ERROR_SUCCESS) {
  1664. WinPEMode = TRUE;
  1665. RegCloseKey(MiniNTKey);
  1666. }
  1667. Initialized = TRUE;
  1668. }
  1669. return WinPEMode;
  1670. }
  1671. #endif