Leaked source code of windows server 2003
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

  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) || (wcsncmp(szPid20, DOTNET_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. if( *pInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE) {
  652. *pInstallType = COMPLIANCE_INSTALLTYPE_NTSPOW;
  653. } else {
  654. *pInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
  655. }
  656. } else {
  657. if (*pInstallSuite & COMPLIANCE_INSTALLSUITE_SBSR) {
  658. *pInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
  659. }
  660. }
  661. }
  662. }
  663. }
  664. }
  665. //
  666. // since there is no data center EVAL type if we detect its eval
  667. // because of time bomb set, we assume it to be CD-Retail.
  668. //
  669. if((pcd->InstallVariation == COMPLIANCE_INSTALLVAR_EVAL) &&
  670. (*pInstallType == COMPLIANCE_INSTALLTYPE_NTSDTC)) {
  671. pcd->InstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  672. }
  673. //
  674. // Free up the allocated memory
  675. //
  676. if (UniqueIdFromReg)
  677. SpMemFree(UniqueIdFromReg);
  678. if (Pid)
  679. SpMemFree(Pid);
  680. return(TRUE);
  681. }
  682. BOOLEAN
  683. pSpIsCompliant(
  684. IN DWORD SourceVersion,
  685. IN DWORD SourceBuildNum,
  686. IN PDISK_REGION OsPartRegion,
  687. IN PWSTR SystemRoot,
  688. OUT PBOOLEAN UpgradeOnlyCompliant
  689. )
  690. /*++
  691. Routine Description:
  692. This routine determines if the current specified installation is compliant for the
  693. source we want to install
  694. Arguments:
  695. InfPath - inf file path containing [Version] section with DriverVer data
  696. OsPartRegion - points to target
  697. SystemRoot - points to target
  698. UpgradeOnlyCompliant - set to TRUE if we can only allow upgrades from the source SKU
  699. Return Value:
  700. TRUE if the current target is compliant for the source.
  701. --*/
  702. {
  703. ULONG MajorVersion, MinorVersion, BuildNumber, ProductSuiteMask;
  704. NT_PRODUCT_TYPE ProductType;
  705. UPG_PROGRESS_TYPE UpgradeProgressValue;
  706. PWSTR UniqueIdFromReg, Pid;
  707. NTSTATUS NtStatus;
  708. BOOLEAN Rslt;
  709. BOOL UpgOnly = FALSE;
  710. COMPLIANCE_DATA TargetData;
  711. DWORD SourceData,SourceSkuVariation;
  712. UINT dontcare;
  713. BOOL dontcare2;
  714. assert(UpgradeOnlyCompliant != NULL);
  715. if ((SourceData = DetermineSourceProduct(&SourceSkuVariation,NULL))== COMPLIANCE_SKU_NONE) {
  716. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "setup: Couldnt' determine source SKU\n" ));
  717. return(FALSE);
  718. }
  719. if (!pSpDetermineCurrentInstallation( OsPartRegion, SystemRoot, &TargetData)) {
  720. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "setup: pSpDetermineCurrentInstallation failed\n" ));
  721. return(FALSE);
  722. }
  723. UpgOnly = TargetData.RequiresValidation;
  724. Rslt = CheckCompliance(SourceData, SourceSkuVariation, SourceVersion,
  725. SourceBuildNum, &TargetData,&dontcare,&dontcare2);
  726. *UpgradeOnlyCompliant = (UpgOnly != 0);
  727. return(Rslt);
  728. }
  729. #define NibbleToChar(x) (N2C[x])
  730. #define CharToNibble(x) ((x)>='0'&&(x)<='9' ? (x)-'0' : ((10+(x)-'A')&0x000f))
  731. char N2C[] = {
  732. '0', '1', '2', '3', '4', '5', '6', '7',
  733. '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  734. };
  735. BOOLEAN
  736. MyTranslatePrivateProfileStruct(
  737. PSTR InputString,
  738. LPVOID lpStruct,
  739. UINT uSizeStruct
  740. )
  741. /*++
  742. Routine Description:
  743. translates a string from an encoded checksummed version into the real structure.
  744. stolen from GetPrivateProfileStructA
  745. Arguments:
  746. InputString - pointer to input string to convert
  747. lpStruct - point to structure that receives the converted data
  748. uSizeStruct - size of the input structure
  749. Return Value:
  750. TRUE if it succeeds in translating into the specified structure, FALSE otherwise.
  751. --*/
  752. {
  753. CHAR szBuf[256] = {0};
  754. PSTR lpBuf, lpBufTemp, lpFreeBuffer;
  755. UINT nLen,tmp;
  756. BYTE checksum;
  757. BOOLEAN Result;
  758. lpFreeBuffer = NULL;
  759. lpBuf = (PSTR)szBuf;
  760. Result = FALSE;
  761. nLen = strlen( InputString );
  762. RtlCopyMemory( lpBuf, InputString, nLen );
  763. if (nLen == uSizeStruct*2+2) {
  764. /* Room for the one byte check sum */
  765. uSizeStruct+=1;
  766. checksum = 0;
  767. for (lpBufTemp=lpBuf; uSizeStruct!=0; --uSizeStruct) {
  768. BYTE bStruct;
  769. BYTE cTemp;
  770. cTemp = *lpBufTemp++;
  771. bStruct = (BYTE)CharToNibble(cTemp);
  772. cTemp = *lpBufTemp++;
  773. bStruct = (BYTE)((bStruct<<4) | CharToNibble(cTemp));
  774. if (uSizeStruct == 1) {
  775. if (checksum == bStruct) {
  776. Result = TRUE;
  777. }
  778. break;
  779. }
  780. checksum += bStruct;
  781. *((LPBYTE)lpStruct)++ = bStruct;
  782. }
  783. }
  784. return Result;
  785. }
  786. BOOLEAN
  787. SpGetStepUpMode(
  788. PWSTR PidExtraData,
  789. BOOLEAN *StepUpMode
  790. )
  791. /*++
  792. Routine Description:
  793. This routine determines if the specified source is in Step Up Mode or
  794. if it's a full retail install.
  795. Arguments:
  796. PidExtraData - checksummed encoded data read out of setupp.ini
  797. StepUpMode - set to TRUE if we're in stepup mode. value is undefined if
  798. we fail to translate the input data.
  799. This routine assumes that the data passed in is a string set by the "pidinit"
  800. program. It decodes this data and makes sure the checksum is correct.
  801. It then checks the CRC value tacked onto the string to determine if the
  802. data has been tampered with.
  803. If both of these checks pass, then it looks at the actual data.
  804. The actual check is this: If the 3rd and 5th bytes are modulo 2 (when
  805. subtracted from the base value 'a'), then we're in stepup mode. Otherwise
  806. we're in full retail mode.
  807. Note that the intent of this algorithm isn't to provide alot of security
  808. (it will be trivial to copy the desired setupp.ini over the current one),
  809. it's main intent is to discourage people from tampering with these values
  810. in the same manner that data is set in the default hives to discourage
  811. tampering.
  812. Return Value:
  813. TRUE if we're able to determine the stepupmode. FALSE if the input data is bogus.
  814. --*/
  815. {
  816. CHAR Buffer[64] = {0};
  817. CHAR StepUpArray[14];
  818. ULONG Needed;
  819. BOOL Mode;
  820. NTSTATUS NtStatus;
  821. NtStatus = RtlUnicodeToOemN(Buffer,
  822. sizeof(Buffer),
  823. &Needed,
  824. PidExtraData,
  825. wcslen(PidExtraData)*sizeof(WCHAR)
  826. );
  827. if (! NT_SUCCESS(NtStatus)) {
  828. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: SpGetStepUpMode couldn't RtlUnicodeToOemN failed, ec = %x\n", NtStatus ));
  829. return(FALSE);
  830. }
  831. if (!MyTranslatePrivateProfileStruct(Buffer,StepUpArray,sizeof(StepUpArray))) {
  832. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "Setup: SpGetStepUpMode couldn't MyTranslatePrivateProfileStruct\n" ));
  833. return(FALSE);
  834. }
  835. if (!IsValidStepUpMode( StepUpArray , &Mode )) {
  836. return(FALSE);
  837. }
  838. *StepUpMode = Mode ? TRUE : FALSE;
  839. return(TRUE);
  840. }
  841. #endif
  842. //
  843. // User mode only functions
  844. //
  845. #ifndef KERNEL_MODE
  846. BOOL
  847. GetCdSourceInstallType(
  848. LPDWORD SourceInstallType
  849. )
  850. /*++
  851. Routine Description:
  852. This routine determines what version of NT you are installing, NTW or NTS. It does this by looking in
  853. dosnet.inf
  854. Arguments:
  855. SourceInstallType -- receives a COMPLIANCE_INSTALLTYPE flag indicating what type you are installing
  856. Return Value:
  857. TRUE for success, FALSE for failure
  858. --*/
  859. {
  860. TCHAR FileName[MAX_PATH];
  861. TCHAR Buffer[10];
  862. TCHAR ptr[1] = {0};
  863. LPTSTR p = &ptr[1];
  864. wsprintf( FileName, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
  865. GetPrivateProfileString(TEXT("Miscellaneous"), TEXT("ProductType"), TEXT("0"),
  866. Buffer, sizeof(Buffer)/sizeof(TCHAR), FileName);
  867. switch (_tcstoul(Buffer, &p, 10) ) {
  868. case 0:
  869. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTW;
  870. break;
  871. case 1:
  872. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTS;
  873. break;
  874. case 2:
  875. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
  876. break;
  877. case 3:
  878. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
  879. break;
  880. case 4:
  881. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTWP;
  882. break;
  883. case 5:
  884. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSB;
  885. break;
  886. case 6:
  887. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
  888. break;
  889. default:
  890. *SourceInstallType = COMPLIANCE_INSTALLTYPE_NTW;
  891. return(FALSE);
  892. }
  893. return(TRUE);
  894. }
  895. BOOL
  896. GetStepUpMode(
  897. BOOL *StepUpMode
  898. )
  899. /*++
  900. Routine Description:
  901. This routine determines if the specified source is in Step Up Mode or
  902. if it's a full retail install.
  903. Arguments:
  904. StepUpMode - set to TRUE if we're in stepup mode. value is undefined if
  905. we fail to translate the input data.
  906. This routine assumes that the data passed in is a string set by the "pidinit"
  907. program. It decodes this data and makes sure the checksum is correct.
  908. It then checks the CRC value tacked onto the string to determine if the
  909. data has been tampered with.
  910. If both of these checks pass, then it looks at the actual data.
  911. The actual check is this: If the 3rd and 5th bytes are modulo 2 (when
  912. subtracted from the base value 'a'), then we're in stepup mode. Otherwise
  913. we're in full retail mode.
  914. Note that the intent of this algorithm isn't to provide alot of security
  915. (it will be trivial to copy the desired setupp.ini over the current one),
  916. it's main intent is to discourage people from tampering with these values
  917. in the same manner that data is set in the default hives to discourage
  918. tampering.
  919. Return Value:
  920. TRUE if we're able to determine the stepupmode. FALSE if the input data is bogus.
  921. --*/
  922. {
  923. char FileName[MAX_PATH];
  924. char data[14];
  925. TCHAR ptr[1] = {0};
  926. LPTSTR p = &ptr[1];
  927. #ifdef UNICODE
  928. char SourcePath[MAX_PATH];
  929. BOOL changed = FALSE;
  930. WideCharToMultiByte(CP_ACP,
  931. 0,
  932. NativeSourcePaths[0],
  933. MAX_PATH,
  934. SourcePath,
  935. sizeof(SourcePath),
  936. "?",
  937. &changed);
  938. sprintf( FileName, "%s\\setupp.ini", SourcePath);
  939. #else
  940. sprintf( FileName, "%s\\setupp.ini", NativeSourcePaths[0]);
  941. #endif
  942. GetPrivateProfileStructA("Pid",
  943. "ExtraData",
  944. data,
  945. sizeof(data),
  946. FileName);
  947. if (!IsValidStepUpMode(data,StepUpMode)) {
  948. return(FALSE);
  949. }
  950. return(TRUE);
  951. }
  952. BOOL
  953. GetSuiteInfoFromDosnet(
  954. OUT LPDWORD Suite
  955. )
  956. /*++
  957. Routine Description:
  958. This routine determines what suite you are installing
  959. It does this by looking at dosnet.inf
  960. Arguments:
  961. Suite -- receives a COMPLIANCE_INSTALLSUITE flag
  962. Return Value:
  963. TRUE for success, FALSE for failure
  964. --*/
  965. {
  966. TCHAR FileName[MAX_PATH];
  967. TCHAR Buffer[10];
  968. TCHAR ptr[1] = {0};
  969. LPTSTR p = &ptr[1];
  970. *Suite = COMPLIANCE_INSTALLSUITE_ANY;
  971. wsprintf( FileName, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
  972. GetPrivateProfileString(TEXT("Miscellaneous"), TEXT("ProductType"), TEXT("0"),
  973. Buffer, sizeof(Buffer)/sizeof(TCHAR), FileName);
  974. switch (_tcstoul(Buffer, &p, 10) ) {
  975. case 0:
  976. case 1:
  977. *Suite = COMPLIANCE_INSTALLSUITE_NONE;
  978. break;
  979. case 2:
  980. *Suite = COMPLIANCE_INSTALLSUITE_ENT;
  981. break;
  982. case 3:
  983. *Suite = COMPLIANCE_INSTALLSUITE_DTC;
  984. break;
  985. case 4:
  986. *Suite = COMPLIANCE_INSTALLSUITE_PER;
  987. break;
  988. case 5:
  989. *Suite = COMPLIANCE_INSTALLSUITE_BLADE;
  990. break;
  991. case 6:
  992. *Suite = COMPLIANCE_INSTALLSUITE_SBS;
  993. break;
  994. default:
  995. ;
  996. #ifdef DBG
  997. OutputDebugString( TEXT("Invalid ProductType!\n"));
  998. #endif
  999. return(FALSE);
  1000. }
  1001. return (TRUE);
  1002. }
  1003. BOOL
  1004. GetSourceInstallVariation(
  1005. LPDWORD SourceInstallVariation
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. This routine determines what variation of NT you are installing, SELECT,OEM,retail...
  1010. Arguments:
  1011. SourceInstallVariation -- receives a COMPLIANCE_INSTALLVAR flag indicating what var
  1012. type you are installing
  1013. Return Value:
  1014. TRUE for success, FALSE for failure
  1015. --*/
  1016. {
  1017. GetSourceInstallType(SourceInstallVariation);
  1018. /*
  1019. switch(SourceInstallType) {
  1020. case SelectInstall:
  1021. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1022. break;
  1023. case OEMInstall:
  1024. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  1025. break;
  1026. case RetailInstall:
  1027. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  1028. break;
  1029. case MSDNInstall:
  1030. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
  1031. break;
  1032. case EvalInstall:
  1033. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  1034. break;
  1035. case NFRInstall:
  1036. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
  1037. break;
  1038. default:
  1039. *SourceInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1040. break;
  1041. }
  1042. */
  1043. return(TRUE);
  1044. }
  1045. BOOL
  1046. GetSourceComplianceData(
  1047. OUT PCOMPLIANCE_DATA pcd,
  1048. IN PCOMPLIANCE_DATA Target
  1049. )
  1050. {
  1051. #ifdef USE_HIVE
  1052. TCHAR HiveLocation[MAX_PATH];
  1053. TCHAR HiveTarget[MAX_PATH];
  1054. TCHAR HivePath[MAX_PATH];
  1055. TCHAR HiveName[MAX_PATH] = TEXT("xSETREG");
  1056. TCHAR lpszSetupReg[MAX_PATH] = TEXT("xSETREG\\ControlSet001\\Services\\setupdd");
  1057. TCHAR TargetPath[MAX_PATH];
  1058. LONG rslt;
  1059. HKEY hKey;
  1060. DWORD Type;
  1061. DWORD Buffer[4];
  1062. DWORD BufferSize = sizeof(Buffer);
  1063. DWORD tmp,i;
  1064. #endif
  1065. BOOL RetVal = FALSE;
  1066. #ifdef DBG
  1067. TCHAR Dbg[1000];
  1068. #endif
  1069. #ifdef USE_HIVE
  1070. DWORD SuiteArray[] = { SUITE_VALUES };
  1071. #define SuiteArrayCount sizeof(SuiteArray)/sizeof(DWORD)
  1072. #endif
  1073. ZeroMemory( pcd, sizeof(COMPLIANCE_DATA) );
  1074. if (!GetCdSourceInstallType(&pcd->InstallType)) {
  1075. #ifdef DBG
  1076. OutputDebugString(TEXT("Couldn't getcdsourceinstalltype\n"));
  1077. #endif
  1078. goto e0;
  1079. }
  1080. if (!GetSourceInstallVariation(&pcd->InstallVariation)) {
  1081. #ifdef DBG
  1082. OutputDebugString(TEXT("Couldn't getsourceinstallvariation\n"));
  1083. #endif
  1084. goto e0;
  1085. }
  1086. if (!GetStepUpMode(&pcd->RequiresValidation)) {
  1087. #ifdef DBG
  1088. OutputDebugString(TEXT("Couldn't getstepupmode\n"));
  1089. #endif
  1090. goto e0;
  1091. }
  1092. RetVal = GetSuiteInfoFromDosnet( &pcd->InstallSuite ) ;
  1093. goto e0;
  1094. #ifdef USE_HIVE
  1095. //
  1096. // now we need to determine if we are installing enterprise or datacenter
  1097. // To do this, we try to load the registry hive, but this won't work on
  1098. // win9x or nt 3.51. So we use dosnet.inf to get the information we need
  1099. // in those cases.
  1100. //
  1101. if ( (Target->InstallType &
  1102. (COMPLIANCE_INSTALLTYPE_WIN31 | COMPLIANCE_INSTALLTYPE_WIN9X)) ||
  1103. (Target->BuildNumberNt < 1381) ) {
  1104. RetVal = GetSuiteInfoFromDosnet( &pcd->InstallSuite ) ;
  1105. goto e0;
  1106. }
  1107. //
  1108. // copy the hive locally since you can only have one open on a hive at a time
  1109. //
  1110. wsprintf( HiveLocation, TEXT("%s\\setupreg.hiv"), NativeSourcePaths[0]);
  1111. GetTempPath(MAX_PATH,TargetPath);
  1112. GetTempFileName(TargetPath,TEXT("set"),0,HiveTarget);
  1113. CopyFile(HiveLocation,HiveTarget,FALSE);
  1114. SetFileAttributes(HiveTarget,FILE_ATTRIBUTE_NORMAL);
  1115. #ifdef DBG
  1116. OutputDebugString(HiveLocation);
  1117. OutputDebugString(TEXT("\n"));
  1118. OutputDebugString(HiveTarget);
  1119. #endif
  1120. //
  1121. // try to unload this first in case we faulted or something and the key is still loaded
  1122. //
  1123. RegUnLoadKey( HKEY_LOCAL_MACHINE, HiveName );
  1124. //
  1125. // need SE_RESTORE_NAME priviledge to call this API!
  1126. //
  1127. rslt = RegLoadKey( HKEY_LOCAL_MACHINE, HiveName, HiveTarget );
  1128. if (rslt != ERROR_SUCCESS) {
  1129. #ifdef DBG
  1130. wsprintf( Dbg, TEXT("Couldn't RegLoadKey, ec = %d\n"), rslt );
  1131. OutputDebugString(Dbg);
  1132. #endif
  1133. //assert(FALSE);
  1134. goto e1;
  1135. }
  1136. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszSetupReg,&hKey);
  1137. if (rslt != ERROR_SUCCESS) {
  1138. #ifdef DBG
  1139. OutputDebugString(TEXT("Couldn't RegOpenKey\n"));
  1140. #endif
  1141. //assert(FALSE);
  1142. goto e2;
  1143. }
  1144. rslt = RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1145. if (rslt != ERROR_SUCCESS || Type != REG_BINARY) {
  1146. #ifdef DBG
  1147. OutputDebugString(TEXT("Couldn't RegQueryValueEx\n"));
  1148. #endif
  1149. //assert(FALSE);
  1150. goto e3;
  1151. }
  1152. for (i = 0,tmp=Buffer[3]; i<SuiteArrayCount;i++) {
  1153. if (tmp & 1) {
  1154. pcd->InstallSuite |= SuiteArray[i];
  1155. }
  1156. tmp = tmp >> 1;
  1157. }
  1158. RetVal = TRUE;
  1159. e3:
  1160. RegCloseKey( hKey );
  1161. e2:
  1162. RegUnLoadKey( HKEY_LOCAL_MACHINE, HiveName );
  1163. e1:
  1164. if (GetFileAttributes(HiveTarget) != 0xFFFFFFFF) {
  1165. SetFileAttributes(HiveTarget,FILE_ATTRIBUTE_NORMAL);
  1166. DeleteFile(HiveTarget);
  1167. }
  1168. #endif // USE_HIVE
  1169. e0:
  1170. return(RetVal);
  1171. }
  1172. BOOL
  1173. GetCurrentNtVersion(
  1174. LPDWORD CurrentInstallType,
  1175. LPDWORD CurrentInstallSuite
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. This routine determines what type of NT you currently have installed, NTW or NTS,
  1180. as well as what product suite you have installed.
  1181. It looks in the registry for this data.
  1182. Arguments:
  1183. CurrentInstallType - receives a COMPLIANCE_INSTALLTYPE_* flag
  1184. CurrentInstallSuite - receives a COMPLIANCE_INSTALLSUITE_* flag
  1185. Return Value:
  1186. TRUE for success, FALSE for failure
  1187. --*/
  1188. {
  1189. LPCTSTR lpszProductKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions");
  1190. LPCTSTR lpszProductType = TEXT("ProductType");
  1191. LPCTSTR lpszProductSuite = TEXT("ProductSuite");
  1192. LPCTSTR lpszProductSuites[] = { TEXT("Small Business"),
  1193. TEXT("Enterprise"),
  1194. TEXT("BackOffice"),
  1195. TEXT("CommunicationServer"),
  1196. TEXT("Terminal Server"),
  1197. TEXT("Small Business(Restricted)"),
  1198. TEXT("EmbeddedNT"),
  1199. TEXT("DataCenter"),
  1200. TEXT("Personal"),
  1201. TEXT("Blade")
  1202. };
  1203. LPCTSTR lpszProductPowered = TEXT("Server Appliance");
  1204. DWORD ProductSuites[] = { SUITE_VALUES };
  1205. #define CountProductSuites sizeof(ProductSuites)/sizeof(DWORD)
  1206. LPCTSTR lpszProductTypeNTW = TEXT("WinNT");
  1207. LPCTSTR lpszCitrixKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Citrix");
  1208. LPCTSTR lpszOemKey = TEXT("OemId");
  1209. LPCTSTR lpszProductVersion = TEXT("ProductVersion");
  1210. HKEY hKey;
  1211. long rslt;
  1212. DWORD Type;
  1213. LPTSTR p;
  1214. TCHAR Buffer[MAX_PATH];
  1215. DWORD BufferSize = sizeof(Buffer);
  1216. DWORD i;
  1217. BOOL retval = FALSE;
  1218. //
  1219. // default to NTW
  1220. //
  1221. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTW;
  1222. *CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
  1223. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszProductKey,&hKey);
  1224. if (rslt != NO_ERROR) {
  1225. return(FALSE);
  1226. }
  1227. rslt = RegQueryValueEx(hKey, lpszProductType, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1228. if (rslt != NO_ERROR || Type != REG_SZ) {
  1229. goto exit;
  1230. }
  1231. if (lstrcmpi(Buffer,lpszProductTypeNTW) != 0) {
  1232. //
  1233. // we have some version of NTS
  1234. //
  1235. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTS;
  1236. }
  1237. retval = TRUE;
  1238. BufferSize = sizeof(Buffer);
  1239. ZeroMemory(Buffer,sizeof(Buffer));
  1240. rslt = RegQueryValueEx(hKey, lpszProductSuite, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1241. if (rslt != NO_ERROR || Type != REG_MULTI_SZ) {
  1242. //
  1243. // might not be there for NT 3.51, just succeed if it's not there
  1244. // Also, won't be there for Professional - aka WKS
  1245. //
  1246. goto exit;
  1247. }
  1248. p = &Buffer[0];
  1249. while (p && *p) {
  1250. for (i = 0; i < CountProductSuites; i++) {
  1251. if (lstrcmp(p, lpszProductSuites[i]) == 0) {
  1252. *CurrentInstallSuite |= ProductSuites[i];
  1253. }
  1254. // W2k powered windows uses the same bit as blade.
  1255. else if( lstrcmp(p, lpszProductPowered) == 0) {
  1256. *CurrentInstallSuite |= COMPLIANCE_INSTALLSUITE_BLADE;
  1257. }
  1258. }
  1259. //
  1260. // point to the next product suite
  1261. //
  1262. p += lstrlen(p) + 1;
  1263. }
  1264. retval = TRUE;
  1265. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_DTC)
  1266. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1267. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSDTC;
  1268. }
  1269. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ENT)
  1270. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1271. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSE;
  1272. }
  1273. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE)
  1274. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1275. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSB;
  1276. }
  1277. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_SBSR)
  1278. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) {
  1279. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSBS;
  1280. }
  1281. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_PER)
  1282. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTW) {
  1283. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTWP;
  1284. }
  1285. // special case for powered windows which has enterprise and blade suite!
  1286. if ( (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_BLADE)
  1287. && (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ENT)
  1288. && *CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTSE) {
  1289. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSPOW;
  1290. }
  1291. if (*CurrentInstallSuite & COMPLIANCE_INSTALLSUITE_ANY) {
  1292. *CurrentInstallSuite = *CurrentInstallSuite & (~COMPLIANCE_INSTALLSUITE_NONE);
  1293. }
  1294. exit:
  1295. RegCloseKey(hKey);
  1296. //
  1297. // if we haven't found a product suite at this point, look for Citrix WinFrame,
  1298. // which we'll treat as terminal server
  1299. //
  1300. if (*CurrentInstallSuite == COMPLIANCE_INSTALLSUITE_NONE) {
  1301. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszCitrixKey,&hKey);
  1302. if (rslt != NO_ERROR) {
  1303. return(TRUE);
  1304. }
  1305. BufferSize = sizeof(Buffer);
  1306. rslt = RegQueryValueEx(
  1307. hKey,
  1308. lpszOemKey,
  1309. NULL,
  1310. &Type,
  1311. (LPBYTE) Buffer,
  1312. &BufferSize);
  1313. if (rslt == NO_ERROR && Type == REG_SZ) {
  1314. if (Buffer[0] != TEXT('\0')) {
  1315. BufferSize = sizeof(Buffer);
  1316. rslt = RegQueryValueEx(
  1317. hKey,
  1318. lpszProductVersion,
  1319. NULL,
  1320. &Type,
  1321. (LPBYTE) Buffer,
  1322. &BufferSize);
  1323. if (rslt == NO_ERROR) {
  1324. *CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_HYDRA;
  1325. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
  1326. }
  1327. }
  1328. }
  1329. RegCloseKey(hKey);
  1330. }
  1331. return(retval);
  1332. }
  1333. BOOL
  1334. GetCurrentInstallVariation(
  1335. OUT LPDWORD CurrentInstallVariation,
  1336. IN DWORD CurrentInstallType,
  1337. IN DWORD CurrentInstallBuildNT,
  1338. IN DWORD InstallVersion
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This routine determines what "variation" you have installed (retail,oem, select,etc.)
  1343. Arguments:
  1344. CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
  1345. It looks at the product Id in the registry to determine this, assuming that the
  1346. product ID is a PID2.0 string. To check whether its a EVAL variation or not
  1347. it looks at "PriorityQuantumMatrix" value in registry
  1348. Return Value:
  1349. None.
  1350. --*/
  1351. {
  1352. LPCTSTR lpszPidKeyWin = TEXT("Software\\Microsoft\\Windows\\CurrentVersion");
  1353. LPCTSTR lpszPidKeyWinNT = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
  1354. LPCTSTR lpszProductId = TEXT("ProductId");
  1355. LPCTSTR szEvalKey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Executive");
  1356. LPCTSTR szPQMValue = TEXT("PriorityQuantumMatrix");
  1357. HKEY hKey = NULL;
  1358. long rslt;
  1359. DWORD Type;
  1360. LPTSTR p;
  1361. TCHAR Buffer[MAX_PATH];
  1362. DWORD BufferSize = sizeof(Buffer);
  1363. DWORD i;
  1364. BOOL bResult = FALSE;
  1365. BOOLEAN bDone = FALSE;
  1366. TCHAR Pid20Site[4];
  1367. TCHAR MPCCode[6] = {-1};
  1368. BYTE abPQM[64] = {-1};
  1369. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1370. rslt = RegOpenKey(HKEY_LOCAL_MACHINE,
  1371. ISNT() ? lpszPidKeyWinNT : lpszPidKeyWin,
  1372. &hKey);
  1373. if (rslt != NO_ERROR) {
  1374. goto exit;
  1375. }
  1376. rslt = RegQueryValueEx(hKey, lpszProductId, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
  1377. if (rslt != NO_ERROR || Type!=REG_SZ || (!IsWinPEMode() && (lstrlen(Buffer) < 20))) {
  1378. //
  1379. // nt 3.51 is pid 1.0 instead of pid 2.0. Just assume it's
  1380. // oem variation for now.
  1381. //
  1382. if (((CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTS) ||
  1383. (CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTW) ||
  1384. (CurrentInstallType == COMPLIANCE_INSTALLTYPE_NTSTSE)) &&
  1385. (CurrentInstallBuildNT < 1381 )) {
  1386. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  1387. bResult = TRUE;
  1388. }
  1389. goto exit;
  1390. }
  1391. // get the MPC code from PID
  1392. lstrcpyn(MPCCode, Buffer, 6);
  1393. //
  1394. // some versions of the product ID have hyphens in the registry, some do not
  1395. //
  1396. if (_tcschr(Buffer, TEXT('-'))) {
  1397. lstrcpyn(Pid20Site,&Buffer[6],4);
  1398. Pid20Site[3] = (TCHAR) NULL;
  1399. } else {
  1400. lstrcpyn(Pid20Site,&Buffer[5],4);
  1401. Pid20Site[3] = (TCHAR) NULL;
  1402. }
  1403. // OutputDebugString(Pid20Site);
  1404. // OutputDebugString(TEXT("\r\n"));
  1405. // OutputDebugString(MPCCode);
  1406. if (lstrcmp(Pid20Site, OEM_INSTALL_RPC)== 0) {
  1407. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_OEM;
  1408. } else if (lstrcmp(Pid20Site, SELECT_INSTALL_RPC)== 0) {
  1409. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_SELECT;
  1410. } else if (lstrcmp(Pid20Site, MSDN_INSTALL_RPC)== 0) {
  1411. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_MSDN;
  1412. } else if ((lstrcmp(MPCCode, EVAL_MPC) == 0) || (lstrcmp(MPCCode, DOTNET_EVAL_MPC) == 0)) {
  1413. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  1414. } else if ((lstrcmp(MPCCode, SRV_NFR_MPC) == 0) ||
  1415. (lstrcmp(MPCCode, ASRV_NFR_MPC) == 0) ||
  1416. (lstrcmp(MPCCode, NT4SRV_NFR_MPC) == 0)){
  1417. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_NFR;
  1418. } else {
  1419. //
  1420. // find out if installation is of type EVAL variation (On NT install only)
  1421. // if timebomb is set we assume its EVAL except for DataCenter because
  1422. // there is no EVAL DataCenter SKU.
  1423. //
  1424. if (ISNT() && (CurrentInstallType != COMPLIANCE_INSTALLTYPE_NTSDTC) && (InstallVersion < 500)) {
  1425. HKEY hEvalKey = NULL;
  1426. if (RegOpenKey(HKEY_LOCAL_MACHINE, szEvalKey, &hEvalKey) == ERROR_SUCCESS) {
  1427. DWORD dwSize = sizeof(abPQM);
  1428. if (RegQueryValueEx(hEvalKey, szPQMValue, NULL, &Type, abPQM, &dwSize)
  1429. == ERROR_SUCCESS) {
  1430. // any of bytes 4-7 (inclusive)
  1431. if ((Type == REG_BINARY) && (dwSize >= 8) && (*(ULONG *)(abPQM + 4))) {
  1432. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_EVAL;
  1433. }
  1434. }
  1435. RegCloseKey(hEvalKey);
  1436. }
  1437. }
  1438. // last default assumption (since we could not find var type).
  1439. if (*CurrentInstallVariation == COMPLIANCE_INSTALLVAR_SELECT)
  1440. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  1441. }
  1442. bResult = TRUE;
  1443. exit:
  1444. //
  1445. // If we couldn't find a PID, just treat the current OS as retail
  1446. //
  1447. if (!bResult) {
  1448. *CurrentInstallVariation = COMPLIANCE_INSTALLVAR_CDRETAIL;
  1449. bResult = TRUE;
  1450. }
  1451. if (hKey)
  1452. RegCloseKey(hKey);
  1453. return bResult;
  1454. }
  1455. BOOL
  1456. DetermineCurrentInstallation(
  1457. LPDWORD CurrentInstallType,
  1458. LPDWORD CurrentInstallVariation,
  1459. LPDWORD CurrentInstallVersion,
  1460. LPDWORD CurrentInstallBuildNT,
  1461. LPDWORD CurrentInstallBuildWin9x,
  1462. LPDWORD CurrentInstallSuite,
  1463. LPDWORD CurrentInstallServicePack
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. This routine determines the current installation you have installed, including
  1468. a) current install type (NTW,NTS,Win9x
  1469. b) current install variation (oem,select, retail)
  1470. c) current install version (for NT only!)
  1471. d) current install suite (SBS, ENTERPRISE,etc.)
  1472. Arguments:
  1473. CurrentInstallType - receives a COMPLIANCE_INSTALLTYPE_* flag
  1474. CurrentInstallVariation - receives a COMPLIANCE_INSTALLVAR_* flag
  1475. CurrentInstallVersion - receives a representation of the build (major.minor * 100), ie., 3.51 == 351
  1476. CurrentInstallBuildNT - build number for an nt install
  1477. CurrentInstallBuildWin9 - build number for a win9x install
  1478. CurrentInstallSuite - receives a COMPLIANCE_INSTALLSUITE_* flag
  1479. Return Value:
  1480. TRUE for success, FALSE for failure.
  1481. --*/
  1482. {
  1483. BOOL useExtendedInfo;
  1484. union {
  1485. OSVERSIONINFO Normal;
  1486. OSVERSIONINFOEX Ex;
  1487. } Ovi;
  1488. #ifdef DBG
  1489. TCHAR dbg[1000];
  1490. #endif
  1491. if (!CurrentInstallType || !CurrentInstallVariation || !CurrentInstallVersion || !CurrentInstallSuite) {
  1492. SetLastError( ERROR_INVALID_PARAMETER );
  1493. return(FALSE);
  1494. }
  1495. useExtendedInfo = TRUE;
  1496. Ovi.Ex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1497. if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Ex) ) {
  1498. //
  1499. // EX size not available; try the normal one
  1500. //
  1501. Ovi.Normal.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1502. if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Normal) ) {
  1503. assert(FALSE);
  1504. return(FALSE);
  1505. }
  1506. useExtendedInfo = FALSE;
  1507. }
  1508. switch (Ovi.Normal.dwPlatformId) {
  1509. case VER_PLATFORM_WIN32s:
  1510. #ifdef DBG
  1511. OutputDebugString(TEXT("Win32s current installation!!!"));
  1512. #endif
  1513. //assert(FALSE);
  1514. return(FALSE);
  1515. break;
  1516. case VER_PLATFORM_WIN32_WINDOWS:
  1517. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_WIN9X;
  1518. *CurrentInstallSuite = COMPLIANCE_INSTALLSUITE_NONE;
  1519. *CurrentInstallBuildNT = 0;
  1520. *CurrentInstallBuildWin9x = Ovi.Normal.dwBuildNumber;
  1521. #ifdef DBG
  1522. wsprintf(dbg, TEXT("%d\n"), *CurrentInstallBuildWin9x);
  1523. OutputDebugString(dbg);
  1524. #endif
  1525. //
  1526. // Need to know what version of windows is installed so we can block upgrade
  1527. // from win95.
  1528. //
  1529. *CurrentInstallVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion;
  1530. if (useExtendedInfo) {
  1531. *CurrentInstallServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor;
  1532. } else {
  1533. *CurrentInstallServicePack = 0;
  1534. }
  1535. break;
  1536. case VER_PLATFORM_WIN32_NT:
  1537. if (!GetCurrentNtVersion(
  1538. CurrentInstallType,
  1539. CurrentInstallSuite)) {
  1540. return(FALSE);
  1541. }
  1542. *CurrentInstallVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion;
  1543. if (useExtendedInfo) {
  1544. *CurrentInstallServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor;
  1545. } else {
  1546. *CurrentInstallServicePack = 0;
  1547. }
  1548. *CurrentInstallBuildWin9x = 0;
  1549. *CurrentInstallBuildNT = Ovi.Normal.dwBuildNumber;
  1550. if (*CurrentInstallBuildNT <= 1381
  1551. && *CurrentInstallSuite == COMPLIANCE_INSTALLSUITE_HYDRA) {
  1552. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_NTSTSE;
  1553. }
  1554. break;
  1555. default:
  1556. #ifdef DBG
  1557. OutputDebugString(TEXT("unknown installation!!!"));
  1558. #endif
  1559. assert(FALSE);
  1560. return(FALSE);
  1561. }
  1562. if (!GetCurrentInstallVariation(CurrentInstallVariation,*CurrentInstallType,*CurrentInstallBuildNT, *CurrentInstallVersion)) {
  1563. #ifdef DBG
  1564. OutputDebugString(TEXT("GetCurrentInstallVariation failed\n"));
  1565. #endif
  1566. //assert(FALSE);
  1567. return(FALSE);
  1568. }
  1569. return(TRUE);
  1570. }
  1571. BOOL
  1572. IsCompliant(
  1573. PBOOL UpgradeOnly,
  1574. PBOOL NoUpgradeAllowed,
  1575. PUINT SrcSku,
  1576. PUINT CurrentInstallType,
  1577. PUINT CurrentInstallVersion,
  1578. PUINT Reason
  1579. )
  1580. /*++
  1581. Routine Description:
  1582. This routines determines if your current installation is compliant (if you are allowed to proceed with your installation).
  1583. To do this, it retreives your current installation and determines the sku for your source installation.
  1584. It then compares the target against the source to determine if the source sku allows an upgrade/clean install
  1585. from your target installation.
  1586. Arguments:
  1587. UpgradeOnly - This flag gets set to TRUE if the current SKU only allows upgrades. This
  1588. lets winnt32 know that it should not allow a clean install from the current
  1589. media. This get's set correctly regardless of the compliance check passing
  1590. SrcSku - COMPLIANCE_SKU flag indicating source sku (for error msg's)
  1591. Reason - COMPLIANCEERR flag indicating why compliance check failed.
  1592. Return Value:
  1593. TRUE if the install is compliant, FALSE if it isn't allowed
  1594. --*/
  1595. {
  1596. DWORD SourceSku;
  1597. DWORD SourceSkuVariation;
  1598. DWORD SourceVersion;
  1599. DWORD SourceBuildNum;
  1600. TCHAR DosnetPath[MAX_PATH] = {0};
  1601. COMPLIANCE_DATA TargetData;
  1602. ZeroMemory(&TargetData, sizeof(TargetData) );
  1603. *UpgradeOnly = FALSE;
  1604. *NoUpgradeAllowed = TRUE;
  1605. *Reason = COMPLIANCEERR_UNKNOWN;
  1606. *SrcSku = COMPLIANCE_SKU_NONE;
  1607. *CurrentInstallType = COMPLIANCE_INSTALLTYPE_UNKNOWN;
  1608. *CurrentInstallVersion = 0;
  1609. if (!DetermineCurrentInstallation(&TargetData.InstallType,
  1610. &TargetData.InstallVariation,
  1611. &TargetData.MinimumVersion,
  1612. &TargetData.BuildNumberNt,
  1613. &TargetData.BuildNumberWin9x,
  1614. &TargetData.InstallSuite,
  1615. &TargetData.InstallServicePack)) {
  1616. #ifdef DBG
  1617. OutputDebugString(TEXT("Error determining current installation"));
  1618. #endif
  1619. *Reason = COMPLIANCEERR_UNKNOWNTARGET;
  1620. return(FALSE);
  1621. }
  1622. *CurrentInstallType = TargetData.InstallType;
  1623. if (TargetData.InstallType & COMPLIANCE_INSTALLTYPE_WIN9X) {
  1624. *CurrentInstallVersion = TargetData.BuildNumberWin9x;
  1625. } else {
  1626. *CurrentInstallVersion = TargetData.BuildNumberNt;
  1627. }
  1628. if ((SourceSku = DetermineSourceProduct(&SourceSkuVariation,&TargetData)) == COMPLIANCE_SKU_NONE) {
  1629. #ifdef DBG
  1630. OutputDebugString(TEXT("couldn't determine source sku!"));
  1631. #endif
  1632. *Reason = COMPLIANCEERR_UNKNOWNSOURCE;
  1633. return(FALSE);
  1634. }
  1635. wsprintf(DosnetPath, TEXT("%s\\dosnet.inf"), NativeSourcePaths[0]);
  1636. if (!DetermineSourceVersionInfo(DosnetPath, &SourceVersion, &SourceBuildNum)) {
  1637. *Reason = COMPLIANCEERR_UNKNOWNSOURCE;
  1638. return(FALSE);
  1639. }
  1640. switch (SourceSku) {
  1641. case COMPLIANCE_SKU_NTW32U:
  1642. //case COMPLIANCE_SKU_NTWU:
  1643. //case COMPLIANCE_SKU_NTSEU:
  1644. case COMPLIANCE_SKU_NTSU:
  1645. case COMPLIANCE_SKU_NTSEU:
  1646. case COMPLIANCE_SKU_NTWPU:
  1647. case COMPLIANCE_SKU_NTSBU:
  1648. case COMPLIANCE_SKU_NTSBSU:
  1649. *UpgradeOnly = TRUE;
  1650. break;
  1651. default:
  1652. *UpgradeOnly = FALSE;
  1653. }
  1654. *SrcSku = SourceSku;
  1655. if( ISNT() && TargetData.MinimumVersion == 400 && TargetData.InstallServicePack < 500) {
  1656. *Reason = COMPLIANCEERR_SERVICEPACK5;
  1657. *NoUpgradeAllowed = TRUE;
  1658. return(FALSE);
  1659. }
  1660. return CheckCompliance(SourceSku, SourceSkuVariation, SourceVersion,
  1661. SourceBuildNum, &TargetData, Reason, NoUpgradeAllowed);
  1662. }
  1663. BOOL
  1664. IsWinPEMode(
  1665. VOID
  1666. )
  1667. /*++
  1668. Routine Description:
  1669. Finds out if we are running under WinPE environment.
  1670. Arguments:
  1671. None
  1672. Return value:
  1673. TRUE or FALSE
  1674. --*/
  1675. {
  1676. static BOOL Initialized = FALSE;
  1677. static BOOL WinPEMode = FALSE;
  1678. if (!Initialized) {
  1679. TCHAR *MiniNTKeyName = TEXT("SYSTEM\\CurrentControlSet\\Control\\MiniNT");
  1680. HKEY MiniNTKey = NULL;
  1681. LONG RegResult;
  1682. RegResult = RegOpenKey(HKEY_LOCAL_MACHINE,
  1683. MiniNTKeyName,
  1684. &MiniNTKey);
  1685. if (RegResult == ERROR_SUCCESS) {
  1686. WinPEMode = TRUE;
  1687. RegCloseKey(MiniNTKey);
  1688. }
  1689. Initialized = TRUE;
  1690. }
  1691. return WinPEMode;
  1692. }
  1693. #endif