Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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