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.

3574 lines
105 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. cmdline.c
  5. Abstract:
  6. Routines to fetch parameters passed to us by text mode
  7. and deal with uniquness criteria.
  8. Author:
  9. Stephane Plante (t-stepl) 16-Oct-1995
  10. Revision History:
  11. 06-Mar-1996 (tedm) massive cleanup, and uniqueness stuff
  12. --*/
  13. #include "setupp.h"
  14. #pragma hdrstop
  15. #ifdef UNICODE
  16. #define _UNICODE
  17. #endif
  18. #include <tchar.h>
  19. #include "hwlog.h"
  20. //
  21. // These get filled in when we call SetUpProcessorNaming().
  22. // They are used for legacy purposes.
  23. //
  24. // PlatformName - a name that indicates the processor platform type;
  25. // one of AMD64, I386, or ia64
  26. //
  27. // ProcessorName - a description of the type of processor. This varies
  28. // depending on PlatformName.
  29. //
  30. // PrinterPlatform - name of platform-specific part of subdirectory
  31. // used in printing architecture. One of w32amd64,
  32. // w32x86, or w32ia64.
  33. //
  34. PCWSTR PlatformName = L"";
  35. PCWSTR ProcessorName = L"";
  36. PCWSTR PrinterPlatform = L"";
  37. GUID DriverVerifyGuid = DRIVER_ACTION_VERIFY;
  38. //
  39. // Source path used for legacy operations. This is the regular
  40. // source path with a platform-specific piece appended to it.
  41. // This is how legacy infs expect it.
  42. //
  43. WCHAR LegacySourcePath[MAX_PATH];
  44. //
  45. // Policy values (ignore, warn, or block) for driver and non-driver signing.
  46. // These are the policy values that are in effect post-setup (i.e., they are
  47. // applied when setup is finished by calling InitializeCodeSigningPolicies with
  48. // FALSE).
  49. //
  50. BYTE DrvSignPolicy;
  51. BYTE NonDrvSignPolicy;
  52. //
  53. // Flags indicating whether the driver and non-driver signing policies came
  54. // from the answerfile. (If so, then those values are in effect after GUI-mode
  55. // setup as well, thus DrvSignPolicy and NonDrvSignPolicy values are ignored.)
  56. //
  57. BOOL AFDrvSignPolicySpecified = FALSE;
  58. BOOL AFNonDrvSignPolicySpecified = FALSE;
  59. //
  60. // Flag indicating if we're installing from a CD.
  61. //
  62. BOOL gInstallingFromCD = FALSE;
  63. //
  64. // Cryptographically secure codesigning policies
  65. //
  66. DWORD PnpSeed = 0;
  67. //
  68. // Define maximum parameter (from answer file) length
  69. //
  70. #define MAX_PARAM_LEN 256
  71. #define FILEUTIL_HORRIBLE_PATHNAME (_T("system32\\CatRoot\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\\"))
  72. BOOL
  73. SpSetupProcessSourcePath(
  74. IN PCWSTR NtPath,
  75. OUT PWSTR *DosPath
  76. );
  77. NTSTATUS
  78. SpSetupLocateSourceCdRom(
  79. OUT PWSTR NtPath
  80. );
  81. VOID
  82. SetUpProcessorNaming(
  83. VOID
  84. );
  85. BOOL
  86. IntegrateUniquenessInfo(
  87. IN PCWSTR DatabaseFile,
  88. IN PCWSTR UniqueId
  89. );
  90. BOOL
  91. ProcessOneUniquenessSection(
  92. IN HINF Database,
  93. IN PCWSTR SectionName,
  94. IN PCWSTR UniqueId
  95. );
  96. DWORD
  97. InstallProductCatalogs(
  98. OUT SetupapiVerifyProblem *Problem,
  99. OUT LPWSTR ProblemFile,
  100. IN LPCWSTR DescriptionForError OPTIONAL
  101. );
  102. DWORD
  103. DeleteOldCatalogs(
  104. VOID
  105. );
  106. VOID
  107. InstallPrivateFiles(
  108. IN HWND Billboard
  109. );
  110. DWORD
  111. PrepDllCache(
  112. VOID
  113. );
  114. VOID
  115. SpUninstallExcepPackCatalogs(
  116. IN HCATADMIN CatAdminHandle OPTIONAL
  117. );
  118. BOOL
  119. SpSetupLoadParameter(
  120. IN PCWSTR Param,
  121. OUT PWSTR Answer,
  122. IN UINT AnswerBufLen
  123. )
  124. /*++
  125. Routine Description:
  126. Load a single parameter out of the [Data] section of the
  127. setup parameters file. If the datum is not found there then
  128. look in the [SetupParams] and [Unattended] sections also.
  129. Arguments:
  130. Param - supplies name of parameter, which is passed to the profile APIs.
  131. Answer - receives the value of the parameter, if successful.
  132. AnswerBufLen - supplies the size in characters of the buffer
  133. pointed to by Answer.
  134. Return Value:
  135. Boolean value indicating success or failure.
  136. --*/
  137. {
  138. if(!AnswerFile[0]) {
  139. //
  140. // We haven't calculated the path to $winnt$.inf yet
  141. //
  142. GetSystemDirectory(AnswerFile,MAX_PATH);
  143. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  144. if(!FileExists(AnswerFile,NULL)) {
  145. //
  146. // Don't log this error message in mini-setup. Mini-setup may delete
  147. // the answer file and later, if someone asks for it, and it is not found
  148. // we don't want to log this as a failure. OOBE pretends to be mini-setup
  149. // so make sure that we log this error if we're running in OOBE and
  150. // we're missing the answer file.
  151. //
  152. if (!MiniSetup || OobeSetup) {
  153. SetuplogError(
  154. LogSevError,
  155. SETUPLOG_USE_MESSAGEID,
  156. MSG_LOG_SYSINFBAD,
  157. AnswerFile,
  158. NULL,NULL);
  159. }
  160. return FALSE;
  161. }
  162. }
  163. if(!GetPrivateProfileString(pwData,Param,pwNull,Answer,AnswerBufLen,AnswerFile)) {
  164. //
  165. // If answer isn't in the DATA section then it could
  166. // conceivably be in the SETUPPARAMS section as a user
  167. // specified (command line) option
  168. //
  169. if(!GetPrivateProfileString(pwSetupParams,Param,pwNull,Answer,AnswerBufLen,AnswerFile)) {
  170. //
  171. // Now check the UNATTENDED section.
  172. //
  173. if(!GetPrivateProfileString(pwUnattended,Param,pwNull,Answer,AnswerBufLen,AnswerFile)) {
  174. //
  175. // Now check the ACCESSIBILITY section.
  176. //
  177. if(!GetPrivateProfileString(pwAccessibility,Param,pwNull,Answer,AnswerBufLen,AnswerFile)) {
  178. //
  179. // We haven't found the answer here so it probably doesn't exist.
  180. // This is an error situation so notify our caller of that.
  181. //
  182. SetupDebugPrint1(L"SETUP: SpSetupLoadParameter was unable to find %ws.", Param);
  183. return(FALSE);
  184. }
  185. }
  186. }
  187. }
  188. //
  189. // Success.
  190. //
  191. return(TRUE);
  192. }
  193. BOOL
  194. SpSetProductTypeFromParameters(
  195. VOID
  196. )
  197. /*++
  198. Routine Description:
  199. Reads the Product Type from the parameters files and sets up
  200. the ProductType global variable.
  201. Arguments:
  202. None
  203. Returns:
  204. Boolean value indicating outcome.
  205. --*/
  206. {
  207. WCHAR p[MAX_PARAM_LEN];
  208. //
  209. // Determine the product type. If we can't resolve this
  210. // then the installation is in a lot of trouble
  211. //
  212. if( !MiniSetup ) {
  213. if( !SpSetupLoadParameter(pwProduct,p,sizeof(p)/sizeof(p[0]))) {
  214. return( FALSE );
  215. }
  216. } else {
  217. DWORD rc, d, Type;
  218. HKEY hKey;
  219. //
  220. // If we're doing a minisetup then we need to go pull the
  221. // product string out of the registry.
  222. //
  223. //
  224. // Open the key.
  225. //
  226. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  227. L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
  228. 0,
  229. KEY_READ,
  230. &hKey );
  231. if( rc != NO_ERROR ) {
  232. SetLastError( rc );
  233. SetupDebugPrint1( L"Setup: Failed to open ProductOptions key (gle %u) \n", rc );
  234. return( FALSE );
  235. }
  236. //
  237. // Get the size of the ProductType entry.
  238. //
  239. rc = RegQueryValueEx( hKey,
  240. L"ProductType",
  241. NULL,
  242. &Type,
  243. NULL,
  244. &d );
  245. if( rc != NO_ERROR ) {
  246. SetLastError( rc );
  247. SetupDebugPrint1( L"Setup: Failed to query size of ProductType key (gle %u) \n", rc );
  248. return( FALSE );
  249. }
  250. //
  251. // Get the ProductType entry.
  252. //
  253. rc = RegQueryValueEx( hKey,
  254. L"ProductType",
  255. NULL,
  256. &Type,
  257. (LPBYTE)p,
  258. &d );
  259. if( rc != NO_ERROR ) {
  260. SetLastError( rc );
  261. SetupDebugPrint1( L"Setup: Failed to query ProductType key (gle %u) \n", rc );
  262. return( FALSE );
  263. }
  264. }
  265. //
  266. // We managed to find an entry in the parameters file
  267. // so we *should* be able to decode it
  268. //
  269. if(!lstrcmpi(p,pwWinNt)) {
  270. //
  271. // We have a WINNT product
  272. //
  273. ProductType = PRODUCT_WORKSTATION;
  274. } else if(!lstrcmpi(p,pwLanmanNt)) {
  275. //
  276. // We have a PRIMARY SERVER product
  277. //
  278. ProductType = PRODUCT_SERVER_PRIMARY;
  279. } else if(!lstrcmpi(p,pwServerNt)) {
  280. //
  281. // We have a STANDALONE SERVER product
  282. // NOTE: this case can currently never occur, since text mode
  283. // always sets WINNT_D_PRODUCT to lanmannt or winnt.
  284. //
  285. ProductType = PRODUCT_SERVER_STANDALONE;
  286. } else {
  287. //
  288. // We can't determine what we are, so fail
  289. //
  290. return (FALSE);
  291. }
  292. return (TRUE);
  293. }
  294. BOOL
  295. SpSetUnattendModeFromParameters(
  296. VOID
  297. )
  298. /*++
  299. Routine Description:
  300. Reads the Unattended Mode from the parameters files and sets up
  301. the UnattendMode global variable.
  302. Arguments:
  303. None
  304. Returns:
  305. Boolean value indicating outcome.
  306. --*/
  307. {
  308. WCHAR p[MAX_PARAM_LEN];
  309. //
  310. // If we're not running unattended, don't bother to look up the mode.
  311. //
  312. if(!Unattended) {
  313. UnattendMode = UAM_GUIATTENDED;
  314. TextmodeEula = TRUE;
  315. return TRUE;
  316. }
  317. if (SpSetupLoadParameter(pwWaitForReboot, p, sizeof(p)/sizeof(p[0]))) {
  318. if (!lstrcmpi(p, pwYes)) {
  319. UnattendWaitForReboot = TRUE;
  320. }
  321. }
  322. if(SpSetupLoadParameter(pwUnattendMode,p,sizeof(p)/sizeof(p[0]))) {
  323. //
  324. // We managed to find an entry in the parameters file
  325. // so we *should* be able to decode it
  326. //
  327. if(!lstrcmpi(p,pwGuiAttended)) {
  328. //
  329. // GUI mode will be fully attended.
  330. //
  331. UnattendMode = UAM_GUIATTENDED;
  332. Unattended = FALSE;
  333. } else if(!lstrcmpi(p,pwProvideDefault)) {
  334. //
  335. // Answers are defaults and can be changed.
  336. //
  337. UnattendMode = UAM_PROVIDEDEFAULT;
  338. } else if(!lstrcmpi(p,pwDefaultHide)) {
  339. //
  340. // Answers are defaults, but a page with all answers supplied is
  341. // not shown.
  342. //
  343. UnattendMode = UAM_DEFAULTHIDE;
  344. } else if(!lstrcmpi(p,pwReadOnly)) {
  345. //
  346. // All supplied answers are read-only. If a page has all its
  347. // answers supplied, then it is not shown.
  348. //
  349. UnattendMode = UAM_READONLY;
  350. } else if(!lstrcmpi(p,pwFullUnattended)) {
  351. //
  352. // Setup is fully unattended. If we have to ask the user for an
  353. // answer, we put up an error dialog.
  354. //
  355. UnattendMode = UAM_FULLUNATTENDED;
  356. } else {
  357. //
  358. // We can't determine what we are, so use a default
  359. //
  360. UnattendMode = UAM_DEFAULTHIDE;
  361. SetupDebugPrint1(
  362. L"SETUP: SpSetUnattendModeFromParameters did not recognize %ls",
  363. p
  364. );
  365. }
  366. } else {
  367. //
  368. // Use default mode since none was specified.
  369. //
  370. UnattendMode = UAM_DEFAULTHIDE;
  371. }
  372. return TRUE;
  373. }
  374. BOOL
  375. SpSetupProcessParameters(
  376. IN OUT HWND *Billboard
  377. )
  378. /*++
  379. Routine Description:
  380. Reads in parameters passed in from TextMode Setup
  381. Arguments:
  382. Billboard - on input supplies window handle of "Setup is Initializing"
  383. billboard. On ouput receives new window handle if we had to
  384. display our own ui (in which case we would have killed and then
  385. redisplayed the billboard).
  386. Returns:
  387. Boolean value indicating outcome.
  388. --*/
  389. {
  390. BOOL b = TRUE;
  391. PWSTR q;
  392. WCHAR p[MAX_PARAM_LEN];
  393. WCHAR Num[24];
  394. UINT Type;
  395. WCHAR c;
  396. WCHAR TitleStringBuffer[1024];
  397. DWORD Err;
  398. SetupapiVerifyProblem Problem;
  399. WCHAR ProblemFile[MAX_PATH];
  400. INITCOMMONCONTROLSEX ControlInit;
  401. if(!SpSetProductTypeFromParameters()) {
  402. return(FALSE);
  403. }
  404. //
  405. // Is winnt/winnt32-based?
  406. //
  407. if((b = SpSetupLoadParameter(pwMsDos,p,MAX_PARAM_LEN))
  408. && (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne))) {
  409. WinntBased = TRUE;
  410. #ifdef _X86_
  411. //
  412. // Get Floppyless boot path, which is given if
  413. // pwBootPath is not set to NO
  414. //
  415. FloppylessBootPath[0] = 0;
  416. if((b = SpSetupLoadParameter(pwBootPath,p,MAX_PARAM_LEN)) && lstrcmpi(p,pwNo)) {
  417. if(q = NtFullPathToDosPath(p)) {
  418. lstrcpyn(
  419. FloppylessBootPath,
  420. q,
  421. sizeof(FloppylessBootPath)/sizeof(FloppylessBootPath[0])
  422. );
  423. MyFree(q);
  424. }
  425. }
  426. #endif
  427. } else {
  428. WinntBased = FALSE;
  429. }
  430. //
  431. // Win3.1 or Win95 upgrade?
  432. //
  433. Win31Upgrade = (b && (b = SpSetupLoadParameter(pwWin31Upgrade,p,MAX_PARAM_LEN)) && !lstrcmpi(p,pwYes));
  434. Win95Upgrade = (b && (b = SpSetupLoadParameter(pwWin95Upgrade,p,MAX_PARAM_LEN)) && !lstrcmpi(p,pwYes));
  435. //
  436. // NT Upgrade?
  437. //
  438. Upgrade = (b && (b = SpSetupLoadParameter(pwNtUpgrade,p,MAX_PARAM_LEN)) && !lstrcmpi(p,pwYes));
  439. SetEnvironmentVariable( L"Upgrade", Upgrade ? L"True" : L"False" );
  440. //
  441. // If this is a an upgrade of or to a standalone server,
  442. // change the product type to standalone server.
  443. //
  444. // If this is not an upgrade and the product type is lanmannt,
  445. // change to standalone server. This makes the default server type
  446. // non-dc.
  447. //
  448. if(b && ((!Upgrade && (ProductType != PRODUCT_WORKSTATION)) || ((b = SpSetupLoadParameter(pwServerUpgrade,p,MAX_PARAM_LEN)) && !lstrcmpi(p,pwYes)))) {
  449. MYASSERT(ISDC(ProductType));
  450. ProductType = PRODUCT_SERVER_STANDALONE;
  451. }
  452. if( ProductType == PRODUCT_WORKSTATION) {
  453. if( GetProductFlavor() == 4) {
  454. SetupTitleStringId = Upgrade ? IDS_TITLE_UPGRADE_P : IDS_TITLE_INSTALL_P;
  455. }
  456. else {
  457. SetupTitleStringId = Upgrade ? IDS_TITLE_UPGRADE_W : IDS_TITLE_INSTALL_W;
  458. }
  459. }
  460. else
  461. {
  462. SetupTitleStringId = Upgrade ? IDS_TITLE_UPGRADE_S : IDS_TITLE_INSTALL_S;
  463. }
  464. //
  465. // Fetch the source directory and convert it to DOS-style path
  466. //
  467. if(b && (b = SpSetupLoadParameter(pwSrcDir,p,MAX_PARAM_LEN))) {
  468. //
  469. // Remember that setupdll.dll does all sorts of checking on the
  470. // source path. We need todo the same checks here. Note that
  471. // we will *write* back the checked path into $winnt$.inf as a
  472. // logical step to take
  473. //
  474. if(SpSetupProcessSourcePath(p,&q)) {
  475. lstrcpyn(SourcePath,q,sizeof(SourcePath)/sizeof(SourcePath[0]));
  476. MyFree(q);
  477. //
  478. // Attempt to write the path to the parameters file.
  479. // This changes it from an nt-style path to a dos-style path there.
  480. //
  481. b = WritePrivateProfileString(pwData,pwDosDir,SourcePath,AnswerFile);
  482. if(!b) {
  483. SetupDebugPrint( L"SETUP: WritePrivateProfileString failed in SpSetupProcessParameters." );
  484. }
  485. } else {
  486. b = FALSE;
  487. SetupDebugPrint( L"SETUP: SpSetupProcessSourcePath failed in SpSetupProcessParameters." );
  488. }
  489. //
  490. // Set up globals for platform-specific info
  491. //
  492. SetUpProcessorNaming();
  493. //
  494. // Construct legacy source path.
  495. //
  496. if(b) {
  497. lstrcpyn(LegacySourcePath,SourcePath,MAX_PATH);
  498. pSetupConcatenatePaths(LegacySourcePath,PlatformName,MAX_PATH,NULL);
  499. }
  500. }
  501. //
  502. // Unattended Mode?
  503. //
  504. Unattended = (b &&
  505. (b = SpSetupLoadParameter(pwInstall,p,MAX_PARAM_LEN)) &&
  506. !lstrcmpi(p,pwYes));
  507. if(b) {
  508. if( !(b = SpSetUnattendModeFromParameters()) ) {
  509. SetupDebugPrint( L"SETUP: SpSetUnattendModeFromParameters failed in SpSetupProcessParameters." );
  510. }
  511. }
  512. SetupDebugPrint1(L"SETUP: Upgrade=%d.", Upgrade);
  513. SetupDebugPrint1(L"SETUP: Unattended=%d.", Unattended);
  514. //
  515. // We can get into unattended mode in several ways, so we also check whether
  516. // the "/unattend" switch was explicitly specified.
  517. //
  518. UnattendSwitch = (b &&
  519. SpSetupLoadParameter(pwUnattendSwitch,p,MAX_PARAM_LEN) &&
  520. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne)));
  521. //
  522. // Should we force OOBE to run?
  523. //
  524. ForceRunOobe = (b &&
  525. SpSetupLoadParameter(pwRunOobe,p,MAX_PARAM_LEN) &&
  526. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne)));
  527. //
  528. // Flag indicating whether we are in a special mode for OEM's to use on the
  529. // factory floor.
  530. //
  531. ReferenceMachine = (b &&
  532. SpSetupLoadParameter(pwReferenceMachine,p,MAX_PARAM_LEN) &&
  533. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne)));
  534. //
  535. // Eula already displayed?
  536. //
  537. if(b && SpSetupLoadParameter(pwEulaDone,p,MAX_PARAM_LEN) &&
  538. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne))) {
  539. EulaComplete = TRUE;
  540. } else {
  541. EulaComplete = FALSE;
  542. }
  543. //
  544. // Do uniqueness stuff now. We do this here so we don't have to
  545. // reinitialize anything. All the stuff above is not subject to change
  546. // via uniquenss.
  547. //
  548. InitializeUniqueness(Billboard);
  549. //
  550. // Initialize unattended operation now.
  551. //
  552. UnattendInitialize();
  553. //
  554. // Setup shell special folders (e.g., "Program Files", etc.) in registry
  555. // prior to loading any INFs with setupapi. That's because it's possible
  556. // that an INF can have DIRIDs that refer to these special directories.
  557. // (In addition to setupapi's potential need for this, OCM definitely needs
  558. // it.)
  559. //
  560. if(b) {
  561. if( !(b = SetProgramFilesDirInRegistry()) ) {
  562. SetupDebugPrint( L"SETUP: SetProgramFilesDirInRegistry failed in SpSetupProcessParameters." );
  563. }
  564. }
  565. //
  566. // Also, let setupapi know where the source path is...
  567. //
  568. // note that the servicepack sourcepath is the same as the system source
  569. // path in this case since we can only be dealing with a slipstreamed
  570. // build in this case
  571. //
  572. if(b) {
  573. if( !(b = pSetupSetSystemSourcePath( SourcePath, SourcePath )) ) {
  574. SetupDebugPrint( L"SETUP: pSetupSetSystemSourcePath failed in SpSetupProcessParameters." );
  575. }
  576. }
  577. if(b && SpSetupLoadParameter(pwIncludeCatalog,p,MAX_PARAM_LEN) && *p) {
  578. IncludeCatalog = pSetupDuplicateString(p);
  579. if(!IncludeCatalog) {
  580. b = FALSE;
  581. SetupDebugPrint( L"SETUP: IncludeCatalog failed in SpSetupProcessParameters." );
  582. }
  583. }
  584. if(b) {
  585. //
  586. // Load the system setup (win95-style!) infs.
  587. //
  588. SyssetupInf = SetupOpenInfFile(L"syssetup.inf",NULL,INF_STYLE_WIN4,NULL);
  589. if(SyssetupInf == INVALID_HANDLE_VALUE) {
  590. KillBillboard(*Billboard);
  591. FatalError(MSG_LOG_SYSINFBAD,L"syssetup.inf",0,0);
  592. }
  593. //
  594. // syssetup.inf opened successfully, now append-load any layout INFs
  595. // it references.
  596. //
  597. if(!SetupOpenAppendInfFile(NULL,SyssetupInf,NULL)) {
  598. KillBillboard(*Billboard);
  599. FatalError(MSG_LOG_SYSINFBAD,L"(syssetup.inf layout)",0,0);
  600. }
  601. //
  602. // write some information about the hardware configuration to setupact.log
  603. //
  604. //
  605. if( !OobeSetup ) {
  606. SP_LOG_HARDWARE_IN LogHardwareIn = { 0 };
  607. LogHardwareIn.SetuplogError = SetuplogError;
  608. SpLogHardware(&LogHardwareIn);
  609. }
  610. if (!MiniSetup && !OobeSetup) {
  611. DuInitialize ();
  612. }
  613. //
  614. // install side by side assemblies (fusion)
  615. //
  616. if( !OobeSetup ) {
  617. SIDE_BY_SIDE SideBySide = {0};
  618. BOOL b1 = FALSE;
  619. BOOL b2 = FALSE;
  620. BOOL b3 = FALSE;
  621. b1 = SideBySidePopulateCopyQueue(&SideBySide, NULL, NULL);
  622. b2 = SideBySideFinish(&SideBySide, b1);
  623. if (!b1 || !b2) {
  624. WCHAR szErrorBuffer[128];
  625. DWORD dwLastError = GetLastError();
  626. szErrorBuffer[0] = 0;
  627. if (FormatMessageW(
  628. FORMAT_MESSAGE_FROM_SYSTEM,
  629. NULL,
  630. dwLastError,
  631. 0,
  632. szErrorBuffer,
  633. RTL_NUMBER_OF(szErrorBuffer),
  634. NULL) == 0) {
  635. _snwprintf(szErrorBuffer, RTL_NUMBER_OF(szErrorBuffer), L"Untranslatable message, Win32LastError is %lu\r\n", dwLastError);
  636. szErrorBuffer[RTL_NUMBER_OF(szErrorBuffer) - 1] = 0;
  637. }
  638. if ((dwLastError == ERROR_CRC) || (dwLastError == ERROR_SWAPERROR))
  639. {
  640. // for CD media error
  641. FatalError(MSG_LOG_SIDE_BY_SIDE_IO_ERROR, szErrorBuffer, 0, 0);
  642. }else
  643. {
  644. FatalError(MSG_LOG_SIDE_BY_SIDE, szErrorBuffer, 0, 0);
  645. }
  646. }
  647. //
  648. // install additional assemblies downloaded from WU
  649. // ignore any errors; logging occurs inside the called function
  650. //
  651. // Meta-issue: Perhaps this should use the SideBySide context
  652. // created above, rather than generating its own thing?
  653. // That would allow even more "goodness" by piggybacking on the
  654. // existing structures, reduce memory usage by not creating
  655. // another context, and then chain all the copy calls (if/when
  656. // SxS uses the real copy queue functionality) into a single
  657. // SideBySideFinish.
  658. //
  659. if (!MiniSetup && !OobeSetup) {
  660. DuInstallDuAsms ();
  661. }
  662. //
  663. // Everyone done and happy? Good, now go and create the default
  664. // context based on whatever DU and the original media installed.
  665. //
  666. b3 = SideBySideCreateSyssetupContext();
  667. if ( !b3 ) {
  668. WCHAR szErrorBuffer[128];
  669. DWORD dwLastError = GetLastError();
  670. szErrorBuffer[0] = 0;
  671. if (FormatMessageW(
  672. FORMAT_MESSAGE_FROM_SYSTEM,
  673. NULL,
  674. dwLastError,
  675. 0,
  676. szErrorBuffer,
  677. RTL_NUMBER_OF(szErrorBuffer),
  678. NULL) == 0) {
  679. _snwprintf(szErrorBuffer, RTL_NUMBER_OF(szErrorBuffer), L"Untranslatable message, Win32LastError is %lu\r\n", dwLastError);
  680. szErrorBuffer[RTL_NUMBER_OF(szErrorBuffer) - 1] = 0;
  681. }
  682. if ((dwLastError == ERROR_CRC) || (dwLastError == ERROR_SWAPERROR))
  683. {
  684. // for CD media error
  685. FatalError(MSG_LOG_SIDE_BY_SIDE_IO_ERROR, szErrorBuffer, 0, 0);
  686. }else
  687. {
  688. FatalError(MSG_LOG_SIDE_BY_SIDE, szErrorBuffer, 0, 0);
  689. }
  690. }
  691. }
  692. //
  693. // We must not use comctl32.dll until after SideBySide install completes.
  694. // It is delayloaded, using the linker feature.
  695. //
  696. // But, actually, it get's loaded by winntbb before us, and that is ok, it
  697. // still gets redirected for uses from syssetup.dll, oc manager, etc.
  698. //
  699. //ASSERT(GetModuleHandleW(L"comctl32.dll") == NULL);
  700. ControlInit.dwSize = sizeof(INITCOMMONCONTROLSEX);
  701. ControlInit.dwICC = ICC_LISTVIEW_CLASSES |
  702. ICC_TREEVIEW_CLASSES |
  703. ICC_BAR_CLASSES |
  704. ICC_TAB_CLASSES |
  705. ICC_UPDOWN_CLASS |
  706. ICC_PROGRESS_CLASS |
  707. ICC_HOTKEY_CLASS |
  708. ICC_ANIMATE_CLASS |
  709. ICC_WIN95_CLASSES |
  710. ICC_DATE_CLASSES |
  711. ICC_USEREX_CLASSES |
  712. ICC_COOL_CLASSES
  713. #if (_WIN32_IE >= 0x0400)
  714. |
  715. ICC_INTERNET_CLASSES |
  716. ICC_PAGESCROLLER_CLASS
  717. #endif
  718. ;
  719. InitCommonControlsEx( &ControlInit );
  720. //
  721. // We're about to go off and install the catalogs that will be used for
  722. // digital signature verification of the product files. First, however,
  723. // we need to make sure all the CAPI stuff is setup. (Errors here are
  724. // not considered fatal.)
  725. //
  726. if(!InstallOrUpgradeCapi()) {
  727. SetupDebugPrint(L"Setup: (non-critical error) Failed call InstallOrUpgradeCapi().\n");
  728. }
  729. //
  730. // Now go install the product catalog files, validating syssetup.inf
  731. // (and any append-loaded INFs) against the 'primary' catalog.
  732. //
  733. // NOTE: No file/INF operations using setupapi should be done until after
  734. // the product catalogs are installed!
  735. //
  736. if(!LoadString(MyModuleHandle, SetupTitleStringId, TitleStringBuffer, SIZECHARS(TitleStringBuffer))) {
  737. *TitleStringBuffer = L'\0';
  738. }
  739. //
  740. // delete old catalogs that we don't want anymore before we install
  741. // our product catalogs
  742. //
  743. DeleteOldCatalogs();
  744. Err = InstallProductCatalogs(&Problem,
  745. ProblemFile,
  746. (*TitleStringBuffer ? TitleStringBuffer : NULL)
  747. );
  748. if(Err == NO_ERROR) {
  749. if (!MiniSetup && !OobeSetup) {
  750. Err = DuInstallCatalogs (
  751. &Problem,
  752. ProblemFile,
  753. (*TitleStringBuffer ? TitleStringBuffer : NULL)
  754. );
  755. if (Err != NO_ERROR) {
  756. //
  757. // We couldn't install updates. However, there's not
  758. // a whole lot we can do about it. We'll just log an error for this
  759. //
  760. SetuplogError(
  761. LogSevError,
  762. SETUPLOG_USE_MESSAGEID,
  763. MSG_LOG_SYSSETUP_UPDATES_FAILED,
  764. (*TitleStringBuffer ? TitleStringBuffer : ProblemFile),
  765. Err,
  766. ProblemFile,
  767. NULL,
  768. NULL
  769. );
  770. //
  771. // Also, add an entry about this failure to setupapi's PSS exception
  772. // logfile.
  773. //
  774. pSetupHandleFailedVerification (
  775. MainWindowHandle,
  776. Problem,
  777. ProblemFile,
  778. (*TitleStringBuffer ? TitleStringBuffer : NULL),
  779. pSetupGetCurrentDriverSigningPolicy(FALSE),
  780. TRUE, // no UI!
  781. Err,
  782. NULL,
  783. NULL,
  784. NULL
  785. );
  786. }
  787. }
  788. }
  789. PnpSeed = GetSeed();
  790. //
  791. // At this point setupapi can verify files/INFs.
  792. //
  793. pSetupSetGlobalFlags(pSetupGetGlobalFlags()&~PSPGF_NO_VERIFY_INF);
  794. //
  795. // Now that we can use crypto, we initialize our codesigning policy
  796. // values. (We have to do this here, because we're about to retrieve
  797. // policy in the error handling code below.)
  798. //
  799. InitializeCodeSigningPolicies(TRUE);
  800. if(Err != NO_ERROR) {
  801. //
  802. // We couldn't install the product catalogs (or syssetup.inf
  803. // couldn't be verified using that catalog). However, there's not
  804. // a whole lot we can do about it. We'll just log an error for
  805. // this, and components that need to be verified later on will
  806. // (based on policy) generate signature verification failure popups.
  807. //
  808. if( Err == CERT_E_EXPIRED)
  809. {
  810. SetuplogError(LogSevError,
  811. SETUPLOG_USE_MESSAGEID,
  812. MSG_LOG_SYSSETUP_CERT_EXPIRED,
  813. Err,
  814. NULL,
  815. NULL
  816. );
  817. }
  818. else
  819. {
  820. SetuplogError(LogSevError,
  821. SETUPLOG_USE_MESSAGEID,
  822. MSG_LOG_SYSSETUP_VERIFY_FAILED,
  823. (*TitleStringBuffer ? TitleStringBuffer : ProblemFile),
  824. Err,
  825. NULL,
  826. SETUPLOG_USE_MESSAGEID,
  827. Err,
  828. NULL,
  829. NULL
  830. );
  831. }
  832. //
  833. // Also, add an entry about this failure to setupapi's PSS exception
  834. // logfile.
  835. //
  836. pSetupHandleFailedVerification(MainWindowHandle,
  837. Problem,
  838. ProblemFile,
  839. (*TitleStringBuffer ? TitleStringBuffer : NULL),
  840. pSetupGetCurrentDriverSigningPolicy(FALSE),
  841. TRUE, // no UI!
  842. Err,
  843. NULL, // log context
  844. NULL, //optional flags
  845. NULL
  846. );
  847. KillBillboard(*Billboard);
  848. FatalError(MSG_LOG_SYSSETUP_CATALOGS_NOT_INSTALLED,0,0);
  849. }
  850. //
  851. // make sure to install the private files (specified with /m)
  852. // BEFORE calling DuInstallUpdates ()
  853. //
  854. InstallPrivateFiles(*Billboard);
  855. if (!MiniSetup && !OobeSetup) {
  856. //
  857. // install any updated files, previously
  858. // downloaded and preprocessed by winnt32
  859. // if it fails, it already logged the reason
  860. //
  861. DuInstallUpdates ();
  862. }
  863. if( (Err=PrepDllCache()) != NO_ERROR ){
  864. SetuplogError(LogSevError,
  865. SETUPLOG_USE_MESSAGEID,
  866. MSG_LOG_MAKEDLLCACHE_CATALOGS_FAILED,
  867. Err,
  868. NULL,
  869. SETUPLOG_USE_MESSAGEID,
  870. Err,
  871. NULL,
  872. NULL
  873. );
  874. }
  875. }
  876. //
  877. // Accessibility Utilities
  878. //
  879. AccessibleSetup = FALSE;
  880. if(SpSetupLoadParameter(pwAccMagnifier,p,MAX_PARAM_LEN) &&
  881. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne))) {
  882. AccessibleSetup = TRUE;
  883. Magnifier = TRUE;
  884. } else {
  885. Magnifier = FALSE;
  886. }
  887. if(SpSetupLoadParameter(pwAccReader,p,MAX_PARAM_LEN) &&
  888. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne))) {
  889. AccessibleSetup = TRUE;
  890. ScreenReader = TRUE;
  891. } else {
  892. ScreenReader = FALSE;
  893. }
  894. if(SpSetupLoadParameter(pwAccKeyboard,p,MAX_PARAM_LEN) &&
  895. (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne))) {
  896. AccessibleSetup = TRUE;
  897. OnScreenKeyboard = TRUE;
  898. } else {
  899. OnScreenKeyboard = FALSE;
  900. }
  901. //
  902. // Fetch original source path and source path type.
  903. // We either deal with network or CD-ROM.
  904. //
  905. if(b) {
  906. Type = DRIVE_CDROM;
  907. lstrcpy(p,L"A:\\");
  908. lstrcat(p,PlatformName);
  909. if(SpSetupLoadParameter(WINNT_D_ORI_SRCPATH,p,MAX_PARAM_LEN)
  910. && SpSetupLoadParameter(WINNT_D_ORI_SRCTYPE,Num,sizeof(Num)/sizeof(Num[0]))) {
  911. Type = wcstoul(Num,NULL,10);
  912. if(Type != DRIVE_REMOTE && Type != DRIVE_FIXED) {
  913. Type = DRIVE_CDROM;
  914. }
  915. }
  916. if(Type == DRIVE_CDROM) {
  917. //
  918. // Make sure the drive is a CD-ROM, as the drive letters
  919. // may be different then when winnt/winnt32 was run.
  920. //
  921. if(MyGetDriveType(p[0]) != DRIVE_CDROM) {
  922. for(c=L'A'; c<=L'Z'; c++) {
  923. if(MyGetDriveType(c) == DRIVE_CDROM) {
  924. p[0] = c;
  925. break;
  926. }
  927. }
  928. if(MyGetDriveType(p[0]) != DRIVE_CDROM) {
  929. //
  930. // No CD-ROM drives. Change to A:.
  931. //
  932. lstrcpy(p,L"A:\\");
  933. lstrcat(p,PlatformName);
  934. }
  935. }
  936. }
  937. //
  938. // Root paths should be like x:\ and not just x:.
  939. //
  940. if(p[0] && (p[1] == L':') && !p[2]) {
  941. p[2] = L'\\';
  942. p[3] = 0;
  943. }
  944. OriginalSourcePath = pSetupDuplicateString(p);
  945. if(!OriginalSourcePath) {
  946. b = FALSE;
  947. SetupDebugPrint( L"SETUP: pSetupDuplicateString failed in SpSetupProcessParameters." );
  948. }
  949. }
  950. //
  951. // The following parameters are optional.
  952. // - Any optional dirs to copy over?
  953. // - User specified command to execute
  954. // - Skip Missing Files?
  955. //
  956. if(b && SpSetupLoadParameter(pwOptionalDirs,p,MAX_PARAM_LEN) && *p) {
  957. OptionalDirSpec = pSetupDuplicateString(p);
  958. if(!OptionalDirSpec) {
  959. b=FALSE;
  960. }
  961. }
  962. if(b && SpSetupLoadParameter(pwUXC,p,MAX_PARAM_LEN) && *p) {
  963. UserExecuteCmd = pSetupDuplicateString(p);
  964. if(!UserExecuteCmd) {
  965. b = FALSE;
  966. SetupDebugPrint( L"SETUP: pSetupDuplicateString failed in SpSetupProcessParameters." );
  967. }
  968. }
  969. if(b && SpSetupLoadParameter(pwSkipMissing,p,MAX_PARAM_LEN)
  970. && (!lstrcmpi(p,pwYes) || !lstrcmpi(p,pwOne))) {
  971. SkipMissingFiles = TRUE;
  972. }
  973. return(b);
  974. }
  975. NTSTATUS
  976. SpSetupLocateSourceCdRom(
  977. OUT PWSTR NtPath
  978. )
  979. /*++
  980. Routine Description:
  981. Searches all the available CD-ROM devices for source media and
  982. returns the NT device name for the first CD-ROM that has the
  983. source media. Currently we use tag file name to validate the
  984. source media.
  985. Arguments:
  986. NtPath - Place holder for receiving NT device name for CD-ROM
  987. that has the source media.
  988. Returns:
  989. Appropriate NTSTATUS code.
  990. --*/
  991. {
  992. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  993. if (NtPath) {
  994. WCHAR LayoutInf[MAX_PATH];
  995. if (GetWindowsDirectory(LayoutInf, ARRAYSIZE(LayoutInf))) {
  996. WCHAR TagFileName[MAX_PATH];
  997. pSetupConcatenatePaths(LayoutInf,
  998. TEXT("\\inf\\layout.inf"),
  999. ARRAYSIZE(TagFileName),
  1000. NULL);
  1001. if (GetPrivateProfileString(TEXT("strings"),
  1002. TEXT("cdtagfile"),
  1003. TEXT(""),
  1004. TagFileName,
  1005. ARRAYSIZE(TagFileName),
  1006. LayoutInf)) {
  1007. SYSTEM_DEVICE_INFORMATION SysDeviceInfo = {0};
  1008. Status = NtQuerySystemInformation(SystemDeviceInformation,
  1009. &SysDeviceInfo,
  1010. sizeof(SYSTEM_DEVICE_INFORMATION),
  1011. NULL);
  1012. if (NT_SUCCESS(Status) && (0 == SysDeviceInfo.NumberOfCdRoms)) {
  1013. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1014. }
  1015. if (NT_SUCCESS(Status)) {
  1016. ULONG Index;
  1017. WCHAR TagFilePathName[MAX_PATH];
  1018. WCHAR SourceCdRomPath[MAX_PATH];
  1019. UNICODE_STRING UnicodeString;
  1020. OBJECT_ATTRIBUTES ObjectAttributes;
  1021. IO_STATUS_BLOCK StatusBlock;
  1022. HANDLE FileHandle;
  1023. UINT OldMode;
  1024. for (Index = 0; Index < SysDeviceInfo.NumberOfCdRoms; Index++) {
  1025. wsprintf(SourceCdRomPath, TEXT("\\device\\cdrom%d\\"), Index);
  1026. wcscpy(TagFilePathName, SourceCdRomPath);
  1027. pSetupConcatenatePaths(TagFilePathName,
  1028. TagFileName,
  1029. ARRAYSIZE(TagFilePathName),
  1030. NULL);
  1031. //
  1032. // See if the NT source path exists.
  1033. //
  1034. RtlInitUnicodeString(&UnicodeString, TagFilePathName);
  1035. InitializeObjectAttributes(&ObjectAttributes,
  1036. &UnicodeString,
  1037. OBJ_CASE_INSENSITIVE,
  1038. NULL,
  1039. NULL);
  1040. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1041. Status = NtCreateFile(&FileHandle,
  1042. FILE_GENERIC_READ,
  1043. &ObjectAttributes,
  1044. &StatusBlock,
  1045. NULL,
  1046. FILE_ATTRIBUTE_NORMAL,
  1047. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1048. FILE_OPEN,
  1049. FILE_SYNCHRONOUS_IO_ALERT,
  1050. NULL,
  1051. 0);
  1052. SetErrorMode(OldMode);
  1053. if(NT_SUCCESS(Status)) {
  1054. CloseHandle(FileHandle);
  1055. //
  1056. // The tag file is present which indicates
  1057. // the current CD-ROM is this is source CD-ROM
  1058. //
  1059. wcscpy(NtPath, SourceCdRomPath);
  1060. break;
  1061. }
  1062. }
  1063. }
  1064. }
  1065. }
  1066. }
  1067. return Status;
  1068. }
  1069. BOOL
  1070. SpSetupProcessSourcePath(
  1071. IN PCWSTR NtPath,
  1072. OUT PWSTR *DosPath
  1073. )
  1074. {
  1075. WCHAR ntPath[MAX_PATH];
  1076. BOOL NtPathIsCd;
  1077. PWCHAR PathPart;
  1078. NTSTATUS Status;
  1079. OBJECT_ATTRIBUTES ObjectAttributes;
  1080. UNICODE_STRING UnicodeString;
  1081. HANDLE Handle;
  1082. IO_STATUS_BLOCK StatusBlock;
  1083. UINT OldMode;
  1084. WCHAR Drive;
  1085. WCHAR PossibleDosPath[MAX_PATH];
  1086. UINT Type;
  1087. BOOL b;
  1088. WCHAR LayoutInf[MAX_PATH];
  1089. #define CDDEVPATH L"\\DEVICE\\CDROM"
  1090. #define CDDEVPATHLEN ((sizeof(CDDEVPATH)/sizeof(WCHAR))-1)
  1091. #define RDRDEVPATH L"\\DEVICE\\LANMANREDIRECTOR"
  1092. #define RDRDEVPATHLEN ((sizeof(RDRDEVPATH)/sizeof(WCHAR))-1)
  1093. if (!(NtPath && DosPath)){
  1094. SetupDebugPrint( L"SETUP: SpSetupProcessSourcePath Invalid parameters passed to SpSetupProcessSourcepath." );
  1095. return FALSE;
  1096. }
  1097. //
  1098. // Determine the source media type based on the nt path
  1099. //
  1100. lstrcpyn(ntPath,NtPath,MAX_PATH);
  1101. CharUpper(ntPath);
  1102. PathPart = NULL;
  1103. NtPathIsCd = FALSE;
  1104. if(wcsstr(ntPath,L"\\DEVICE\\HARDDISK")) {
  1105. //
  1106. // Looks like a hard drive; make sure it's really valid.
  1107. //
  1108. if(PathPart = wcsstr(ntPath,L"\\PARTITION")) {
  1109. if(PathPart = wcschr(PathPart+1,L'\\')) {
  1110. PathPart++;
  1111. }
  1112. }
  1113. } else {
  1114. if(!memcmp(ntPath,CDDEVPATH,CDDEVPATHLEN*sizeof(WCHAR))) {
  1115. NtPathIsCd = TRUE;
  1116. if(PathPart = wcschr(ntPath+CDDEVPATHLEN,L'\\')) {
  1117. PathPart++;
  1118. } else {
  1119. PathPart = wcschr(ntPath,0);
  1120. }
  1121. }
  1122. }
  1123. //
  1124. // Set a global here so we can always know if we're installing from
  1125. // CD.
  1126. //
  1127. gInstallingFromCD = NtPathIsCd;
  1128. //
  1129. // If the case where we don't recognize the device type, just try to
  1130. // convert it to a DOS path and return.
  1131. //
  1132. if(!PathPart) {
  1133. if (memcmp(ntPath,RDRDEVPATH,RDRDEVPATHLEN*sizeof(WCHAR)) == 0) {
  1134. //
  1135. // Special case for \Device\LanmanRedirector: convert to UNC path.
  1136. //
  1137. *DosPath = MyMalloc((lstrlen(ntPath) - RDRDEVPATHLEN + 2)*sizeof(WCHAR));
  1138. if (*DosPath != NULL) {
  1139. wcscpy(*DosPath, L"\\");
  1140. wcscat(*DosPath, ntPath + RDRDEVPATHLEN);
  1141. }
  1142. //
  1143. // Set RemoteBootSetup to indicate that we're doing a remote boot
  1144. // setup. Set BaseCopyStyle to indicate that single-instance store
  1145. // links should be created instead of copying files.
  1146. //
  1147. RemoteBootSetup = TRUE;
  1148. BaseCopyStyle = SP_COPY_SOURCE_SIS_MASTER;
  1149. } else {
  1150. *DosPath = NtFullPathToDosPath(ntPath);
  1151. }
  1152. return(*DosPath != NULL);
  1153. }
  1154. //
  1155. // See if the NT source path exists for CDROM.
  1156. //
  1157. if (GetWindowsDirectory(LayoutInf, ARRAYSIZE(LayoutInf))) {
  1158. WCHAR TagFileName[MAX_PATH];
  1159. pSetupConcatenatePaths(LayoutInf,
  1160. TEXT("\\inf\\layout.inf"),
  1161. ARRAYSIZE(LayoutInf),
  1162. NULL);
  1163. //
  1164. // Get the name of the cd tag file name from layout.inf file
  1165. //
  1166. if (GetPrivateProfileString(TEXT("strings"),
  1167. TEXT("cdtagfile"),
  1168. TEXT(""),
  1169. TagFileName,
  1170. ARRAYSIZE(TagFileName),
  1171. LayoutInf)) {
  1172. WCHAR TagFilePathName[MAX_PATH];
  1173. HANDLE FileHandle;
  1174. wcscpy(TagFilePathName, ntPath);
  1175. pSetupConcatenatePaths( TagFilePathName,
  1176. TagFileName,
  1177. ARRAYSIZE(TagFilePathName),
  1178. NULL);
  1179. //
  1180. // Check if the tag file exists in the CDROM media
  1181. // corresponding to the NtPath passed to us from the
  1182. // Text mode setup.
  1183. // It could have changed, if there are more than one CDROM
  1184. // drives on the computer and more than one contain media
  1185. // as the order in which they get detected in GUI mode setup
  1186. // can be different than in Text mode Setup.
  1187. //
  1188. RtlInitUnicodeString(&UnicodeString, TagFilePathName);
  1189. InitializeObjectAttributes(&ObjectAttributes,
  1190. &UnicodeString,
  1191. OBJ_CASE_INSENSITIVE,
  1192. NULL,
  1193. NULL);
  1194. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1195. Status = NtCreateFile(&FileHandle,
  1196. FILE_GENERIC_READ,
  1197. &ObjectAttributes,
  1198. &StatusBlock,
  1199. NULL,
  1200. FILE_ATTRIBUTE_NORMAL,
  1201. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1202. FILE_OPEN,
  1203. FILE_SYNCHRONOUS_IO_ALERT,
  1204. NULL,
  1205. 0);
  1206. SetErrorMode(OldMode);
  1207. //
  1208. // Tag file exists in the CDROM media represented by NtPath.
  1209. //
  1210. if(NT_SUCCESS(Status)) {
  1211. CloseHandle(FileHandle);
  1212. //
  1213. // The tag file is present which indicates
  1214. // the current CD-ROM is this is source CD-ROM
  1215. //
  1216. *DosPath = NtFullPathToDosPath(ntPath);
  1217. return(*DosPath != NULL);
  1218. }
  1219. }
  1220. }
  1221. //
  1222. // Scan for source CD-ROM among available CD-ROM devices
  1223. //
  1224. if (NtPathIsCd) {
  1225. WCHAR NtSourceCdRomPath[MAX_PATH] = {0};
  1226. NTSTATUS Status = SpSetupLocateSourceCdRom(NtSourceCdRomPath);
  1227. if (NT_SUCCESS(Status)) {
  1228. *DosPath = NtFullPathToDosPath(NtSourceCdRomPath);
  1229. if (*DosPath) {
  1230. return TRUE;
  1231. }
  1232. }
  1233. }
  1234. //
  1235. // The directory does not exist as-is. Look through all dos drives
  1236. // to attempt to find the source path. Match the drive types as well.
  1237. //
  1238. // When we get here PathPart points past the initial \ in the
  1239. // part of the nt device path past the device name. Note that this
  1240. // may be a nul char.
  1241. //
  1242. for(Drive = L'A'; Drive <= L'Z'; Drive++) {
  1243. PossibleDosPath[0] = Drive;
  1244. PossibleDosPath[1] = L':';
  1245. PossibleDosPath[2] = L'\\';
  1246. PossibleDosPath[3] = 0;
  1247. //
  1248. // NOTE: Removable hard drives and floppies both come back
  1249. // as DRIVE_REMOVABLE.
  1250. //
  1251. Type = GetDriveType(PossibleDosPath);
  1252. if(((Type == DRIVE_CDROM) && NtPathIsCd)
  1253. || (((Type == DRIVE_REMOVABLE) || (Type == DRIVE_FIXED)) && !NtPathIsCd)) {
  1254. //
  1255. // See whether the path exists. If we're looking for
  1256. // the root path (such as when installing from a CD,
  1257. // in which case the ntPath was something like
  1258. // \Device\CdRom0\) then we can't use FileExists
  1259. // since that relies on FindFirstFile which fails
  1260. // on root paths.
  1261. //
  1262. if(*PathPart) {
  1263. lstrcpy(PossibleDosPath+3,PathPart);
  1264. b = FileExists(PossibleDosPath,NULL);
  1265. } else {
  1266. b = GetVolumeInformation(
  1267. PossibleDosPath,
  1268. NULL,0, // vol name buffer and size
  1269. NULL, // serial #
  1270. NULL, // max comp len
  1271. NULL, // fs flags
  1272. NULL,0 // fs name buffer and size
  1273. );
  1274. }
  1275. if(b) {
  1276. *DosPath = pSetupDuplicateString(PossibleDosPath);
  1277. return(*DosPath != NULL);
  1278. }
  1279. }
  1280. }
  1281. //
  1282. // Couldn't find it. Try a fall-back.
  1283. //
  1284. *DosPath = NtFullPathToDosPath(ntPath);
  1285. return(*DosPath != NULL);
  1286. }
  1287. VOID
  1288. SetUpProcessorNaming(
  1289. VOID
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. Determines strings which corresponds to the platform name,
  1294. processor name and printer platform. For backwards compat.
  1295. Sets global variables
  1296. PlatformName - a name that indicates the processor platform type;
  1297. one of AMD64, I386, or ia64.
  1298. ProcessorName - a description of the type of processor. This varies
  1299. depending on PlatformName.
  1300. PrinterPlatform - name of platform-specific part of subdirectory
  1301. used in printing architecture. One of w32amd64, w32ia64, or w32x86.
  1302. Arguments:
  1303. None
  1304. Returns:
  1305. None. Global vars filled in as described above.
  1306. --*/
  1307. {
  1308. SYSTEM_INFO SystemInfo;
  1309. GetSystemInfo(&SystemInfo);
  1310. switch(SystemInfo.wProcessorArchitecture) {
  1311. case PROCESSOR_ARCHITECTURE_AMD64:
  1312. ProcessorName = L"AMD64";
  1313. PlatformName = L"AMD64";
  1314. PrinterPlatform = L"w32amd64";
  1315. break;
  1316. case PROCESSOR_ARCHITECTURE_INTEL:
  1317. switch(SystemInfo.wProcessorLevel) {
  1318. case 3:
  1319. ProcessorName = (!IsNEC_98) ? L"I386" : L"nec98"; //NEC98
  1320. break;
  1321. case 4:
  1322. ProcessorName = L"I486";
  1323. break;
  1324. case 6:
  1325. ProcessorName = L"I686";
  1326. break;
  1327. case 5:
  1328. default:
  1329. ProcessorName = L"I586";
  1330. break;
  1331. }
  1332. PlatformName = (!IsNEC_98) ? L"I386" : L"nec98"; //NEC98
  1333. PrinterPlatform = L"w32x86";
  1334. break;
  1335. case PROCESSOR_ARCHITECTURE_IA64:
  1336. ProcessorName = L"Merced";
  1337. PlatformName = L"IA64";
  1338. PrinterPlatform = L"w32ia64";
  1339. break;
  1340. }
  1341. //
  1342. // In default case the vars stay "" which is what they are
  1343. // statically initialized to.
  1344. //
  1345. }
  1346. VOID
  1347. InitializeUniqueness(
  1348. IN OUT HWND *Billboard
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. Initialize uniquess by looking in a database file and overwriting the
  1353. parameters file with information found in it, based in a unique identifier
  1354. passed along to us from text mode (and originally winnt/winnt32).
  1355. There are 2 options: the database was copied into the source path by winnt/
  1356. winnt32, or we need to prompt the user to insert a floppy from his admin
  1357. that contains the database.
  1358. The user may elect to cancel, which means setup will continue, but the
  1359. machine will probably not be configured properly.
  1360. Arguments:
  1361. Billboard - on input contains handle of currently displayed "Setup is
  1362. Initializing" billboard. On output contains new handle if this routine
  1363. had to display UI. We pass this around to avoid annoying flashing of
  1364. the billboard.
  1365. Returns:
  1366. None.
  1367. --*/
  1368. {
  1369. PWCHAR p;
  1370. WCHAR UniquenessId[MAX_PARAM_LEN];
  1371. WCHAR DatabaseFile[MAX_PATH];
  1372. BOOL Prompt;
  1373. int i;
  1374. UINT OldMode;
  1375. BOOL NeedNewBillboard;
  1376. //
  1377. // Determine whether uniqueness is even important by looking
  1378. // for a uniqueness spec in the parameters file.
  1379. // If the id ends with a * then we expect the uniqueness database file
  1380. // to be in the source, with a reserved name. Otherwise we need to
  1381. // prompt for it on a floppy.
  1382. //
  1383. if(SpSetupLoadParameter(WINNT_D_UNIQUENESS,UniquenessId,MAX_PARAM_LEN)) {
  1384. if(p = wcschr(UniquenessId,L'*')) {
  1385. *p = 0;
  1386. Prompt = FALSE;
  1387. } else {
  1388. Prompt = TRUE;
  1389. }
  1390. } else {
  1391. //
  1392. // We don't care about uniqueness.
  1393. //
  1394. return;
  1395. }
  1396. //
  1397. // If the file is already in the source, attempt to make use of it now.
  1398. // If this fails tell the user and fall through to the floppy prompt case.
  1399. //
  1400. if(!Prompt) {
  1401. lstrcpy(DatabaseFile,SourcePath);
  1402. pSetupConcatenatePaths(DatabaseFile,WINNT_UNIQUENESS_DB,MAX_PATH,NULL);
  1403. if(IntegrateUniquenessInfo(DatabaseFile,UniquenessId)) {
  1404. return;
  1405. }
  1406. MessageBoxFromMessage(
  1407. MainWindowHandle,
  1408. MSG_UNIQUENESS_DB_BAD_1,
  1409. NULL,
  1410. IDS_WINNT_SETUP,
  1411. MB_OK | MB_ICONERROR,
  1412. UniquenessId
  1413. );
  1414. Prompt = TRUE;
  1415. }
  1416. lstrcpy(DatabaseFile,L"A:\\");
  1417. lstrcat(DatabaseFile,WINNT_UNIQUENESS_DB);
  1418. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1419. if(Prompt) {
  1420. KillBillboard(*Billboard);
  1421. NeedNewBillboard = TRUE;
  1422. } else {
  1423. NeedNewBillboard = FALSE;
  1424. }
  1425. while(Prompt) {
  1426. i = MessageBoxFromMessage(
  1427. MainWindowHandle,
  1428. MSG_UNIQUENESS_DB_PROMPT,
  1429. NULL,
  1430. IDS_WINNT_SETUP,
  1431. MB_OKCANCEL
  1432. );
  1433. if(i == IDOK) {
  1434. //
  1435. // User thinks he provided a floppy with the database floppy on it.
  1436. //
  1437. if(IntegrateUniquenessInfo(DatabaseFile,UniquenessId)) {
  1438. Prompt = FALSE;
  1439. } else {
  1440. MessageBoxFromMessage(
  1441. MainWindowHandle,
  1442. MSG_UNIQUENESS_DB_BAD_2,
  1443. NULL,
  1444. IDS_WINNT_SETUP,
  1445. MB_OK | MB_ICONERROR,
  1446. UniquenessId
  1447. );
  1448. }
  1449. } else {
  1450. //
  1451. // User cancelled -- verify.
  1452. //
  1453. i = MessageBoxFromMessage(
  1454. MainWindowHandle,
  1455. MSG_UNIQUENESS_DB_VERIFYCANCEL,
  1456. NULL,
  1457. IDS_WINNT_SETUP,
  1458. MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION
  1459. );
  1460. Prompt = (i != IDYES);
  1461. }
  1462. }
  1463. if(NeedNewBillboard) {
  1464. *Billboard = DisplayBillboard(MainWindowHandle,MSG_INITIALIZING);
  1465. }
  1466. SetErrorMode(OldMode);
  1467. }
  1468. BOOL
  1469. IntegrateUniquenessInfo(
  1470. IN PCWSTR DatabaseFile,
  1471. IN PCWSTR UniqueId
  1472. )
  1473. /*++
  1474. Routine Description:
  1475. Apply uniqueness data from a database, based on a unique identifier.
  1476. The unique identifier is looked up in the [UniqueIds] section of
  1477. the database file. Each field on the line is the name of a section.
  1478. Each section's data overwrites existing data in the unattend.txt file.
  1479. [UniqueIds]
  1480. Id1 = foo,bar
  1481. [foo]
  1482. a = ...
  1483. b = ...
  1484. [bar]
  1485. y = ...
  1486. etc.
  1487. Arguments:
  1488. Database - supplies the name of the uniqueness database (which is
  1489. opened as a legacy inf for simplicity in parsing).
  1490. UniqueId - supplies the unique id for this computer.
  1491. Returns:
  1492. Boolean value indicating outcome.
  1493. --*/
  1494. {
  1495. HINF Database;
  1496. INFCONTEXT InfLine;
  1497. DWORD SectionCount;
  1498. PCWSTR SectionName;
  1499. DWORD i;
  1500. BOOL b;
  1501. //
  1502. // Load the database file as a legacy inf. This makes processing it
  1503. // a little easier.
  1504. //
  1505. Database = SetupOpenInfFile(DatabaseFile,NULL,INF_STYLE_OLDNT,NULL);
  1506. if(Database == INVALID_HANDLE_VALUE) {
  1507. b = FALSE;
  1508. goto c0;
  1509. }
  1510. //
  1511. // Look in the [UniqueIds] section to grab a list of sections
  1512. // we need to overwrite for this user. If the unique id does not appear
  1513. // in the database, bail now. If the id exists but there are no sections,
  1514. // exit with success.
  1515. //
  1516. if(!SetupFindFirstLine(Database,L"UniqueIds",UniqueId,&InfLine)) {
  1517. b = FALSE;
  1518. goto c1;
  1519. }
  1520. SectionCount = SetupGetFieldCount(&InfLine);
  1521. if(!SectionCount) {
  1522. b = TRUE;
  1523. goto c1;
  1524. }
  1525. //
  1526. // Now process each section.
  1527. //
  1528. for(b=TRUE,i=0; b && (i<SectionCount); i++) {
  1529. if(SectionName = pSetupGetField(&InfLine,i+1)) {
  1530. b = ProcessOneUniquenessSection(Database,SectionName,UniqueId);
  1531. } else {
  1532. //
  1533. // Strange case -- the field is there but we can't get at it.
  1534. //
  1535. b = FALSE;
  1536. goto c1;
  1537. }
  1538. }
  1539. c1:
  1540. SetupCloseInfFile(Database);
  1541. c0:
  1542. return(b);
  1543. }
  1544. BOOL
  1545. ProcessOneUniquenessSection(
  1546. IN HINF Database,
  1547. IN PCWSTR SectionName,
  1548. IN PCWSTR UniqueId
  1549. )
  1550. /*++
  1551. Routine Description:
  1552. Within the uniqueness database, process a single section whose contents
  1553. are to be merged into the unattend file. The contents of the section are
  1554. read, key by key, and then written into the unattend file via profile APIs.
  1555. Before looking for the given section, we try to look for a section whose
  1556. name is composed of the unique id and the section name like so
  1557. [someid:sectionname]
  1558. If this section is not found then we look for
  1559. [sectionname]
  1560. Arguments:
  1561. Database - supplies handle to profile file (opened as a legacy inf)
  1562. containing the uniqueness database.
  1563. SectionName - supplies the name of the section to be merged into
  1564. unattend.txt.
  1565. UniqueId - supplies the unique id for this computer.
  1566. Returns:
  1567. Boolean value indicating outcome.
  1568. --*/
  1569. {
  1570. BOOL b;
  1571. PWSTR OtherSection;
  1572. PCWSTR section;
  1573. LONG Count;
  1574. DWORD FieldCount;
  1575. DWORD j;
  1576. LONG i;
  1577. INFCONTEXT InfLine;
  1578. PWCHAR Buffer;
  1579. PWCHAR p;
  1580. PCWSTR Key;
  1581. Buffer = MyMalloc(MAX_INF_STRING_LENGTH * sizeof(WCHAR));
  1582. if(!Buffer) {
  1583. return(FALSE);
  1584. }
  1585. //
  1586. // Form the name of the unique section.
  1587. //
  1588. if(OtherSection = MyMalloc((lstrlen(SectionName) + lstrlen(UniqueId) + 2) * sizeof(WCHAR))) {
  1589. b = TRUE;
  1590. lstrcpy(OtherSection,UniqueId);
  1591. lstrcat(OtherSection,L":");
  1592. lstrcat(OtherSection,SectionName);
  1593. //
  1594. // See whether this unique section exists and if not whether
  1595. // the section name exists as given.
  1596. //
  1597. if((Count = SetupGetLineCount(Database,OtherSection)) == -1) {
  1598. Count = SetupGetLineCount(Database,SectionName);
  1599. section = (Count == -1) ? NULL : SectionName;
  1600. } else {
  1601. section = OtherSection;
  1602. }
  1603. if(section) {
  1604. //
  1605. // Process each line in the section. If a line doesn't have a key,
  1606. // ignore it. If a line has only a key, delete the line in the target.
  1607. //
  1608. for(i=0; i<Count; i++) {
  1609. SetupGetLineByIndex(Database,section,i,&InfLine);
  1610. if(Key = pSetupGetField(&InfLine,0)) {
  1611. if(FieldCount = SetupGetFieldCount(&InfLine)) {
  1612. Buffer[0] = 0;
  1613. for(j=0; j<FieldCount; j++) {
  1614. if(j) {
  1615. lstrcat(Buffer,L",");
  1616. }
  1617. lstrcat(Buffer,L"\"");
  1618. lstrcat(Buffer,pSetupGetField(&InfLine,j+1));
  1619. lstrcat(Buffer,L"\"");
  1620. }
  1621. p = Buffer;
  1622. } else {
  1623. p = NULL;
  1624. }
  1625. if(!WritePrivateProfileString(SectionName,Key,p,AnswerFile)) {
  1626. //
  1627. // Failure, but keep trying in case others might work.
  1628. //
  1629. b = FALSE;
  1630. }
  1631. }
  1632. }
  1633. } else {
  1634. //
  1635. // Unable to find a matching section. Bail.
  1636. //
  1637. b = FALSE;
  1638. }
  1639. MyFree(OtherSection);
  1640. } else {
  1641. b = FALSE;
  1642. }
  1643. MyFree(Buffer);
  1644. return(b);
  1645. }
  1646. DWORD
  1647. InstallProductCatalogs(
  1648. OUT SetupapiVerifyProblem *Problem,
  1649. OUT LPWSTR ProblemFile,
  1650. IN LPCWSTR DescriptionForError OPTIONAL
  1651. )
  1652. /*++
  1653. Routine Description:
  1654. This routine installs all catalog files specified in the
  1655. [ProductCatalogsToInstall] section of syssetup.inf, and validates
  1656. syssetup.inf (and any other INFs append-loaded into its HINF) against the
  1657. catalog that's marked with a non-zero value in the second field of the line.
  1658. Arguments:
  1659. Problem - Supplies the address of a variable that receives the type of
  1660. verification error that occurred, This is only valid if the routine
  1661. returns failure.
  1662. ProblemFile - Supplies a buffer of at least MAX_PATH characters that
  1663. receives the name of the file that caused the verification failure.
  1664. This is only valid if the routine returns failure.
  1665. DescriptionForError - Optionally, supplies descriptive text to be used in a
  1666. call to pSetupHandleFailedVerification() in case an error is encountered.
  1667. Return Value:
  1668. If successful, the return value is NO_ERROR, otherwise it is a Win32 error
  1669. code indicating the cause of the failure. The Problem and ProblemFile
  1670. parameters may be used in that case to provide more specific information
  1671. about why the failure occurred.
  1672. --*/
  1673. {
  1674. HINF hInf;
  1675. LONG LineCount, LineNo;
  1676. DWORD RequiredSize;
  1677. WCHAR SyssetupInfName[MAX_PATH], DecompressedName[MAX_PATH];
  1678. PSP_INF_INFORMATION InfInfoBuffer;
  1679. INFCONTEXT InfContext;
  1680. PCWSTR SectionName = L"ProductCatalogsToInstall";
  1681. PCWSTR InfFileName;
  1682. WCHAR CatToInstall[MAX_PATH], PromptPath[MAX_PATH];
  1683. INT CatForInfVerify;
  1684. DWORD Err = NO_ERROR, ret = NO_ERROR;
  1685. UINT ErrorMessageId;
  1686. BOOL PrimaryCatalogProcessed = FALSE;
  1687. UINT i, SourceId;
  1688. WCHAR TempBuffer[MAX_PATH];
  1689. BOOL DeltaCatPresent=FALSE;
  1690. BOOL OemTestSigned=FALSE;
  1691. //
  1692. // We open up syssetup.inf (and append load any layout INFs) here, just so
  1693. // we can install the catalogs and verify the syssetup.inf and friends
  1694. // against the 'primary' catalog. Note that this isn't the global
  1695. // SyssetupInf handle--that gets opened up later. We can't open the global
  1696. // HINF here, since there's stuff that gets done after this routine is
  1697. // called that could potentially change the way we process the INF
  1698. //
  1699. //
  1700. // Retrieve an INF information context containing information about all
  1701. // append-loaded INFs in our syssetup.inf handle. These INFs will all be
  1702. // validated against our 'primary' catalog file once we discover it.
  1703. //
  1704. if(SetupGetInfInformation(SyssetupInf,
  1705. INFINFO_INF_SPEC_IS_HINF,
  1706. NULL,
  1707. 0,
  1708. &RequiredSize)) {
  1709. MYASSERT(RequiredSize >= sizeof(SP_INF_INFORMATION));
  1710. if(InfInfoBuffer = MyMalloc(RequiredSize)) {
  1711. if(!SetupGetInfInformation(SyssetupInf,
  1712. INFINFO_INF_SPEC_IS_HINF,
  1713. InfInfoBuffer,
  1714. RequiredSize,
  1715. NULL)) {
  1716. //
  1717. // This should never fail!
  1718. //
  1719. Err = GetLastError();
  1720. MYASSERT(0);
  1721. }
  1722. } else {
  1723. Err = ERROR_NOT_ENOUGH_MEMORY;
  1724. }
  1725. } else {
  1726. Err = GetLastError();
  1727. InfInfoBuffer = NULL;
  1728. }
  1729. //
  1730. // If we encountered an error, then we couldn't retrieve information about
  1731. // the loaded INFs in syssetup.inf's HINF--this should never happen
  1732. // (barring an out-of-memory condition), but if it does, just bail.
  1733. //
  1734. if(Err != NO_ERROR) {
  1735. *Problem = SetupapiVerifyInfProblem;
  1736. lstrcpy(ProblemFile, L"syssetup.inf");
  1737. goto clean0;
  1738. }
  1739. //
  1740. // If there's a [SourceDisksFiles] entry for testroot.cer in one of the
  1741. // append-loaded INFs in syssetup.inf's HINF (specifically, from
  1742. // layout.inf), then we will go and install that test certificate in the
  1743. // root store so that the test signatures used for this internal-release-only
  1744. // build will be verified. We will also install a test root certificate if
  1745. // one is specified in unattend.txt in the "TestCert" entry in the
  1746. // [unattended] section.
  1747. //
  1748. // If testroot.cer isn't listed in one of the two aforementioned locations,
  1749. // then we know the files in this build were signed for real, so we want to
  1750. // delete the test certificate(s), in case we're updating an installation
  1751. // that was installed previously using a test-signed build.
  1752. //
  1753. if(SetupGetSourceFileLocation(SyssetupInf, NULL, L"testroot.cer", &SourceId, NULL, 0, NULL)) {
  1754. //
  1755. // Testroot.cer must exist (possibly compressed) in the source
  1756. // directory. (Regardless of whether testroot.cer is compressed, use
  1757. // the DecompressedName buffer to temporarily hold this filename.)
  1758. //
  1759. lstrcpy(DecompressedName, L"testroot.cer");
  1760. } else {
  1761. GetSystemDirectory(TempBuffer, MAX_PATH);
  1762. pSetupConcatenatePaths(TempBuffer, WINNT_GUI_FILE, MAX_PATH, NULL);
  1763. if(GetPrivateProfileString(WINNT_UNATTENDED,
  1764. WINNT_U_TESTCERT,
  1765. pwNull,
  1766. DecompressedName,
  1767. MAX_PATH,
  1768. TempBuffer)) {
  1769. OemTestSigned = TRUE;
  1770. }
  1771. }
  1772. if(*DecompressedName) {
  1773. Err = SetupAddOrRemoveTestCertificate(
  1774. DecompressedName,
  1775. (OemTestSigned ? INVALID_HANDLE_VALUE : SyssetupInf)
  1776. );
  1777. if(Err != NO_ERROR) {
  1778. SetupDebugPrint2(L"SETUP: SetupAddOrRemoveTestCertificate(%ls) failed. Error = %d \n", DecompressedName, Err );
  1779. //
  1780. // This is considered a critial failure--as we could bugcheck post - setup.
  1781. //
  1782. SetuplogError(LogSevError,
  1783. SETUPLOG_USE_MESSAGEID,
  1784. MSG_LOG_SYSSETUP_CERT_NOT_INSTALLED,
  1785. DecompressedName,
  1786. Err,
  1787. NULL,
  1788. SETUPLOG_USE_MESSAGEID,
  1789. Err,
  1790. NULL,
  1791. NULL
  1792. );
  1793. //
  1794. // If this was an internal test-signed build, then point the
  1795. // accusing finger at syssetup.inf.
  1796. //
  1797. if(!OemTestSigned) {
  1798. *Problem = SetupapiVerifyInfProblem;
  1799. lstrcpy(ProblemFile, L"syssetup.inf");
  1800. } else {
  1801. *Problem = SetupapiVerifyCatalogProblem;
  1802. lstrcpy(ProblemFile, DecompressedName);
  1803. }
  1804. if(InfInfoBuffer)
  1805. MyFree(InfInfoBuffer);
  1806. return Err;
  1807. }
  1808. } else {
  1809. //
  1810. // testroot.cer isn't listed--remove it from the installation in case
  1811. // we're upgrading over an internal-release-only test build.
  1812. //
  1813. MYASSERT(GetLastError() == ERROR_LINE_NOT_FOUND);
  1814. Err = SetupAddOrRemoveTestCertificate(NULL,NULL);
  1815. if(Err != NO_ERROR) {
  1816. SetupDebugPrint1(L"SETUP: SetupAddOrRemoveTestCertificate(NULL) failed. Error = %d \n", Err );
  1817. //
  1818. // This is not considered a critial failure.
  1819. //
  1820. Err = NO_ERROR;
  1821. }
  1822. }
  1823. //
  1824. // Loop through all the lines in the ProductCatalogsToInstall section,
  1825. // verifying and installing each one.
  1826. //
  1827. LineCount = SetupGetLineCount(SyssetupInf, SectionName);
  1828. for(LineNo=0; LineNo<LineCount+1; LineNo++) {
  1829. if(LineNo==LineCount){
  1830. if(IncludeCatalog && *IncludeCatalog ){
  1831. DeltaCatPresent = TRUE; // This indicates presence as well as says that we
  1832. }else // are looking at delta.cat in this iteration.
  1833. break;
  1834. }
  1835. if((SetupGetLineByIndex(SyssetupInf, SectionName, LineNo, &InfContext)
  1836. && (InfFileName = pSetupGetField(&InfContext,1))) || DeltaCatPresent ) {
  1837. if( DeltaCatPresent )
  1838. InfFileName = IncludeCatalog;
  1839. //
  1840. // This .CAT file might be compressed (e.g., .CA_), so decompress it
  1841. // into a temporary file in the windows directory. (Use CatToInstall
  1842. // temporarily as a holding space for the windows directory in
  1843. // preparation for a call to GetTempFileName).
  1844. //
  1845. if(!GetWindowsDirectory(CatToInstall, SIZECHARS(CatToInstall)) ||
  1846. !GetTempFileName(CatToInstall, L"SETP", 0, DecompressedName)) {
  1847. Err = GetLastError();
  1848. if(InfInfoBuffer)
  1849. MyFree(InfInfoBuffer);
  1850. return Err;
  1851. }
  1852. //
  1853. // The catalog file will be in the (platform-specific) source
  1854. // directory...
  1855. //
  1856. BuildPathToInstallationFile (InfFileName, CatToInstall, SIZECHARS(CatToInstall));
  1857. //
  1858. // If the 2nd field of this line has a non-zero value, then this is
  1859. // the catalog against which the members of the HINF must be
  1860. // verified.
  1861. //
  1862. if(!DeltaCatPresent && !SetupGetIntField(&InfContext, 2, &CatForInfVerify)) {
  1863. CatForInfVerify = 0;
  1864. }
  1865. //
  1866. // Get necessary strings and source ID for UI if needed.
  1867. //
  1868. if( DeltaCatPresent ){
  1869. Err = SetupDecompressOrCopyFile(CatToInstall,
  1870. DecompressedName,
  1871. NULL);
  1872. }else{
  1873. SetupGetSourceFileLocation(
  1874. SyssetupInf,
  1875. NULL,
  1876. InfFileName,
  1877. &SourceId, //re-using
  1878. NULL,
  1879. 0,
  1880. NULL
  1881. );
  1882. SetupGetSourceInfo(
  1883. SyssetupInf,
  1884. SourceId,
  1885. SRCINFO_DESCRIPTION,
  1886. TempBuffer,
  1887. sizeof(TempBuffer),
  1888. NULL
  1889. );
  1890. //
  1891. // This .CAT file might be compressed (e.g., .CA_), so decompress it
  1892. // into a temporary file in the windows directory.
  1893. //
  1894. do{
  1895. Err = DuSetupPromptForDisk (
  1896. MainWindowHandle,
  1897. NULL,
  1898. TempBuffer,
  1899. LegacySourcePath,
  1900. InfFileName,
  1901. NULL,
  1902. IDF_CHECKFIRST | IDF_NODETAILS | IDF_NOBROWSE,
  1903. PromptPath,
  1904. MAX_PATH,
  1905. NULL
  1906. );
  1907. if( Err == DPROMPT_SUCCESS ){
  1908. lstrcpy( CatToInstall, PromptPath );
  1909. pSetupConcatenatePaths(CatToInstall, InfFileName, SIZECHARS(CatToInstall), NULL);
  1910. Err = SetupDecompressOrCopyFile(CatToInstall,
  1911. DecompressedName,
  1912. NULL);
  1913. }
  1914. }while( Err == ERROR_NOT_READY );
  1915. }
  1916. if(Err != NO_ERROR){
  1917. if( lstrcmpi(InfFileName, L"NT5.CAT") && !CatForInfVerify ){
  1918. SetuplogError(LogSevError,
  1919. SETUPLOG_USE_MESSAGEID,
  1920. MSG_LOG_SYSSETUP_CATFILE_SKIPPED,
  1921. CatToInstall,
  1922. NULL,
  1923. SETUPLOG_USE_MESSAGEID,
  1924. Err,
  1925. NULL,
  1926. NULL
  1927. );
  1928. Err = NO_ERROR;
  1929. continue;
  1930. }
  1931. else{
  1932. SetuplogError(LogSevError,
  1933. SETUPLOG_USE_MESSAGEID,
  1934. MSG_LOG_SYSSETUP_CATFILE_NOT_FOUND,
  1935. CatToInstall,
  1936. Err,
  1937. NULL,
  1938. SETUPLOG_USE_MESSAGEID,
  1939. Err,
  1940. NULL,
  1941. NULL
  1942. );
  1943. }
  1944. if(InfInfoBuffer)
  1945. MyFree(InfInfoBuffer);
  1946. return Err; //Fatal (NT5.cat or NT5INF.cat)- must fail as we could bugcheck later
  1947. }
  1948. if(CatForInfVerify) {
  1949. PrimaryCatalogProcessed = TRUE;
  1950. //
  1951. // Verify all INFs in syssetup.inf's HINF using this catalog.
  1952. //
  1953. for(i = 0;
  1954. ((Err == NO_ERROR) && (i < InfInfoBuffer->InfCount));
  1955. i++)
  1956. {
  1957. if(!SetupQueryInfFileInformation(InfInfoBuffer,
  1958. i,
  1959. SyssetupInfName,
  1960. SIZECHARS(SyssetupInfName),
  1961. NULL)) {
  1962. //
  1963. // This should never fail!
  1964. //
  1965. MYASSERT(0);
  1966. //
  1967. // Just use syssetup.inf's simple name so there'll
  1968. // be some clue as to what blew up.
  1969. //
  1970. lstrcpy(ProblemFile, L"syssetup.inf");
  1971. *Problem = SetupapiVerifyInfProblem;
  1972. Err = GetLastError();
  1973. MYASSERT(Err != NO_ERROR);
  1974. break;
  1975. }
  1976. Err = pSetupVerifyFile(NULL,
  1977. DecompressedName,
  1978. NULL,
  1979. 0,
  1980. pSetupGetFileTitle(SyssetupInfName),
  1981. SyssetupInfName,
  1982. Problem,
  1983. ProblemFile,
  1984. FALSE,
  1985. NULL,
  1986. NULL,
  1987. NULL
  1988. );
  1989. }
  1990. if(Err != NO_ERROR) {
  1991. //
  1992. // Just return the error--the caller will deal with it.
  1993. //
  1994. if(*Problem == SetupapiVerifyCatalogProblem) {
  1995. //
  1996. // Use the catalog's original name, not our temporary
  1997. // filename.
  1998. //
  1999. lstrcpy(ProblemFile, CatToInstall);
  2000. } else {
  2001. //
  2002. // pSetupVerifyCatalogFile didn't know we were asking it to verify an
  2003. // INF, but we do.
  2004. //
  2005. *Problem = SetupapiVerifyInfProblem;
  2006. }
  2007. DeleteFile(DecompressedName);
  2008. goto clean0;
  2009. }
  2010. //
  2011. // OK, catalog and INF both verify--now install the catalog.
  2012. //
  2013. Err = pSetupInstallCatalog(DecompressedName, InfFileName, NULL);
  2014. if(Err != NO_ERROR) {
  2015. //
  2016. // Fill out problem information about the catalog we couldn't
  2017. // install, and return this error to the caller.
  2018. //
  2019. *Problem = SetupapiVerifyCatalogProblem;
  2020. lstrcpy(ProblemFile, CatToInstall);
  2021. DeleteFile(DecompressedName);
  2022. goto clean0;
  2023. }
  2024. } else {
  2025. //
  2026. // Just verify the catalog, and if it's OK, then install it.
  2027. // (If we encounter any errors here, we'll log an event about it.
  2028. //
  2029. Err = pSetupVerifyCatalogFile(DecompressedName);
  2030. if(Err == NO_ERROR) {
  2031. Err = pSetupInstallCatalog(DecompressedName, InfFileName, NULL);
  2032. if(Err != NO_ERROR) {
  2033. ErrorMessageId = MSG_LOG_SYSSETUP_CATINSTALL_FAILED;
  2034. }
  2035. } else {
  2036. ErrorMessageId = MSG_LOG_SYSSETUP_VERIFY_FAILED;
  2037. }
  2038. if(Err != NO_ERROR) {
  2039. DWORD DontCare;
  2040. SetuplogError(LogSevError,
  2041. SETUPLOG_USE_MESSAGEID,
  2042. ErrorMessageId,
  2043. CatToInstall,
  2044. Err,
  2045. NULL,
  2046. SETUPLOG_USE_MESSAGEID,
  2047. Err,
  2048. NULL,
  2049. NULL
  2050. );
  2051. //
  2052. // Also, add an entry about this failure to setupapi's PSS
  2053. // exception logfile.
  2054. //
  2055. pSetupHandleFailedVerification(MainWindowHandle,
  2056. SetupapiVerifyCatalogProblem,
  2057. CatToInstall,
  2058. DescriptionForError,
  2059. pSetupGetCurrentDriverSigningPolicy(FALSE),
  2060. TRUE, // no UI!
  2061. Err,
  2062. NULL, // log context
  2063. NULL, // optional flags
  2064. NULL
  2065. );
  2066. if( !lstrcmpi(InfFileName, L"NT5.CAT") ){ //Special case NT5.CAT as critical failure
  2067. *Problem = SetupapiVerifyCatalogProblem; //Otherwise just log it and move on
  2068. lstrcpy(ProblemFile, CatToInstall);
  2069. DeleteFile(DecompressedName);
  2070. goto clean0;
  2071. }else
  2072. Err = NO_ERROR;
  2073. }
  2074. }
  2075. //
  2076. // Delete the temporary file we created to hold the decompressed
  2077. // catalog during verification/installation.
  2078. //
  2079. DeleteFile(DecompressedName);
  2080. }
  2081. }
  2082. clean0:
  2083. if(!PrimaryCatalogProcessed) {
  2084. //
  2085. // Then we didn't find a line in our ProductCatalogsToInstall section
  2086. // that was marked as the 'primary' catalog. Point the accusing finger
  2087. // at syssetup.inf.
  2088. //
  2089. if(!SetupQueryInfFileInformation(InfInfoBuffer,
  2090. 0,
  2091. ProblemFile,
  2092. MAX_PATH,
  2093. NULL)) {
  2094. //
  2095. // This should never fail!
  2096. //
  2097. MYASSERT(0);
  2098. //
  2099. // Just use syssetup.inf's simple name so there'll be some clue as
  2100. // to what blew up.
  2101. //
  2102. lstrcpy(ProblemFile, L"syssetup.inf");
  2103. }
  2104. *Problem = SetupapiVerifyInfProblem;
  2105. Err = ERROR_LINE_NOT_FOUND;
  2106. }
  2107. if(InfInfoBuffer) {
  2108. MyFree(InfInfoBuffer);
  2109. }
  2110. return Err;
  2111. }
  2112. DWORD
  2113. SetupInstallCatalog(
  2114. IN LPCWSTR DecompressedName
  2115. )
  2116. {
  2117. PCWSTR InfFileName = pSetupGetFileTitle(DecompressedName);
  2118. DWORD Err;
  2119. UINT ErrorMessageId;
  2120. Err = pSetupVerifyCatalogFile(DecompressedName);
  2121. if(Err == NO_ERROR) {
  2122. Err = pSetupInstallCatalog(DecompressedName, InfFileName, NULL);
  2123. if(Err != NO_ERROR) {
  2124. ErrorMessageId = MSG_LOG_SYSSETUP_CATINSTALL_FAILED;
  2125. }
  2126. } else {
  2127. ErrorMessageId = MSG_LOG_SYSSETUP_VERIFY_FAILED;
  2128. }
  2129. if(Err != NO_ERROR) {
  2130. SetuplogError(LogSevError,
  2131. SETUPLOG_USE_MESSAGEID,
  2132. ErrorMessageId,
  2133. DecompressedName,
  2134. Err,
  2135. NULL,
  2136. SETUPLOG_USE_MESSAGEID,
  2137. Err,
  2138. NULL,
  2139. NULL
  2140. );
  2141. }
  2142. return Err;
  2143. }
  2144. VOID
  2145. InitializeCodeSigningPolicies(
  2146. IN BOOL ForGuiSetup
  2147. )
  2148. /*++
  2149. Routine Description:
  2150. Sets up the system-default policy values for driver and non-driver signing.
  2151. These policies control what action is taken when a digital signature
  2152. verification failure is encountered. The possible values are:
  2153. Ignore (0) -- suppress any UI and continue with the operation (we do still
  2154. log the error, however)
  2155. Warn (1) -- warn the user, giving them the option of continuing in spite
  2156. of the verification failure
  2157. Block (2) -- inform the user of the failure, and do not allow them to
  2158. continue with the operation
  2159. The registry path for driver signing policy is:
  2160. HKLM\Software\Microsoft\Driver Signing
  2161. and the registry path for non-driver signing policy is:
  2162. HKLM\Software\Microsoft\Non-Driver Signing
  2163. In both cases, the value entry is called "Policy". For Win98 compatibility,
  2164. this value is a REG_BINARY (length 1). However, when the codesigning stuff
  2165. was first checked in on NT, it was implemented as a REG_DWORD. At that
  2166. time, the default policy was ignore. We now want the default to be warn for
  2167. both driver and non-driver signing during GUI-mode setup, while dropping the
  2168. non-driver signing policy back to ignore once GUI-mode setup is completed.
  2169. (If answerfile values are specified for either of these policies, those
  2170. values are in effect for GUI-mode setup and thereafter.)
  2171. When upgrading from previous builds (in the absence of answerfile entries),
  2172. we want to preserve the existing policy settings once GUI-mode setup is
  2173. completed. However, we'd like to raise the policy level to warn post-setup
  2174. for upgrades from older builds (like beta 2). We use the aforementioned
  2175. difference between the present REG_BINARY type and the old REG_DWORD type to
  2176. accomplish this. If we retrieve the existing driver signing policy and its
  2177. data type is REG_DWORD, then we update it to be set to warn (unless it's
  2178. already set to block, in which case we leave it alone).
  2179. Arguments:
  2180. ForGuiSetup - if non-zero (TRUE), then we're entering GUI-mode setup, and
  2181. we'll apply the answerfile policies, if provided. Otherwise, we'll use
  2182. the same default values that are in-place post-setup. (Presently, this
  2183. is Warn for driver signing, and Ignore for non-driver signing.)
  2184. If zero (FALSE), we're leaving GUI-mode setup, and we want to restore
  2185. the policies that were in effect when we entered setup. If there
  2186. weren't any (i.e., a fresh install) then they were initialized to warn
  2187. and ignore for driver and non-driver signing, respectively. See
  2188. discussion above for how we raise driver signing policy from its old
  2189. default of ignore to the present default of warn.
  2190. Return Value:
  2191. None
  2192. --*/
  2193. {
  2194. WCHAR p[MAX_PARAM_LEN];
  2195. BYTE SpDrvSignPolicy, SpNonDrvSignPolicy;
  2196. LONG Err;
  2197. if(ForGuiSetup) {
  2198. //
  2199. // Default in GUI-mode setup is that driver signing policy is set to
  2200. // warn, and non-driver signing policy is set to ignore.
  2201. //
  2202. SpDrvSignPolicy = DRIVERSIGN_WARNING;
  2203. SpNonDrvSignPolicy = DRIVERSIGN_NONE;
  2204. //
  2205. // Retrieve the (optional) system-default policy for driver signing.
  2206. //
  2207. if(SpSetupLoadParameter(pwDrvSignPol,p,MAX_PARAM_LEN)) {
  2208. if(!lstrcmpi(p, pwIgnore)) {
  2209. AFDrvSignPolicySpecified = TRUE;
  2210. SpDrvSignPolicy = DRIVERSIGN_NONE;
  2211. } else if(!lstrcmpi(p, pwWarn)) {
  2212. AFDrvSignPolicySpecified = TRUE;
  2213. SpDrvSignPolicy = DRIVERSIGN_WARNING;
  2214. } else if(!lstrcmpi(p, pwBlock)) {
  2215. AFDrvSignPolicySpecified = TRUE;
  2216. SpDrvSignPolicy = DRIVERSIGN_BLOCKING;
  2217. }
  2218. }
  2219. SetCodeSigningPolicy(PolicyTypeDriverSigning,
  2220. SpDrvSignPolicy,
  2221. (AFDrvSignPolicySpecified
  2222. ? NULL
  2223. : &DrvSignPolicy)
  2224. );
  2225. //
  2226. // Now retrieve the (optional) system-default policy for non-driver
  2227. // signing.
  2228. //
  2229. if(SpSetupLoadParameter(pwNonDrvSignPol,p,MAX_PARAM_LEN)) {
  2230. if(!lstrcmpi(p, pwIgnore)) {
  2231. AFNonDrvSignPolicySpecified = TRUE;
  2232. SpNonDrvSignPolicy = DRIVERSIGN_NONE;
  2233. } else if(!lstrcmpi(p, pwWarn)) {
  2234. AFNonDrvSignPolicySpecified = TRUE;
  2235. SpNonDrvSignPolicy = DRIVERSIGN_WARNING;
  2236. } else if(!lstrcmpi(p, pwBlock)) {
  2237. AFNonDrvSignPolicySpecified = TRUE;
  2238. SpNonDrvSignPolicy = DRIVERSIGN_BLOCKING;
  2239. }
  2240. }
  2241. SetCodeSigningPolicy(PolicyTypeNonDriverSigning,
  2242. SpNonDrvSignPolicy,
  2243. (AFNonDrvSignPolicySpecified
  2244. ? NULL
  2245. : &NonDrvSignPolicy)
  2246. );
  2247. } else {
  2248. //
  2249. // We're setting up the policies to be in effect after GUI-mode setup.
  2250. // If the answer file specified a policy, then we'll leave that in
  2251. // effect (i.e., it's applicable both during GUI-mode setup and
  2252. // thereafter).
  2253. //
  2254. if(!AFDrvSignPolicySpecified) {
  2255. SetCodeSigningPolicy(PolicyTypeDriverSigning, DrvSignPolicy, NULL);
  2256. }
  2257. if(!AFNonDrvSignPolicySpecified) {
  2258. SetCodeSigningPolicy(PolicyTypeNonDriverSigning, NonDrvSignPolicy, NULL);
  2259. }
  2260. }
  2261. }
  2262. VOID
  2263. InstallPrivateFiles(
  2264. IN HWND Billboard
  2265. )
  2266. /*
  2267. Routine to make sure that files in delta.inf (winnt32 /m private files that live inside the cab)
  2268. are copied to the driver cache directory so that setupapi finds them instead of the ones in the
  2269. cab.
  2270. */
  2271. {
  2272. WCHAR DeltaPath[MAX_PATH];
  2273. HINF DeltaInf;
  2274. HSPFILEQ FileQueue;
  2275. PVOID QContext;
  2276. BOOL b=TRUE;
  2277. BYTE PrevPolicy;
  2278. BOOL ResetPolicy = TRUE;
  2279. //
  2280. // Unless the default non-driver signing policy was overridden via an
  2281. // answerfile entry, then we want to temporarily turn down the policy level
  2282. // to ignore while we copy optional directories. Of course, setupapi log
  2283. // entries will still be generated for any unsigned files copied during
  2284. // this time, but there'll be no UI.
  2285. //
  2286. if(!AFNonDrvSignPolicySpecified) {
  2287. SetCodeSigningPolicy(PolicyTypeNonDriverSigning, DRIVERSIGN_NONE, &PrevPolicy);
  2288. ResetPolicy = TRUE;
  2289. }
  2290. BuildPathToInstallationFileEx (L"delta.inf", DeltaPath, MAX_PATH, FALSE);
  2291. FileQueue = SetupOpenFileQueue();
  2292. b = b && (FileQueue != INVALID_HANDLE_VALUE);
  2293. b = b && FileExists( DeltaPath, NULL );
  2294. if(b){
  2295. DeltaInf = SetupOpenInfFile(DeltaPath,NULL,INF_STYLE_WIN4,NULL);
  2296. if(DeltaInf && (DeltaInf != INVALID_HANDLE_VALUE)) {
  2297. SetupInstallFilesFromInfSection(
  2298. DeltaInf,
  2299. NULL,
  2300. FileQueue,
  2301. L"InstallSection",
  2302. LegacySourcePath,
  2303. SP_COPY_NEWER
  2304. );
  2305. SetupCloseInfFile(DeltaInf);
  2306. } else {
  2307. b = FALSE;
  2308. }
  2309. }
  2310. if( b ){
  2311. QContext = InitSysSetupQueueCallbackEx(
  2312. Billboard,
  2313. INVALID_HANDLE_VALUE,
  2314. 0,0,NULL);
  2315. if (QContext) {
  2316. b = SetupCommitFileQueue(
  2317. Billboard,
  2318. FileQueue,
  2319. SysSetupQueueCallback,
  2320. QContext
  2321. );
  2322. TermSysSetupQueueCallback(QContext);
  2323. } else {
  2324. b = FALSE;
  2325. }
  2326. }
  2327. if(FileQueue != INVALID_HANDLE_VALUE)
  2328. SetupCloseFileQueue(FileQueue);
  2329. //
  2330. // Now crank the non-driver signing policy back up to what it was prior to
  2331. // entering this routine.
  2332. //
  2333. if(ResetPolicy) {
  2334. SetCodeSigningPolicy(PolicyTypeNonDriverSigning, PrevPolicy, NULL);
  2335. }
  2336. return;
  2337. }
  2338. BOOL
  2339. IsCatalogPresent(
  2340. IN PCWSTR CatalogName
  2341. )
  2342. {
  2343. WCHAR FileBuffer[MAX_PATH];
  2344. ExpandEnvironmentStrings( L"%systemroot%", FileBuffer, sizeof(FileBuffer)/sizeof(WCHAR));
  2345. pSetupConcatenatePaths( FileBuffer, FILEUTIL_HORRIBLE_PATHNAME, MAX_PATH, NULL );
  2346. pSetupConcatenatePaths( FileBuffer, CatalogName, MAX_PATH, NULL );
  2347. return (FileExists( FileBuffer, NULL));
  2348. }
  2349. BOOL
  2350. CALLBACK
  2351. CatalogListCallback(
  2352. IN PCWSTR Directory OPTIONAL,
  2353. IN PCWSTR FilePath
  2354. )
  2355. /*++
  2356. Routine Description:
  2357. This is the callback function for enumerating catalogs in a directory.
  2358. Arguments:
  2359. Directory - If not NULL or empty, it will be prepended to FilePath to build the file path
  2360. FilePath - Path (including file name) to the file to verify
  2361. Return value:
  2362. TRUE if the file is a catalog, FALSE otherwise.
  2363. --*/
  2364. {
  2365. BOOL bRet = FALSE;
  2366. PWSTR szPath = NULL;
  2367. DWORD Error;
  2368. if(NULL == FilePath || 0 == FilePath[0]) {
  2369. goto exit;
  2370. }
  2371. if(Directory != NULL && Directory[0] != 0) {
  2372. szPath = MyMalloc(MAX_PATH * sizeof(WCHAR));
  2373. if(NULL == szPath) {
  2374. goto exit;
  2375. }
  2376. wcsncpy(szPath, Directory, MAX_PATH - 1);
  2377. szPath[MAX_PATH - 1] = 0;
  2378. if(!pSetupConcatenatePaths(szPath, FilePath, MAX_PATH, NULL)) {
  2379. goto exit;
  2380. }
  2381. FilePath = szPath;
  2382. }
  2383. bRet = IsCatalogFile(INVALID_HANDLE_VALUE, (PWSTR) FilePath);
  2384. exit:
  2385. if(szPath != NULL) {
  2386. MyFree(szPath);
  2387. }
  2388. return bRet;
  2389. }
  2390. DWORD
  2391. DeleteOldCatalogs(
  2392. VOID
  2393. )
  2394. /*++
  2395. Routine Description:
  2396. This routine deletes the catalogs specified by the ProductCatalogsToUninstall section of syssetup.inf.
  2397. It does not delete any system catalogs (i.e. specified by the ProductCatalogsToInstall section of the same inf) since
  2398. they will be installed after this function completes.
  2399. Arguments:
  2400. None.
  2401. Return Value:
  2402. If successful, the return value is NO_ERROR, otherwise it is a Win32 error
  2403. code indicating the cause of the failure.
  2404. --*/
  2405. {
  2406. DWORD Error = NO_ERROR;
  2407. HINF hInf = INVALID_HANDLE_VALUE;
  2408. HCATADMIN hCatAdmin = NULL;
  2409. PTSTR szCatPath = NULL;
  2410. LIST_ENTRY InstalledCatalogsList;
  2411. LONG lLines;
  2412. LONG i;
  2413. PCWSTR szInstallSection = L"ProductCatalogsToInstall";
  2414. PCWSTR szUninstallSection = L"ProductCatalogsToUninstall";
  2415. InitializeListHead(&InstalledCatalogsList);
  2416. if(!CryptCATAdminAcquireContext(&hCatAdmin, &DriverVerifyGuid, 0)) {
  2417. Error = GetLastError();
  2418. goto exit;
  2419. }
  2420. //
  2421. // Uninstall exception package catalogs first; this could cleanup the list of installed catalogs a bit
  2422. //
  2423. SpUninstallExcepPackCatalogs(hCatAdmin);
  2424. szCatPath = (PTSTR) MyMalloc(MAX_PATH * sizeof(TCHAR));
  2425. if(NULL == szCatPath) {
  2426. Error = ERROR_NOT_ENOUGH_MEMORY;
  2427. goto exit;
  2428. }
  2429. //
  2430. // Build the list of installed catalogs
  2431. //
  2432. GetWindowsDirectory(szCatPath, MAX_PATH);
  2433. if(!pSetupConcatenatePaths(szCatPath, FILEUTIL_HORRIBLE_PATHNAME, MAX_PATH, NULL)) {
  2434. Error = ERROR_BAD_PATHNAME;
  2435. goto exit;
  2436. }
  2437. Error = BuildFileListFromDir(szCatPath, NULL, 0, FILE_ATTRIBUTE_DIRECTORY, CatalogListCallback, &InstalledCatalogsList);
  2438. if(Error != ERROR_SUCCESS) {
  2439. goto exit;
  2440. }
  2441. //
  2442. // Remove the system catalogs from the installed catalogs list since we don't want to delete them
  2443. //
  2444. hInf = SetupOpenInfFile(L"syssetup.inf", NULL, INF_STYLE_WIN4, NULL);
  2445. if(INVALID_HANDLE_VALUE == hInf) {
  2446. Error = GetLastError();
  2447. goto exit;
  2448. }
  2449. lLines = SetupGetLineCount(hInf, szInstallSection);
  2450. for(i = 0; i < lLines; ++i) {
  2451. INFCONTEXT ctx;
  2452. PCWSTR szCatName;
  2453. PSTRING_LIST_ENTRY pString;
  2454. if(!SetupGetLineByIndex(hInf, szInstallSection, i, &ctx)) {
  2455. Error = GetLastError();
  2456. goto exit;
  2457. }
  2458. szCatName = pSetupGetField(&ctx, 1);
  2459. if(NULL == szCatName) {
  2460. Error = GetLastError();
  2461. goto exit;
  2462. }
  2463. pString = SearchStringInList(&InstalledCatalogsList, szCatName, FALSE);
  2464. if(pString != NULL) {
  2465. RemoveEntryList(&pString->Entry);
  2466. FreeStringEntry(&pString->Entry, TRUE);
  2467. }
  2468. }
  2469. if(InstalledCatalogsList.Flink == &InstalledCatalogsList) {
  2470. //
  2471. // No catalogs left
  2472. //
  2473. goto exit;
  2474. }
  2475. //
  2476. // Uninstall every catalog in the uninstall list
  2477. //
  2478. lLines = SetupGetLineCount(hInf, szUninstallSection);
  2479. for(i = 0; i < lLines; ++i) {
  2480. INFCONTEXT ctx;
  2481. PCWSTR szCatName;
  2482. PCWSTR szAttribName;
  2483. PCWSTR szAttribValue;
  2484. if(!SetupGetLineByIndex(hInf, szUninstallSection, i, &ctx)) {
  2485. Error = GetLastError();
  2486. goto exit;
  2487. }
  2488. szCatName = pSetupGetField(&ctx, 1);
  2489. if(NULL == szCatName) {
  2490. Error = GetLastError();
  2491. goto exit;
  2492. }
  2493. szAttribName = pSetupGetField(&ctx, 2);
  2494. szAttribValue = pSetupGetField(&ctx, 3);
  2495. if(0 == szCatName[0]) {
  2496. PLIST_ENTRY pEntry;
  2497. //
  2498. // If the name is not specified, an attribute or a value must be specified
  2499. //
  2500. if((NULL == szAttribName || 0 == szAttribName[0]) && (NULL == szAttribValue || 0 == szAttribValue[0])) {
  2501. Error = ERROR_INVALID_DATA;
  2502. goto exit;
  2503. }
  2504. //
  2505. // Uninstall every catalog with the attribute name/value specified
  2506. //
  2507. pEntry = InstalledCatalogsList.Flink;
  2508. while(pEntry != &InstalledCatalogsList) {
  2509. //
  2510. // Save Flink since SpUninstallCatalog might destroy pEntry
  2511. //
  2512. PLIST_ENTRY Flink = pEntry->Flink;
  2513. PSTRING_LIST_ENTRY pString = CONTAINING_RECORD(pEntry, STRING_LIST_ENTRY, Entry);
  2514. SpUninstallCatalog(hCatAdmin, pString->String, szCatPath, szAttribName, szAttribValue, &InstalledCatalogsList);
  2515. pEntry = Flink;
  2516. }
  2517. } else {
  2518. SpUninstallCatalog(hCatAdmin, szCatName, szCatPath, szAttribName, szAttribValue, &InstalledCatalogsList);
  2519. }
  2520. }
  2521. exit:
  2522. FreeStringList(&InstalledCatalogsList);
  2523. if(szCatPath != NULL) {
  2524. MyFree(szCatPath);
  2525. }
  2526. if(NULL != hCatAdmin) {
  2527. CryptCATAdminReleaseContext(hCatAdmin, 0);
  2528. }
  2529. if(hInf != INVALID_HANDLE_VALUE) {
  2530. SetupCloseInfFile(hInf);
  2531. }
  2532. return Error;
  2533. }
  2534. VOID
  2535. GetDllCacheFolder(
  2536. OUT LPWSTR CacheDir,
  2537. IN DWORD cbCacheDir
  2538. )
  2539. {
  2540. DWORD retval;
  2541. DWORD Type,Length;
  2542. PWSTR RegData;
  2543. if ((retval = QueryValueInHKLM(
  2544. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  2545. L"SFCDllCacheDir",
  2546. &Type,
  2547. (PVOID)&RegData,
  2548. &Length)) != NO_ERROR) {
  2549. ExpandEnvironmentStrings(
  2550. L"%systemroot%\\system32\\dllcache",
  2551. CacheDir,
  2552. cbCacheDir );
  2553. } else {
  2554. ExpandEnvironmentStrings(
  2555. RegData,
  2556. CacheDir,
  2557. cbCacheDir );
  2558. MyFree(RegData);
  2559. }
  2560. }
  2561. DWORD
  2562. CleanOutDllCache(
  2563. VOID
  2564. )
  2565. /*++
  2566. Routine Description:
  2567. This routine cleans out the current dllcache contents.
  2568. Arguments:
  2569. None.
  2570. Return Value:
  2571. Win32 error code indicating outcome.
  2572. --*/
  2573. {
  2574. DWORD retval = ERROR_SUCCESS, DeleteError = ERROR_SUCCESS;
  2575. WIN32_FIND_DATA FindFileData;
  2576. WCHAR CacheDir[MAX_PATH];
  2577. HANDLE hFind;
  2578. PWSTR p;
  2579. GetDllCacheFolder(CacheDir, MAX_PATH);
  2580. MYASSERT(*CacheDir != L'\0');
  2581. pSetupConcatenatePaths( CacheDir, L"*", MAX_PATH, NULL );
  2582. //
  2583. // save pointer to directory
  2584. //
  2585. p = wcsrchr( CacheDir, L'\\' );
  2586. if (!p) {
  2587. ASSERT(FALSE);
  2588. retval = ERROR_INVALID_DATA;
  2589. goto exit;
  2590. }
  2591. p += 1;
  2592. hFind = FindFirstFile( CacheDir, &FindFileData );
  2593. if (hFind == INVALID_HANDLE_VALUE) {
  2594. retval = GetLastError();
  2595. goto exit;
  2596. }
  2597. do {
  2598. if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  2599. wcscpy( p, FindFileData.cFileName );
  2600. SetFileAttributes( CacheDir, FILE_ATTRIBUTE_NORMAL );
  2601. if (!DeleteFile( CacheDir )) {
  2602. DeleteError = GetLastError();
  2603. }
  2604. }
  2605. } while(FindNextFile( hFind, &FindFileData ));
  2606. FindClose( hFind );
  2607. retval = DeleteError;
  2608. exit:
  2609. return(retval);
  2610. }
  2611. DWORD
  2612. PrepDllCache(
  2613. VOID
  2614. )
  2615. /*++
  2616. Routine Description:
  2617. This routine prepares the dllcache for later on in setup. It cleans out
  2618. the current dllcache contents and copies in a copy of the system catalog
  2619. files.
  2620. Arguments:
  2621. None.
  2622. Return Value:
  2623. If successful, the return value is NO_ERROR, otherwise it is a Win32 error
  2624. code indicating the cause of the failure.
  2625. --*/
  2626. {
  2627. DWORD retval = ERROR_SUCCESS;
  2628. WCHAR CacheDir[MAX_PATH];
  2629. HANDLE h;
  2630. USHORT Compression = COMPRESSION_FORMAT_DEFAULT;
  2631. DWORD Attributes;
  2632. BOOL b = FALSE;
  2633. PWSTR RegData;
  2634. DWORD Type,Length;
  2635. HSPFILEQ hFileQ = INVALID_HANDLE_VALUE;
  2636. PVOID Context;
  2637. DWORD Count,i;
  2638. if (MiniSetup) {
  2639. retval = ERROR_SUCCESS;
  2640. goto e0;
  2641. }
  2642. //
  2643. // clean out old dllcache
  2644. //
  2645. CleanOutDllCache();
  2646. //
  2647. // Configure the registry for the DllCache.
  2648. //
  2649. ConfigureSystemFileProtection();
  2650. //
  2651. // get the path to the dllcache.
  2652. //
  2653. if ((retval = QueryValueInHKLM(
  2654. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  2655. L"SFCDllCacheDir",
  2656. &Type,
  2657. (PVOID)&RegData,
  2658. &Length)) != NO_ERROR) {
  2659. ExpandEnvironmentStrings(
  2660. L"%systemroot%\\system32\\dllcache",
  2661. CacheDir,
  2662. MAX_PATH );
  2663. } else {
  2664. ExpandEnvironmentStrings(
  2665. RegData,
  2666. CacheDir,
  2667. MAX_PATH );
  2668. MyFree(RegData);
  2669. }
  2670. //
  2671. // set attributes on dllcache (hidden, system, compressed...)
  2672. //
  2673. Attributes = GetFileAttributes(CacheDir);
  2674. if (Attributes == 0xffffffff) {
  2675. CreateDirectory( CacheDir, NULL );
  2676. Attributes = GetFileAttributes(CacheDir);
  2677. }
  2678. if (!(Attributes & FILE_ATTRIBUTE_COMPRESSED)) {
  2679. Attributes = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM;
  2680. SetFileAttributes( CacheDir, FILE_ATTRIBUTE_NORMAL );
  2681. h = CreateFile(
  2682. CacheDir,
  2683. GENERIC_READ | GENERIC_WRITE,
  2684. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2685. NULL,
  2686. OPEN_EXISTING,
  2687. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN,
  2688. INVALID_HANDLE_VALUE
  2689. );
  2690. if (h == INVALID_HANDLE_VALUE) {
  2691. SetFileAttributes( CacheDir, Attributes );
  2692. retval = GetLastError();
  2693. goto e0;
  2694. }
  2695. DeviceIoControl(
  2696. h,
  2697. FSCTL_SET_COMPRESSION,
  2698. &Compression,
  2699. sizeof(Compression),
  2700. NULL,
  2701. 0,
  2702. &retval,
  2703. NULL
  2704. );
  2705. CloseHandle( h );
  2706. SetFileAttributes( CacheDir, Attributes );
  2707. }
  2708. //
  2709. // copy system catalogs into the dllcache
  2710. //
  2711. MYASSERT( SyssetupInf != NULL );
  2712. hFileQ = SetupOpenFileQueue();
  2713. if (hFileQ == INVALID_HANDLE_VALUE) {
  2714. retval = GetLastError();
  2715. goto e0;
  2716. }
  2717. Context = InitSysSetupQueueCallbackEx(
  2718. MainWindowHandle,
  2719. INVALID_HANDLE_VALUE,
  2720. 0,
  2721. 0,
  2722. NULL);
  2723. if (!Context) {
  2724. retval = GetLastError();
  2725. goto e1;
  2726. }
  2727. Count = SetupGetLineCount( SyssetupInf, L"ProductCatalogsToInstall");
  2728. for (i = 0; i < Count; i++) {
  2729. INFCONTEXT InfContext;
  2730. WCHAR CatalogName[MAX_PATH];
  2731. BOOL SuccessfullyValidatedOrRestoredACatalog = FALSE;
  2732. if(SetupGetLineByIndex(
  2733. SyssetupInf,
  2734. L"ProductCatalogsToInstall",
  2735. i,
  2736. &InfContext) &&
  2737. (SetupGetStringField(
  2738. &InfContext,
  2739. 1,
  2740. CatalogName,
  2741. sizeof(CatalogName)/sizeof(WCHAR),
  2742. NULL))) {
  2743. if (!SetupQueueCopy(
  2744. hFileQ,
  2745. DuDoesUpdatedFileExist (CatalogName) ? DuGetUpdatesPath () : LegacySourcePath,
  2746. NULL,
  2747. CatalogName,
  2748. NULL,
  2749. NULL,
  2750. CacheDir,
  2751. NULL,
  2752. 0
  2753. )) {
  2754. retval = GetLastError();
  2755. goto e2;
  2756. }
  2757. }
  2758. }
  2759. if (!SetupCommitFileQueue(
  2760. MainWindowHandle,
  2761. hFileQ,
  2762. SysSetupQueueCallback,
  2763. Context)) {
  2764. retval = GetLastError();
  2765. goto e2;
  2766. }
  2767. retval = ERROR_SUCCESS;
  2768. e2:
  2769. TermSysSetupQueueCallback(Context);
  2770. e1:
  2771. SetupCloseFileQueue( hFileQ );
  2772. e0:
  2773. return(retval);
  2774. }
  2775. DWORD
  2776. SpUninstallCatalog(
  2777. IN HCATADMIN CatAdminHandle OPTIONAL,
  2778. IN PCWSTR CatFileName,
  2779. IN PCWSTR CatFilePath OPTIONAL,
  2780. IN PCWSTR AttributeName OPTIONAL,
  2781. IN PCWSTR AttributeValue OPTIONAL,
  2782. IN OUT PLIST_ENTRY InstalledCatalogsList OPTIONAL
  2783. )
  2784. /*++
  2785. Routine Description:
  2786. This function uninstalls the specified catalog based on a list of installed catalogs and a pair of attribute name/value.
  2787. Arguments:
  2788. CatAdminHandle - Handle to crypto context. If NULL, the function will open a context and close it upon exit.
  2789. CatFileName - Name of the catalog (without any path) to be uninstalled.
  2790. CatFilePath - If specified, specifies the path to CatFileName.
  2791. AttributeName - See AttributeValue.
  2792. AttributeValue - If AttributeName and AttributeValue are not specified, the catalog is always uninstalled.
  2793. If AttributeName is specified and AttributeValue isn't, the catalog will be uninstalled only if it has an
  2794. attribute with AttributeName name, regardess of its value. If AttributeName is not specified and AttributeValue is,
  2795. the catalog will be uninstalled only if it has an attribute with AttributeValue value, regardless of its
  2796. name. If both AttributeName and AttributeValue are specified, the catalog is uninstalled only if it
  2797. has an attribute with AttributeName name and AttributeValue value.
  2798. InstalledCatalogsList - If not NULL, contains the list of catalogs installed on the system. If the catalog is not on the list,
  2799. it is not uninstalled. If the catalog is on the list, it is uninstalled and removed from the list. If NULL,
  2800. the catalog is always uninstalled.
  2801. Return value:
  2802. NO_ERROR on success, otherwise a Win32 error code.
  2803. --*/
  2804. {
  2805. DWORD dwError = NO_ERROR;
  2806. HCATADMIN hCatAdmin = CatAdminHandle;
  2807. PSTRING_LIST_ENTRY pEntry = NULL;
  2808. if(NULL == CatFileName || 0 == CatFileName[0]) {
  2809. dwError = ERROR_INVALID_PARAMETER;
  2810. goto exit;
  2811. }
  2812. if(NULL == CatAdminHandle && !CryptCATAdminAcquireContext(&hCatAdmin, &DriverVerifyGuid, 0)) {
  2813. dwError = GetLastError();
  2814. goto exit;
  2815. }
  2816. if(NULL == InstalledCatalogsList || NULL != (pEntry = SearchStringInList(InstalledCatalogsList, CatFileName, FALSE))) {
  2817. BOOL bFound;
  2818. dwError = LookupCatalogAttribute(CatFileName, CatFilePath, AttributeName, AttributeValue, &bFound);
  2819. if(dwError != ERROR_SUCCESS) {
  2820. goto exit;
  2821. }
  2822. if(bFound) {
  2823. if(CryptCATAdminRemoveCatalog(hCatAdmin, (PWCHAR) CatFileName, 0)) {
  2824. if(pEntry != NULL) {
  2825. RemoveEntryList(&pEntry->Entry);
  2826. FreeStringEntry(&pEntry->Entry, TRUE);
  2827. }
  2828. } else {
  2829. dwError = GetLastError();
  2830. SetuplogError(
  2831. LogSevInformation,
  2832. SETUPLOG_USE_MESSAGEID,
  2833. MSG_LOG_SYSSETUP_CATALOG_NOT_DELETED,
  2834. CatFileName,
  2835. NULL,
  2836. NULL
  2837. );
  2838. }
  2839. }
  2840. }
  2841. exit:
  2842. if(NULL == CatAdminHandle && hCatAdmin != NULL) {
  2843. CryptCATAdminReleaseContext(hCatAdmin, 0);
  2844. }
  2845. return dwError;
  2846. }
  2847. typedef struct _UNINSTALL_EXCEPPACK_CATALOG_CONTEXT {
  2848. HCATADMIN CatAdminHandle;
  2849. } UNINSTALL_EXCEPPACK_CATALOG_CONTEXT, * PUNINSTALL_EXCEPPACK_CATALOG_CONTEXT;
  2850. BOOL
  2851. CALLBACK
  2852. SpUninstallExcepPackCatalogsCallback(
  2853. IN const PSETUP_OS_COMPONENT_DATA SetupOsComponentData,
  2854. IN const PSETUP_OS_EXCEPTION_DATA SetupOsExceptionData,
  2855. IN OUT DWORD_PTR Context
  2856. )
  2857. /*++
  2858. Routine Description:
  2859. This is the callback function for the SetupEnumerateRegisteredOsComponents call in SpUninstallExcepPackCatalogs.
  2860. It uninstalls the catalog specified by SetupOsExceptionData->CatalogFileName.
  2861. Arguments:
  2862. SetupOsComponentData - component data
  2863. SetupOsExceptionData - exception pack data
  2864. Context - pointer to an UNINSTALL_EXCEPPACK_CATALOG_CONTEXT struct
  2865. Return value:
  2866. TRUE to continue the enumeration
  2867. --*/
  2868. {
  2869. PUNINSTALL_EXCEPPACK_CATALOG_CONTEXT pContext;
  2870. PCWSTR szCatName;
  2871. ASSERT(Context != 0);
  2872. pContext = (PUNINSTALL_EXCEPPACK_CATALOG_CONTEXT) Context;
  2873. szCatName = wcsrchr(SetupOsExceptionData->CatalogFileName, L'\\');
  2874. ASSERT(szCatName != NULL);
  2875. if(szCatName != NULL) {
  2876. DWORD dwError = SpUninstallCatalog(pContext->CatAdminHandle, szCatName + 1, NULL, NULL, NULL, NULL);
  2877. if(dwError != NO_ERROR) {
  2878. SetupDebugPrint1(L"SETUP: SpUninstallCatalog returned 0x%08x.", dwError);
  2879. }
  2880. }
  2881. return TRUE;
  2882. }
  2883. VOID
  2884. SpUninstallExcepPackCatalogs(
  2885. IN HCATADMIN CatAdminHandle OPTIONAL
  2886. )
  2887. /*++
  2888. Routine Description:
  2889. This function uninstalls all exception package catalogs.
  2890. Arguments:
  2891. CatAdminHandle - a handle to crypto catalog admin; may be NULL
  2892. Return value:
  2893. none
  2894. --*/
  2895. {
  2896. UNINSTALL_EXCEPPACK_CATALOG_CONTEXT Context;
  2897. Context.CatAdminHandle = CatAdminHandle;
  2898. SetupEnumerateRegisteredOsComponents(SpUninstallExcepPackCatalogsCallback, (DWORD_PTR) &Context);
  2899. }