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.

7970 lines
282 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. fileq4.c
  5. Abstract:
  6. Setup file queue routines for commit (ie, performing enqueued actions).
  7. Author:
  8. Ted Miller (tedm) 15-Feb-1995
  9. Revision History:
  10. Jamie Hunter (jamiehun) 28-Jan-1997
  11. Added backup queue capabilities
  12. backup on demand capabilities
  13. and unwind capabilities
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #define LINK_START (TEXT("<A>"))
  18. #define LINK_END (TEXT("</A>"))
  19. typedef struct _Q_CAB_CB_DATA {
  20. PSP_FILE_QUEUE Queue;
  21. PSOURCE_MEDIA_INFO SourceMedia;
  22. PSP_FILE_QUEUE_NODE CurrentFirstNode;
  23. PVOID MsgHandler;
  24. PVOID Context;
  25. BOOL IsMsgHandlerNativeCharWidth;
  26. PSETUP_LOG_CONTEXT LogContext;
  27. } Q_CAB_CB_DATA, *PQ_CAB_CB_DATA;
  28. typedef struct _CERT_PROMPT {
  29. LPCTSTR lpszDescription;
  30. LPCTSTR lpszFile;
  31. SetupapiVerifyProblem ProblemType;
  32. ULONG DriverSigningPolicy;
  33. } CERT_PROMPT, *PCERT_PROMPT;
  34. typedef struct _AUTHENTICODE_CERT_PROMPT {
  35. LPCTSTR lpszDescription;
  36. HANDLE hWVTStateData;
  37. DWORD Error;
  38. } AUTHENTICODE_CERT_PROMPT, *PAUTHENTICODE_CERT_PROMPT;
  39. typedef struct _DRIVERBLOCK_PROMPT {
  40. LPCTSTR lpszFile;
  41. SDBENTRYINFO entryinfo;
  42. } DRIVERBLOCK_PROMPT, *PDRIVERBLOCK_PROMPT;
  43. DWORD
  44. pSetupCommitSingleBackup(
  45. IN PSP_FILE_QUEUE Queue,
  46. IN PCTSTR FullTargetPath,
  47. IN LONG TargetRootPath,
  48. IN LONG TargetSubDir,
  49. IN LONG TargetFilename,
  50. IN PVOID MsgHandler,
  51. IN PVOID Context,
  52. IN BOOL IsMsgHandlerNativeCharWidth,
  53. IN BOOL RenameExisting,
  54. OUT PBOOL InUse
  55. );
  56. DWORD
  57. pCommitCopyQueue(
  58. IN PSP_FILE_QUEUE Queue,
  59. IN PVOID MsgHandler,
  60. IN PVOID Context,
  61. IN BOOL IsMsgHandlerNativeCharWidth
  62. );
  63. DWORD
  64. pCommitBackupQueue(
  65. IN PSP_FILE_QUEUE Queue,
  66. IN PVOID MsgHandler,
  67. IN PVOID Context,
  68. IN BOOL IsMsgHandlerNativeCharWidth
  69. );
  70. DWORD
  71. pCommitDeleteQueue(
  72. IN PSP_FILE_QUEUE Queue,
  73. IN PVOID MsgHandler,
  74. IN PVOID Context,
  75. IN BOOL IsMsgHandlerNativeCharWidth
  76. );
  77. DWORD
  78. pCommitRenameQueue(
  79. IN PSP_FILE_QUEUE Queue,
  80. IN PVOID MsgHandler,
  81. IN PVOID Context,
  82. IN BOOL IsMsgHandlerNativeCharWidth
  83. );
  84. UINT
  85. pSetupCabinetQueueCallback(
  86. IN PVOID Context,
  87. IN UINT Notification,
  88. IN UINT_PTR Param1,
  89. IN UINT_PTR Param2
  90. );
  91. DWORD
  92. pSetupCopySingleQueuedFile(
  93. IN PSP_FILE_QUEUE Queue,
  94. IN PSP_FILE_QUEUE_NODE QueueNode,
  95. IN PCTSTR FullSourceName,
  96. IN PVOID MsgHandler,
  97. IN PVOID Context,
  98. OUT PTSTR NewSourcePath,
  99. IN BOOL IsMsgHandlerNativeCharWidth,
  100. IN DWORD CopyStyleFlags
  101. );
  102. DWORD
  103. pSetupCopySingleQueuedFileCabCase(
  104. IN PSP_FILE_QUEUE Queue,
  105. IN PSP_FILE_QUEUE_NODE QueueNode,
  106. IN PCTSTR CabinetName,
  107. IN PCTSTR FullSourceName,
  108. IN PVOID MsgHandler,
  109. IN PVOID Context,
  110. IN BOOL IsMsgHandlerNativeCharWidth
  111. );
  112. VOID
  113. pSetupSetPathOverrides(
  114. IN PVOID StringTable,
  115. IN OUT PTSTR RootPath,
  116. IN OUT PTSTR SubPath,
  117. IN LONG RootPathId,
  118. IN LONG SubPathId,
  119. IN PTSTR NewPath
  120. );
  121. VOID
  122. pSetupBuildSourceForCopy(
  123. IN PCTSTR UserRoot,
  124. IN PCTSTR UserPath,
  125. IN LONG MediaRoot,
  126. IN PSP_FILE_QUEUE Queue,
  127. IN PSP_FILE_QUEUE_NODE QueueNode,
  128. OUT PTSTR FullPath
  129. );
  130. INT_PTR
  131. CALLBACK
  132. CertifyDlgProc(
  133. IN HWND hwnd,
  134. IN UINT msg,
  135. IN WPARAM wParam,
  136. IN LPARAM lParam
  137. );
  138. INT_PTR
  139. CALLBACK
  140. AuthenticodeCertifyDlgProc(
  141. IN HWND hwnd,
  142. IN UINT msg,
  143. IN WPARAM wParam,
  144. IN LPARAM lParam
  145. );
  146. INT_PTR
  147. CALLBACK
  148. NoAuthenticodeCertifyDlgProc(
  149. IN HWND hwnd,
  150. IN UINT msg,
  151. IN WPARAM wParam,
  152. IN LPARAM lParam
  153. );
  154. INT_PTR
  155. CALLBACK
  156. DriverBlockDlgProc(
  157. IN HWND hwnd,
  158. IN UINT msg,
  159. IN WPARAM wParam,
  160. IN LPARAM lParam
  161. );
  162. VOID
  163. RestoreBootReplacedFile(
  164. IN PSP_FILE_QUEUE Queue,
  165. IN PSP_FILE_QUEUE_NODE QueueNode
  166. );
  167. VOID
  168. pSetupExemptFileFromProtection(
  169. IN PCTSTR FileName,
  170. IN DWORD FileChangeFlags,
  171. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  172. OUT PDWORD QueueNodeFlags OPTIONAL
  173. );
  174. VOID
  175. pSetupUninstallNewCatalogNodes(
  176. IN PSP_FILE_QUEUE Queue,
  177. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  178. );
  179. BOOL
  180. _SetupCommitFileQueue(
  181. IN HWND Owner, OPTIONAL
  182. IN HSPFILEQ QueueHandle,
  183. IN PVOID MsgHandler,
  184. IN PVOID Context,
  185. IN BOOL IsMsgHandlerNativeCharWidth
  186. )
  187. /*++
  188. Routine Description:
  189. Implementation for SetupCommitFileQueue; handles ANSI and Unicode
  190. callback routines.
  191. Arguments:
  192. Same as for SetupCommitFileQueue().
  193. IsMsgHandlerNativeCharWidth - indicates whether the MsgHandler callback
  194. expects native char width args (or ansi ones, in the unicode build
  195. of this dll).
  196. Return Value:
  197. Boolean value indicating outcome. If FALSE, the GetLastError() indicates
  198. cause of failure.
  199. --*/
  200. {
  201. PSP_FILE_QUEUE Queue;
  202. DWORD rc;
  203. BOOL Success = TRUE;
  204. BOOL ChangedThreadLogContext = FALSE;
  205. PSETUP_LOG_CONTEXT SavedLogContext = NULL;
  206. PSETUP_LOG_CONTEXT LogContext = NULL;
  207. //
  208. // Queue handle is actually a pointer to the queue structure.
  209. //
  210. Queue = (PSP_FILE_QUEUE)QueueHandle;
  211. //
  212. // do a quick handle validation before anything else
  213. //
  214. try {
  215. Success = ((Queue != NULL) && (Queue != INVALID_HANDLE_VALUE) && (Queue->Signature == SP_FILE_QUEUE_SIG));
  216. if (Success) {
  217. LogContext = Queue->LogContext;
  218. }
  219. } except (EXCEPTION_EXECUTE_HANDLER) {
  220. Success = FALSE;
  221. }
  222. if (!Success) {
  223. SetLastError(ERROR_INVALID_HANDLE);
  224. return FALSE;
  225. }
  226. //
  227. // If there's nothing to do, bail now. This prevents an empty
  228. // progress dialog from flashing on the screen. Don't return out
  229. // of the body of the try -- that is bad news performance-wise.
  230. //
  231. try {
  232. Success = (!Queue->DeleteNodeCount && !Queue->RenameNodeCount && !Queue->CopyNodeCount && !Queue->BackupNodeCount);
  233. } except (EXCEPTION_EXECUTE_HANDLER) {
  234. SetLastError(ERROR_INVALID_HANDLE);
  235. return(FALSE);
  236. }
  237. if(Success) {
  238. //
  239. // We are successful in that we had no file operations to do. However,
  240. // we still need to validate the queued catalogs at this time, because
  241. // we always do validation in the context of file copying. If we don't
  242. // do this, we have a hole where a device INF that doesn't copy files
  243. // (e.g., a modem INF) can circumvent driver signing checking.
  244. //
  245. WriteLogEntry(
  246. LogContext,
  247. SETUP_LOG_TIME,
  248. MSG_LOG_BEGIN_VERIFY3_CAT_TIME,
  249. NULL); // text message
  250. rc = _SetupVerifyQueuedCatalogs(Owner,
  251. Queue,
  252. VERCAT_INSTALL_INF_AND_CAT,
  253. NULL,
  254. NULL
  255. );
  256. WriteLogEntry(
  257. LogContext,
  258. SETUP_LOG_TIME,
  259. MSG_LOG_END_VERIFY3_CAT_TIME,
  260. NULL); // text message
  261. if (rc == NO_ERROR) {
  262. //
  263. // If we performed a backup and this is a device install then call
  264. // the pSetupCompleteBackup API to create the Reinstall instance
  265. // subkey and do other device rollback cleanup.
  266. //
  267. if (Queue->Flags & FQF_DEVICE_BACKUP) {
  268. pSetupCompleteBackup(Queue);
  269. }
  270. Queue->Flags |= FQF_QUEUE_ALREADY_COMMITTED;
  271. } else {
  272. //
  273. // Go uninstall any newly-copied INFs/PNFs/CATs.
  274. //
  275. pSetupUninstallNewCatalogNodes(Queue, LogContext);
  276. }
  277. SetLastError(rc);
  278. return(rc == NO_ERROR);
  279. }
  280. ASSERT_HEAP_IS_VALID();
  281. //
  282. // make a note of default logging context for duration of queue processing
  283. // this will catch, eg, INF being opened as part of a callback
  284. //
  285. MYASSERT(!ChangedThreadLogContext);
  286. ChangedThreadLogContext = SetThreadLogContext(LogContext,&SavedLogContext);
  287. if (ChangedThreadLogContext) {
  288. //
  289. // add one more ref to protext log context
  290. //
  291. RefLogContext(LogContext);
  292. }
  293. Success = pSetupCallMsgHandler(
  294. LogContext,
  295. MsgHandler,
  296. IsMsgHandlerNativeCharWidth,
  297. Context,
  298. SPFILENOTIFY_STARTQUEUE,
  299. (UINT_PTR)Owner,
  300. 0
  301. );
  302. if(!Success) {
  303. rc = GetLastError();
  304. if(!rc) {
  305. rc = ERROR_OPERATION_ABORTED;
  306. }
  307. goto final;
  308. }
  309. try {
  310. //
  311. // Verify catalogs/infs.
  312. //
  313. WriteLogEntry(
  314. LogContext,
  315. SETUP_LOG_TIME,
  316. MSG_LOG_BEGIN_VERIFY2_CAT_TIME,
  317. NULL); // text message
  318. rc = _SetupVerifyQueuedCatalogs(Owner,
  319. Queue,
  320. VERCAT_INSTALL_INF_AND_CAT,
  321. NULL,
  322. NULL
  323. );
  324. WriteLogEntry(
  325. LogContext,
  326. SETUP_LOG_TIME,
  327. MSG_LOG_END_VERIFY2_CAT_TIME,
  328. NULL); // text message
  329. Success = (rc == NO_ERROR);
  330. if(rc != NO_ERROR) {
  331. goto Bail;
  332. }
  333. ASSERT_HEAP_IS_VALID();
  334. //
  335. // Handle backup first
  336. // don't commit if there's nothing to do
  337. //
  338. rc = Queue->BackupNodeCount
  339. ? pCommitBackupQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  340. : NO_ERROR;
  341. Success = (rc == NO_ERROR);
  342. ASSERT_HEAP_IS_VALID();
  343. if (!Success) {
  344. goto Bail;
  345. }
  346. //
  347. // Handle deletes
  348. // now done after backups, but may incorporate a per-delete backup
  349. // don't commit if there's nothing to do
  350. //
  351. rc = Queue->DeleteNodeCount
  352. ? pCommitDeleteQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  353. : NO_ERROR;
  354. Success = (rc == NO_ERROR);
  355. ASSERT_HEAP_IS_VALID();
  356. if (!Success) {
  357. goto Bail;
  358. }
  359. //
  360. // Handle renames next.
  361. // don't commit if there's nothing to do
  362. //
  363. rc = Queue->RenameNodeCount
  364. ? pCommitRenameQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  365. : NO_ERROR;
  366. Success = (rc == NO_ERROR);
  367. ASSERT_HEAP_IS_VALID();
  368. if (!Success) {
  369. goto Bail;
  370. }
  371. //
  372. // Handle copies last. Don't bother calling the copy commit routine
  373. // if there are no files to copy.
  374. //
  375. rc = Queue->CopyNodeCount
  376. ? pCommitCopyQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  377. : NO_ERROR;
  378. Success = (rc == NO_ERROR);
  379. ASSERT_HEAP_IS_VALID();
  380. if (!Success) {
  381. goto Bail;
  382. }
  383. rc = DoAllDelayedMoves(Queue);
  384. Success = (rc == NO_ERROR);
  385. if(Success) {
  386. //
  387. // Set a flag indicating we've committed the file queue (used to keep
  388. // us from attempting to prune the queue after having committed it).
  389. //
  390. Queue->Flags |= FQF_QUEUE_ALREADY_COMMITTED;
  391. }
  392. //
  393. // If we performed a backup and this is a device install then call
  394. // the pSetupCompleteBackup API to create the Reinstall instance
  395. // subkey and do other device rollback cleanup.
  396. //
  397. if (Queue->Flags & FQF_DEVICE_BACKUP) {
  398. pSetupCompleteBackup(Queue);
  399. }
  400. Bail:
  401. ;
  402. } except(EXCEPTION_EXECUTE_HANDLER) {
  403. Success = FALSE;
  404. rc = ERROR_INVALID_DATA;
  405. }
  406. pSetupCallMsgHandler(
  407. LogContext,
  408. MsgHandler,
  409. IsMsgHandlerNativeCharWidth,
  410. Context,
  411. SPFILENOTIFY_ENDQUEUE,
  412. Success,
  413. 0
  414. );
  415. pSetupUnwindAll(Queue, Success);
  416. final:
  417. //
  418. // If we didn't succeed, then uninstall any new INFs/PNFs/CATs we may have
  419. // installed.
  420. //
  421. if(!Success) {
  422. pSetupUninstallNewCatalogNodes(Queue, LogContext);
  423. }
  424. if (ChangedThreadLogContext) {
  425. //
  426. // restore thread log context
  427. //
  428. SetThreadLogContext(SavedLogContext,NULL);
  429. DeleteLogContext(LogContext); // counter RefLogContext
  430. }
  431. SetLastError(rc);
  432. return(Success);
  433. }
  434. //
  435. // ANSI version. Also need undecorated (Unicode) version for compatibility
  436. // with apps that were linked before we had A and W versions.
  437. //
  438. BOOL
  439. SetupCommitFileQueueA(
  440. IN HWND Owner, OPTIONAL
  441. IN HSPFILEQ QueueHandle,
  442. IN PSP_FILE_CALLBACK_A MsgHandler,
  443. IN PVOID Context
  444. )
  445. {
  446. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,FALSE));
  447. }
  448. #undef SetupCommitFileQueue
  449. SetupCommitFileQueue(
  450. IN HWND Owner, OPTIONAL
  451. IN HSPFILEQ QueueHandle,
  452. IN PSP_FILE_CALLBACK_W MsgHandler,
  453. IN PVOID Context
  454. )
  455. {
  456. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,TRUE));
  457. }
  458. BOOL
  459. SetupCommitFileQueueW(
  460. IN HWND Owner, OPTIONAL
  461. IN HSPFILEQ QueueHandle,
  462. IN PSP_FILE_CALLBACK MsgHandler,
  463. IN PVOID Context
  464. )
  465. /*++
  466. Routine Description:
  467. Perform file operations enqueued on a setup file queue.
  468. Arguments:
  469. OwnerWindow - if specified, supplies the window handle of a window
  470. that is to be used as the parent of any progress dialogs.
  471. QueueHandle - supplies a handle to a setup file queue, as returned
  472. by SetupOpenFileQueue.
  473. MsgHandler - Supplies a callback routine to be notified
  474. of various significant events in the queue processing.
  475. Context - Supplies a value that is passed to the MsgHandler
  476. callback function.
  477. Return Value:
  478. Boolean value indicating outcome.
  479. --*/
  480. {
  481. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,TRUE));
  482. }
  483. DWORD
  484. pCommitBackupQueue(
  485. IN PSP_FILE_QUEUE Queue,
  486. IN PVOID MsgHandler,
  487. IN PVOID Context,
  488. IN BOOL IsMsgHandlerNativeCharWidth
  489. )
  490. /*++
  491. Routine Description:
  492. Process the backup Queue
  493. Backup each file specified in the queue if it exists
  494. File is marked as backup
  495. Location of backup is recorded
  496. Files are not added to unwind queue here
  497. They get added to unwind queue the first time they are potentially modified
  498. See also pCommitDeleteQueue, pCommitRenameQueue and pCommitCopyQueue
  499. Arguments:
  500. Queue - queue that contains the backup sub-queue
  501. MsgHandler - Supplies a callback routine to be notified
  502. of various significant events in the queue processing.
  503. Context - Supplies a value that is passed to the MsgHandler
  504. callback function.
  505. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  506. Return Value:
  507. DWORD indicating status or success
  508. --*/
  509. {
  510. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  511. UINT u;
  512. BOOL b;
  513. DWORD rc;
  514. PCTSTR FullTargetPath,FullBackupPath;
  515. FILEPATHS FilePaths;
  516. BOOL Skipped = FALSE;
  517. DWORD BackupFlags = SP_BACKUP_BACKUPPASS;
  518. MYASSERT(Queue->BackupNodeCount);
  519. b = pSetupCallMsgHandler(
  520. Queue->LogContext,
  521. MsgHandler,
  522. IsMsgHandlerNativeCharWidth,
  523. Context,
  524. SPFILENOTIFY_STARTSUBQUEUE,
  525. FILEOP_BACKUP,
  526. Queue->BackupNodeCount
  527. );
  528. if(!b) {
  529. rc = GetLastError();
  530. if(!rc) {
  531. rc = ERROR_OPERATION_ABORTED;
  532. }
  533. goto clean0;
  534. }
  535. for(QueueNode=Queue->BackupQueue; QueueNode; QueueNode=QueueNode->Next) {
  536. //
  537. // Form the full path of the file to be backed up
  538. //
  539. FullBackupPath = pSetupFormFullPath(
  540. Queue->StringTable,
  541. QueueNode->SourceRootPath,
  542. QueueNode->SourcePath,
  543. QueueNode->SourceFilename
  544. );
  545. if(!FullBackupPath) {
  546. rc = ERROR_NOT_ENOUGH_MEMORY;
  547. goto clean0;
  548. }
  549. FullTargetPath = pSetupFormFullPath(
  550. Queue->StringTable,
  551. QueueNode->TargetDirectory,
  552. QueueNode->TargetFilename,
  553. -1
  554. );
  555. if(!FullTargetPath) {
  556. MyFree(FullBackupPath);
  557. rc = ERROR_NOT_ENOUGH_MEMORY;
  558. goto clean0;
  559. }
  560. FilePaths.Source = FullTargetPath; // copying from
  561. FilePaths.Target = FullBackupPath; // copying to (backup)
  562. FilePaths.Win32Error = NO_ERROR;
  563. FilePaths.Flags = BackupFlags;
  564. Skipped = FALSE;
  565. //
  566. // Inform the callback that we are about to start a backup operation.
  567. //
  568. u = pSetupCallMsgHandler(
  569. Queue->LogContext,
  570. MsgHandler,
  571. IsMsgHandlerNativeCharWidth,
  572. Context,
  573. SPFILENOTIFY_STARTBACKUP,
  574. (UINT_PTR)&FilePaths,
  575. FILEOP_BACKUP
  576. );
  577. if(u == FILEOP_ABORT) {
  578. rc = GetLastError();
  579. if(!rc) {
  580. rc = ERROR_OPERATION_ABORTED;
  581. }
  582. MyFree(FullTargetPath);
  583. MyFree(FullBackupPath);
  584. goto clean0;
  585. }
  586. if(u == FILEOP_DOIT) {
  587. //
  588. // Attempt the backup. If it fails inform the callback,
  589. // which may decide to abort, retry. or skip the file.
  590. //
  591. //SetFileAttributes(FullTargetPath,FILE_ATTRIBUTE_NORMAL);
  592. do {
  593. rc = pSetupBackupFile((HSPFILEQ)Queue,
  594. FullTargetPath,
  595. FullBackupPath,
  596. -1, // TargetID not known
  597. QueueNode->TargetDirectory, // what to backup
  598. -1, // Queue Node's don't maintain this intermediate path
  599. QueueNode->TargetFilename,
  600. QueueNode->SourceRootPath, // backup as...
  601. QueueNode->SourcePath,
  602. QueueNode->SourceFilename,
  603. &b
  604. );
  605. if (rc == NO_ERROR) {
  606. if (b) {
  607. // delayed (in use)
  608. QueueNode->InternalFlags |= INUSE_IN_USE;
  609. //
  610. // Tell the callback.
  611. //
  612. FilePaths.Win32Error = NO_ERROR;
  613. FilePaths.Flags = FILEOP_BACKUP;
  614. pSetupCallMsgHandler(
  615. Queue->LogContext,
  616. MsgHandler,
  617. IsMsgHandlerNativeCharWidth,
  618. Context,
  619. SPFILENOTIFY_FILEOPDELAYED,
  620. (UINT_PTR)&FilePaths,
  621. 0
  622. );
  623. }
  624. } else {
  625. FilePaths.Win32Error = rc;
  626. FilePaths.Flags = BackupFlags;
  627. u = pSetupCallMsgHandler(
  628. Queue->LogContext,
  629. MsgHandler,
  630. IsMsgHandlerNativeCharWidth,
  631. Context,
  632. SPFILENOTIFY_BACKUPERROR,
  633. (UINT_PTR)&FilePaths,
  634. 0
  635. );
  636. if(u == FILEOP_ABORT) {
  637. rc = GetLastError();
  638. if(!rc) {
  639. rc = ERROR_OPERATION_ABORTED;
  640. }
  641. MyFree(FullTargetPath);
  642. MyFree(FullBackupPath);
  643. goto clean0;
  644. }
  645. if(u == FILEOP_SKIP) {
  646. // we skipped the backup
  647. Skipped = TRUE;
  648. break;
  649. }
  650. }
  651. } while(rc != NO_ERROR);
  652. } else {
  653. // we skipped the backup
  654. Skipped = TRUE;
  655. rc = NO_ERROR;
  656. }
  657. FilePaths.Win32Error = rc;
  658. FilePaths.Flags = BackupFlags;
  659. pSetupCallMsgHandler(
  660. Queue->LogContext,
  661. MsgHandler,
  662. IsMsgHandlerNativeCharWidth,
  663. Context,
  664. SPFILENOTIFY_ENDBACKUP,
  665. (UINT_PTR)&FilePaths,
  666. 0
  667. );
  668. MyFree(FullTargetPath);
  669. MyFree(FullBackupPath);
  670. }
  671. pSetupCallMsgHandler(
  672. Queue->LogContext,
  673. MsgHandler,
  674. IsMsgHandlerNativeCharWidth,
  675. Context,
  676. SPFILENOTIFY_ENDSUBQUEUE,
  677. FILEOP_BACKUP,
  678. 0
  679. );
  680. rc = NO_ERROR;
  681. clean0:
  682. SetLastError(rc);
  683. return rc;
  684. }
  685. DWORD
  686. pSetupCommitSingleBackup(
  687. IN PSP_FILE_QUEUE Queue,
  688. IN PCTSTR FullTargetPath,
  689. IN LONG TargetRootPath,
  690. IN LONG TargetSubDir,
  691. IN LONG TargetFilename,
  692. IN PVOID MsgHandler,
  693. IN PVOID Context,
  694. IN BOOL IsMsgHandlerNativeCharWidth,
  695. IN BOOL RenameExisting,
  696. OUT PBOOL InUse
  697. )
  698. /*++
  699. Routine Description:
  700. Check a single file that is potentially about to be modified
  701. If the target file doesn't exist, then this routine does nothing
  702. If the target file hasn't been backed up, back it up
  703. If the target file has been backed up, but is not on unwind queue,
  704. add to unwind queue
  705. The default target location of the backup is used, which is either
  706. into a backup directory tree, or a temporary backup location
  707. Location of backup is recorded
  708. Arguments:
  709. Queue - queue that contains the backup sub-queue
  710. FullTargetPath - String giving target path, or NULL if not formed
  711. TargetRootPath - String ID giving RootPath, or -1 if not specified
  712. TargetSubDir - String ID giving SubDir (relative to RootPath),
  713. or -1 if not specified
  714. TargetFilename - String ID giving Filename, or -1 if not specified
  715. MsgHandler - Supplies a callback routine to be notified
  716. of various significant events in the queue processing.
  717. Context - Supplies a value that is passed to the MsgHandler
  718. callback function.
  719. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  720. RenameExisting - Should existing file be renamed?
  721. InUse - if specified, set to indicate if file is in use or not
  722. This should never be the case
  723. Return Value:
  724. DWORD indicating status or success
  725. --*/
  726. {
  727. UINT u;
  728. BOOL b;
  729. DWORD rc;
  730. DWORD rc2;
  731. FILEPATHS FilePaths;
  732. LONG TargetID;
  733. PTSTR TargetPathLocal = NULL;
  734. PSP_UNWIND_NODE UnwindNode = NULL;
  735. SP_TARGET_ENT TargetInfo;
  736. BOOL FileOfSameNameExists;
  737. BOOL DoBackup = TRUE;
  738. BOOL NeedUnwind = FALSE;
  739. BOOL Skipped = FALSE;
  740. WIN32_FILE_ATTRIBUTE_DATA FileAttribData;
  741. UINT OldMode;
  742. BOOL DoRename;
  743. DWORD BackupFlags = SP_BACKUP_DEMANDPASS;
  744. //
  745. // used in this function to init time field
  746. //
  747. static const FILETIME zeroTime = {
  748. 0,0
  749. };
  750. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS); // inhibit unexpected dialog boxes
  751. MYASSERT(Queue);
  752. if (FullTargetPath == NULL) {
  753. TargetPathLocal = pSetupFormFullPath(
  754. Queue->StringTable,
  755. TargetRootPath,
  756. TargetSubDir,
  757. TargetFilename);
  758. if(!TargetPathLocal) {
  759. rc = ERROR_NOT_ENOUGH_MEMORY;
  760. goto clean0;
  761. }
  762. FullTargetPath = TargetPathLocal;
  763. }
  764. FileOfSameNameExists = GetFileAttributesEx(FullTargetPath, GetFileExInfoStandard, &FileAttribData);
  765. if (!FileOfSameNameExists) {
  766. // file doesn't exist, so no need to backup
  767. rc = NO_ERROR;
  768. goto clean0;
  769. }
  770. rc = pSetupBackupGetTargetByPath((HSPFILEQ)Queue,
  771. NULL, // use Queue's string table
  772. FullTargetPath,
  773. TargetRootPath,
  774. TargetSubDir,
  775. TargetFilename,
  776. &TargetID,
  777. &TargetInfo
  778. );
  779. if (rc != NO_ERROR) {
  780. // failed for some strange reason
  781. goto clean0;
  782. }
  783. if (TargetInfo.InternalFlags & SP_TEFLG_INUSE) {
  784. //
  785. // was "inuse'd" before
  786. // we mark as still INUSE
  787. if (InUse != NULL) {
  788. *InUse = TRUE;
  789. }
  790. //
  791. // Don't consider this an error, unless we were supposed to rename the
  792. // existing file.
  793. //
  794. rc = RenameExisting ? ERROR_SHARING_VIOLATION : NO_ERROR;
  795. goto clean0;
  796. }
  797. if (TargetInfo.InternalFlags & SP_TEFLG_SKIPPED) {
  798. //
  799. // was skipped before
  800. // we can't rely on it now
  801. //
  802. rc = NO_ERROR;
  803. goto clean0;
  804. }
  805. //
  806. // If we've been asked to backup the existing file, then make sure the
  807. // SP_TEFLG_RENAMEEXISTING flag is set in the TargetInfo. Also, figure out
  808. // if we've already done the rename.
  809. //
  810. if(RenameExisting &&
  811. !(TargetInfo.InternalFlags & SP_TEFLG_RENAMEEXISTING)) {
  812. //
  813. // We'd better not think we already renamed this file!
  814. //
  815. MYASSERT(!(TargetInfo.InternalFlags & SP_TEFLG_MOVED));
  816. TargetInfo.InternalFlags |= SP_TEFLG_RENAMEEXISTING;
  817. //
  818. // update internal info (this call should never fail)
  819. //
  820. pSetupBackupSetTargetByID((HSPFILEQ)Queue,
  821. TargetID,
  822. &TargetInfo
  823. );
  824. }
  825. //
  826. // Figure out whether we've been asked to rename the existing file to a
  827. // temp name in the same directory, but haven't yet done so.
  828. //
  829. DoRename = ((TargetInfo.InternalFlags & (SP_TEFLG_RENAMEEXISTING | SP_TEFLG_MOVED)) == SP_TEFLG_RENAMEEXISTING);
  830. if(TargetInfo.InternalFlags & SP_TEFLG_SAVED) {
  831. //
  832. // already backed up
  833. //
  834. DoBackup = FALSE;
  835. if((TargetInfo.InternalFlags & SP_TEFLG_UNWIND) && !DoRename) {
  836. //
  837. // already added to unwind queue, and we don't need to do a rename--
  838. // don't need to do anything at all
  839. //
  840. rc = NO_ERROR;
  841. goto clean0;
  842. }
  843. //
  844. // we don't need to backup
  845. // but we still need to add to unwind queue, rename the existing file,
  846. // or both.
  847. //
  848. }
  849. if(DoBackup) {
  850. BackupFlags |= SP_BACKUP_DEMANDPASS;
  851. }
  852. if(DoRename) {
  853. BackupFlags |= SP_BACKUP_BOOTFILE | SP_BACKUP_SPECIAL;
  854. }
  855. FilePaths.Source = FullTargetPath; // what we are backing up
  856. FilePaths.Target = NULL; // indicates an automatic backup
  857. FilePaths.Win32Error = NO_ERROR;
  858. FilePaths.Flags = BackupFlags;
  859. if (DoRename) {
  860. pSetupExemptFileFromProtection(
  861. FullTargetPath,
  862. SFC_ACTION_ADDED | SFC_ACTION_REMOVED | SFC_ACTION_MODIFIED
  863. | SFC_ACTION_RENAMED_OLD_NAME |SFC_ACTION_RENAMED_NEW_NAME,
  864. Queue->LogContext,
  865. NULL
  866. );
  867. }
  868. if (DoBackup && (Queue->Flags & FQF_BACKUP_AWARE)) {
  869. //
  870. // Inform the callback that we are about to start a backup operation.
  871. //
  872. u = pSetupCallMsgHandler(
  873. Queue->LogContext,
  874. MsgHandler,
  875. IsMsgHandlerNativeCharWidth,
  876. Context,
  877. SPFILENOTIFY_STARTBACKUP,
  878. (UINT_PTR)&FilePaths,
  879. FILEOP_BACKUP
  880. );
  881. } else {
  882. //
  883. // no backup, or not backup aware, assume a default
  884. //
  885. u = FILEOP_DOIT;
  886. }
  887. if(u == FILEOP_ABORT) {
  888. rc = GetLastError();
  889. if(!rc) {
  890. rc = ERROR_OPERATION_ABORTED;
  891. }
  892. goto clean0;
  893. }
  894. if((u == FILEOP_DOIT) || (BackupFlags & SP_BACKUP_SPECIAL)) {
  895. //
  896. // Attempt the backup. If it fails inform the callback,
  897. // which may decide to abort, retry. or skip the file.
  898. //
  899. //SetFileAttributes(FullTargetPath,FILE_ATTRIBUTE_NORMAL);
  900. //
  901. // Setup an unwind node, unless we already have one.
  902. //
  903. if(!(TargetInfo.InternalFlags & SP_TEFLG_UNWIND)) {
  904. UnwindNode = MyMalloc(sizeof(SP_UNWIND_NODE));
  905. if (UnwindNode == NULL) {
  906. rc = ERROR_NOT_ENOUGH_MEMORY;
  907. goto clean0;
  908. }
  909. UnwindNode->NextNode = Queue->UnwindQueue;
  910. UnwindNode->TargetID = TargetID;
  911. if (RetreiveFileSecurity( FullTargetPath, &(UnwindNode->SecurityDesc)) != NO_ERROR) {
  912. // failed, but not fatal
  913. UnwindNode->SecurityDesc = NULL;
  914. }
  915. if (GetSetFileTimestamp( FullTargetPath, &(UnwindNode->CreateTime),
  916. &(UnwindNode->AccessTime),
  917. &(UnwindNode->WriteTime),
  918. FALSE) != NO_ERROR) {
  919. // failed, but not fatal
  920. UnwindNode->CreateTime = zeroTime;
  921. UnwindNode->AccessTime = zeroTime;
  922. UnwindNode->WriteTime = zeroTime;
  923. }
  924. }
  925. if (DoBackup || DoRename) {
  926. do {
  927. rc = pSetupBackupFile((HSPFILEQ)Queue,
  928. FullTargetPath, // since we know this, pass it
  929. NULL, // automatic destination
  930. TargetID, // we got this earlier
  931. TargetRootPath, // since we know this, pass it
  932. TargetSubDir,
  933. TargetFilename,
  934. -1, // use the details from TargetID (or temp)
  935. -1,
  936. -1,
  937. &b // in use (should always return FALSE)
  938. );
  939. if (rc == NO_ERROR) {
  940. if (InUse != NULL) {
  941. *InUse = b;
  942. }
  943. if (b) {
  944. //
  945. // if file is in use, callback can decide what to do
  946. //
  947. if (Queue->Flags & FQF_BACKUP_AWARE) {
  948. //
  949. // Tell the callback.
  950. //
  951. FilePaths.Win32Error = ERROR_SHARING_VIOLATION;
  952. FilePaths.Flags = BackupFlags;
  953. if (Queue->Flags & FQF_BACKUP_AWARE) {
  954. u = pSetupCallMsgHandler(
  955. Queue->LogContext,
  956. MsgHandler,
  957. IsMsgHandlerNativeCharWidth,
  958. Context,
  959. SPFILENOTIFY_BACKUPERROR,
  960. (UINT_PTR)&FilePaths,
  961. 0
  962. );
  963. if(u == FILEOP_ABORT) {
  964. rc = GetLastError();
  965. if(!rc) {
  966. rc = ERROR_OPERATION_ABORTED;
  967. }
  968. goto clean0;
  969. }
  970. } else {
  971. rc = ERROR_OPERATION_ABORTED;
  972. goto clean0;
  973. }
  974. }
  975. } else {
  976. //
  977. // success!!!!!
  978. // we would have to unwind this if setup fails
  979. //
  980. NeedUnwind = TRUE;
  981. }
  982. } else {
  983. FilePaths.Win32Error = rc;
  984. FilePaths.Flags = BackupFlags;
  985. if (Queue->Flags & FQF_BACKUP_AWARE) {
  986. //
  987. // inform about error
  988. //
  989. u = pSetupCallMsgHandler(
  990. Queue->LogContext,
  991. MsgHandler,
  992. IsMsgHandlerNativeCharWidth,
  993. Context,
  994. SPFILENOTIFY_BACKUPERROR,
  995. (UINT_PTR)&FilePaths,
  996. 0
  997. );
  998. if(u == FILEOP_ABORT) {
  999. rc = GetLastError();
  1000. if(!rc) {
  1001. rc = ERROR_OPERATION_ABORTED;
  1002. }
  1003. goto clean0;
  1004. }
  1005. } else {
  1006. //
  1007. // if caller is not backup aware, abort
  1008. //
  1009. rc = ERROR_OPERATION_ABORTED;
  1010. goto clean0;
  1011. }
  1012. if(u == FILEOP_SKIP) {
  1013. //
  1014. // we skipped the backup
  1015. //
  1016. Skipped = TRUE;
  1017. break;
  1018. }
  1019. }
  1020. } while(rc != NO_ERROR);
  1021. } else {
  1022. //
  1023. // didn't need to backup, only need to add to unwind queue
  1024. //
  1025. NeedUnwind = TRUE;
  1026. }
  1027. } else {
  1028. //
  1029. // we skipped the backup
  1030. //
  1031. Skipped = TRUE;
  1032. rc = NO_ERROR;
  1033. }
  1034. if (DoBackup) {
  1035. FilePaths.Win32Error = rc;
  1036. if (Queue->Flags & FQF_BACKUP_AWARE) {
  1037. //
  1038. // report result only if backup aware
  1039. //
  1040. pSetupCallMsgHandler(
  1041. Queue->LogContext,
  1042. MsgHandler,
  1043. IsMsgHandlerNativeCharWidth,
  1044. Context,
  1045. SPFILENOTIFY_ENDBACKUP,
  1046. (UINT_PTR)&FilePaths,
  1047. 0
  1048. );
  1049. }
  1050. }
  1051. if (Skipped) {
  1052. //
  1053. // once we return, file may get overwritten or deleted
  1054. // we have to save the fact it has been skipped once
  1055. // so we always skip this file
  1056. //
  1057. if (pSetupBackupGetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo) == NO_ERROR) {
  1058. //
  1059. // flag the file should always be skipped
  1060. //
  1061. TargetInfo.InternalFlags|=SP_TEFLG_SKIPPED;
  1062. pSetupBackupSetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo);
  1063. }
  1064. }
  1065. else if (NeedUnwind) {
  1066. //
  1067. // We only want to add this to unwind queue
  1068. //
  1069. if (pSetupBackupGetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo) == NO_ERROR) {
  1070. if ((TargetInfo.InternalFlags&SP_TEFLG_UNWIND)==FALSE) {
  1071. //
  1072. // node needs to be added to unwind queue
  1073. // we only ever do this once
  1074. //
  1075. Queue->UnwindQueue = UnwindNode;
  1076. //
  1077. // set to NULL so we don't clean it up later
  1078. //
  1079. UnwindNode = NULL;
  1080. //
  1081. // flag that we've added it to unwind queue
  1082. // so we don't try and do it again later
  1083. //
  1084. TargetInfo.InternalFlags|=SP_TEFLG_UNWIND;
  1085. pSetupBackupSetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo);
  1086. }
  1087. }
  1088. }
  1089. rc = NO_ERROR;
  1090. clean0:
  1091. if (UnwindNode != NULL) {
  1092. //
  1093. // we allocated, but didn't use this structure
  1094. //
  1095. if (UnwindNode->SecurityDesc != NULL) {
  1096. MyFree(UnwindNode->SecurityDesc);
  1097. }
  1098. MyFree(UnwindNode);
  1099. }
  1100. if (TargetPathLocal != NULL) {
  1101. MyFree(TargetPathLocal);
  1102. }
  1103. SetErrorMode(OldMode);
  1104. SetLastError(rc);
  1105. return rc;
  1106. }
  1107. DWORD
  1108. pCommitDeleteQueue(
  1109. IN PSP_FILE_QUEUE Queue,
  1110. IN PVOID MsgHandler,
  1111. IN PVOID Context,
  1112. IN BOOL IsMsgHandlerNativeCharWidth
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. Process the delete Queue
  1117. Delete each file specified in the queue
  1118. Files are backed up before they are deleted (if not already backed up)
  1119. See also pCommitBackupQueue, pCommitRenameQueue and pCommitCopyQueue
  1120. Arguments:
  1121. Queue - queue that contains the delete sub-queue
  1122. MsgHandler - Supplies a callback routine to be notified
  1123. of various significant events in the queue processing.
  1124. Context - Supplies a value that is passed to the MsgHandler
  1125. callback function.
  1126. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  1127. Return Value:
  1128. DWORD indicating status or success
  1129. --*/
  1130. {
  1131. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  1132. UINT u;
  1133. BOOL b;
  1134. DWORD rc;
  1135. PCTSTR FullTargetPath;
  1136. FILEPATHS FilePaths;
  1137. BOOL BackupInUse = FALSE;
  1138. BOOL TargetIsProtected;
  1139. MYASSERT(Queue->DeleteNodeCount);
  1140. b = pSetupCallMsgHandler(
  1141. Queue->LogContext,
  1142. MsgHandler,
  1143. IsMsgHandlerNativeCharWidth,
  1144. Context,
  1145. SPFILENOTIFY_STARTSUBQUEUE,
  1146. FILEOP_DELETE,
  1147. Queue->DeleteNodeCount
  1148. );
  1149. if(!b) {
  1150. rc = GetLastError();
  1151. if(!rc) {
  1152. rc = ERROR_OPERATION_ABORTED;
  1153. }
  1154. goto clean0;
  1155. }
  1156. for(QueueNode=Queue->DeleteQueue; QueueNode; QueueNode=QueueNode->Next) {
  1157. //
  1158. // Form the full path of the file to be deleted.
  1159. //
  1160. FullTargetPath = pSetupFormFullPath(
  1161. Queue->StringTable,
  1162. QueueNode->TargetDirectory,
  1163. QueueNode->TargetFilename,
  1164. -1
  1165. );
  1166. if(!FullTargetPath) {
  1167. rc = ERROR_NOT_ENOUGH_MEMORY;
  1168. goto clean0;
  1169. }
  1170. //
  1171. // Backup the file we're about to delete
  1172. //
  1173. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  1174. FullTargetPath,
  1175. LASTGOOD_OPERATION_DELETE,
  1176. NULL)) != NO_ERROR) {
  1177. MyFree(FullTargetPath);
  1178. goto clean0;
  1179. }
  1180. rc = pSetupCommitSingleBackup(Queue,
  1181. FullTargetPath,
  1182. QueueNode->TargetDirectory,
  1183. -1,
  1184. QueueNode->TargetFilename,
  1185. MsgHandler,
  1186. Context,
  1187. IsMsgHandlerNativeCharWidth,
  1188. FALSE,
  1189. &BackupInUse
  1190. );
  1191. if (rc != NO_ERROR) {
  1192. MyFree(FullTargetPath);
  1193. goto clean0;
  1194. }
  1195. FilePaths.Source = NULL;
  1196. FilePaths.Target = FullTargetPath;
  1197. FilePaths.Win32Error = NO_ERROR;
  1198. FilePaths.Flags = 0;
  1199. //
  1200. // Inform the callback that we are about to start a delete operation.
  1201. //
  1202. u = pSetupCallMsgHandler(
  1203. Queue->LogContext,
  1204. MsgHandler,
  1205. IsMsgHandlerNativeCharWidth,
  1206. Context,
  1207. SPFILENOTIFY_STARTDELETE,
  1208. (UINT_PTR)&FilePaths,
  1209. FILEOP_DELETE
  1210. );
  1211. if(u == FILEOP_ABORT) {
  1212. rc = GetLastError();
  1213. if(!rc) {
  1214. rc = ERROR_OPERATION_ABORTED;
  1215. }
  1216. MyFree(FullTargetPath);
  1217. goto clean0;
  1218. }
  1219. if(u == FILEOP_DOIT) {
  1220. //
  1221. // Attempt the delete. If it fails inform the callback,
  1222. // which may decide to abort, retry. or skip the file.
  1223. //
  1224. SetFileAttributes(FullTargetPath,FILE_ATTRIBUTE_NORMAL);
  1225. do {
  1226. if (BackupInUse) {
  1227. rc = ERROR_SHARING_VIOLATION;
  1228. } else {
  1229. rc = DeleteFile(FullTargetPath) ? NO_ERROR : GetLastError();
  1230. }
  1231. if((rc == ERROR_ACCESS_DENIED)
  1232. || (rc == ERROR_SHARING_VIOLATION)
  1233. || (rc == ERROR_USER_MAPPED_FILE)) {
  1234. //
  1235. // The file is probably in use.
  1236. //
  1237. if(QueueNode->InternalFlags & IQF_DELAYED_DELETE_OK) {
  1238. //
  1239. // Inf wanted delete on next reboot. Check to see if
  1240. // we're being asked to delete a protected system file.
  1241. // If so (and all the catalog nodes associated with the
  1242. // queue were OK), then we'll allow this to happen.
  1243. // Otherwise, we'll silently skip the deletion (and log
  1244. // it).
  1245. //
  1246. MYASSERT((Queue->Flags & FQF_DID_CATALOGS_OK) ||
  1247. (Queue->Flags & FQF_DID_CATALOGS_FAILED));
  1248. if(Queue->Flags & FQF_DID_CATALOGS_OK) {
  1249. QueueNode->InternalFlags |= INUSE_IN_USE;
  1250. TargetIsProtected = IsFileProtected(FullTargetPath,
  1251. Queue->LogContext,
  1252. NULL
  1253. );
  1254. if(b = PostDelayedMove(Queue,
  1255. FullTargetPath,
  1256. NULL,
  1257. -1,
  1258. TargetIsProtected)) {
  1259. //
  1260. // Tell the callback.
  1261. //
  1262. FilePaths.Source = NULL;
  1263. FilePaths.Target = FullTargetPath;
  1264. FilePaths.Win32Error = NO_ERROR;
  1265. FilePaths.Flags = FILEOP_DELETE;
  1266. pSetupCallMsgHandler(
  1267. Queue->LogContext,
  1268. MsgHandler,
  1269. IsMsgHandlerNativeCharWidth,
  1270. Context,
  1271. SPFILENOTIFY_FILEOPDELAYED,
  1272. (UINT_PTR)&FilePaths,
  1273. 0
  1274. );
  1275. }
  1276. } else {
  1277. //
  1278. // We're installing an unsigned package. Skip the
  1279. // delayed delete operation, and generate a log
  1280. // entry about this.
  1281. //
  1282. WriteLogEntry(Queue->LogContext,
  1283. SETUP_LOG_ERROR,
  1284. MSG_LOG_DELAYED_DELETE_SKIPPED_FOR_SFC,
  1285. NULL,
  1286. FullTargetPath
  1287. );
  1288. }
  1289. } else {
  1290. //
  1291. // Just skip this file.
  1292. //
  1293. b = TRUE;
  1294. }
  1295. rc = b ? NO_ERROR : GetLastError();
  1296. if(rc) {
  1297. WriteLogEntry(
  1298. Queue->LogContext,
  1299. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  1300. MSG_LOG_DELAYDELETE_FILE_ERROR,
  1301. NULL,
  1302. FullTargetPath);
  1303. WriteLogError(Queue->LogContext,SETUP_LOG_ERROR,rc);
  1304. } else {
  1305. WriteLogEntry(
  1306. Queue->LogContext,
  1307. SETUP_LOG_INFO,
  1308. MSG_LOG_DELAYDELETED_FILE,
  1309. NULL,
  1310. FullTargetPath);
  1311. }
  1312. } else if(rc) {
  1313. WriteLogEntry(
  1314. Queue->LogContext,
  1315. DEL_ERR_LOG_LEVEL(rc) | SETUP_LOG_BUFFER,
  1316. MSG_LOG_DELETE_FILE_ERROR,
  1317. NULL,
  1318. FullTargetPath);
  1319. WriteLogError(Queue->LogContext,DEL_ERR_LOG_LEVEL(rc),rc);
  1320. } else {
  1321. WriteLogEntry(
  1322. Queue->LogContext,
  1323. SETUP_LOG_INFO,
  1324. MSG_LOG_DELETED_FILE,
  1325. NULL,
  1326. FullTargetPath);
  1327. }
  1328. if( rc == NO_ERROR )
  1329. {
  1330. rc = pSetupCallSCE(
  1331. ST_SCE_DELETE,
  1332. FullTargetPath,
  1333. NULL,
  1334. NULL,
  1335. -1,
  1336. NULL
  1337. );
  1338. SetLastError( rc );
  1339. }
  1340. if(rc != NO_ERROR) {
  1341. FilePaths.Win32Error = rc;
  1342. u = pSetupCallMsgHandler(
  1343. Queue->LogContext,
  1344. MsgHandler,
  1345. IsMsgHandlerNativeCharWidth,
  1346. Context,
  1347. SPFILENOTIFY_DELETEERROR,
  1348. (UINT_PTR)&FilePaths,
  1349. 0
  1350. );
  1351. if(u == FILEOP_ABORT) {
  1352. rc = GetLastError();
  1353. if(!rc) {
  1354. rc = ERROR_OPERATION_ABORTED;
  1355. }
  1356. MyFree(FullTargetPath);
  1357. goto clean0;
  1358. }
  1359. if(u == FILEOP_SKIP) {
  1360. break;
  1361. }
  1362. }
  1363. } while(rc != NO_ERROR);
  1364. } else {
  1365. rc = NO_ERROR;
  1366. }
  1367. FilePaths.Win32Error = rc;
  1368. pSetupCallMsgHandler(
  1369. Queue->LogContext,
  1370. MsgHandler,
  1371. IsMsgHandlerNativeCharWidth,
  1372. Context,
  1373. SPFILENOTIFY_ENDDELETE,
  1374. (UINT_PTR)&FilePaths,
  1375. 0
  1376. );
  1377. MyFree(FullTargetPath);
  1378. }
  1379. pSetupCallMsgHandler(
  1380. Queue->LogContext,
  1381. MsgHandler,
  1382. IsMsgHandlerNativeCharWidth,
  1383. Context,
  1384. SPFILENOTIFY_ENDSUBQUEUE,
  1385. FILEOP_DELETE,
  1386. 0
  1387. );
  1388. rc = NO_ERROR;
  1389. clean0:
  1390. SetLastError(rc);
  1391. return rc;
  1392. }
  1393. DWORD
  1394. pCommitRenameQueue(
  1395. IN PSP_FILE_QUEUE Queue,
  1396. IN PVOID MsgHandler,
  1397. IN PVOID Context,
  1398. IN BOOL IsMsgHandlerNativeCharWidth
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. Process the rename Queue
  1403. Rename each file specified in the queue
  1404. Files are backed up before they are renamed (if not already backed up)
  1405. If the target exists, it is also backed up (if not already backed up)
  1406. Performance: this can get optimized by treating the newly named files
  1407. as a backup
  1408. See also pCommitBackupQueue, pCommitDeleteQueue and pCommitCopyQueue
  1409. Arguments:
  1410. Queue - queue that contains the rename sub-queue
  1411. MsgHandler - Supplies a callback routine to be notified
  1412. of various significant events in the queue processing.
  1413. Context - Supplies a value that is passed to the MsgHandler
  1414. callback function.
  1415. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  1416. Return Value:
  1417. DWORD indicating status or success
  1418. --*/
  1419. {
  1420. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  1421. UINT u;
  1422. BOOL b;
  1423. DWORD rc;
  1424. PCTSTR FullTargetPath;
  1425. PCTSTR FullSourcePath;
  1426. FILEPATHS FilePaths;
  1427. BOOL BackupInUse = FALSE;
  1428. BOOL TargetIsProtected;
  1429. MYASSERT(Queue->RenameNodeCount);
  1430. b = pSetupCallMsgHandler(
  1431. Queue->LogContext,
  1432. MsgHandler,
  1433. IsMsgHandlerNativeCharWidth,
  1434. Context,
  1435. SPFILENOTIFY_STARTSUBQUEUE,
  1436. FILEOP_RENAME,
  1437. Queue->RenameNodeCount
  1438. );
  1439. if(!b) {
  1440. rc = GetLastError();
  1441. if(!rc) {
  1442. rc = ERROR_OPERATION_ABORTED;
  1443. }
  1444. goto clean0;
  1445. }
  1446. for(QueueNode=Queue->RenameQueue; QueueNode; QueueNode=QueueNode->Next) {
  1447. //
  1448. // Form the full source path of the file to be renamed.
  1449. //
  1450. FullSourcePath = pSetupFormFullPath(
  1451. Queue->StringTable,
  1452. QueueNode->SourcePath,
  1453. QueueNode->SourceFilename,
  1454. -1
  1455. );
  1456. if(!FullSourcePath) {
  1457. rc = ERROR_NOT_ENOUGH_MEMORY;
  1458. goto clean0;
  1459. }
  1460. //
  1461. // Form the full target path of the file to be renamed.
  1462. //
  1463. FullTargetPath = pSetupFormFullPath(
  1464. Queue->StringTable,
  1465. QueueNode->TargetDirectory == -1 ? QueueNode->SourcePath : QueueNode->TargetDirectory,
  1466. QueueNode->TargetFilename,
  1467. -1
  1468. );
  1469. if(!FullTargetPath) {
  1470. MyFree(FullSourcePath);
  1471. rc = ERROR_NOT_ENOUGH_MEMORY;
  1472. goto clean0;
  1473. }
  1474. //
  1475. // Backup the file we may be overwriting
  1476. //
  1477. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  1478. FullTargetPath,
  1479. 0,
  1480. NULL)) != NO_ERROR) {
  1481. MyFree(FullSourcePath);
  1482. MyFree(FullTargetPath);
  1483. goto clean0;
  1484. }
  1485. rc = pSetupCommitSingleBackup(Queue,
  1486. FullTargetPath,
  1487. QueueNode->TargetDirectory == -1 ? QueueNode->SourcePath : QueueNode->TargetDirectory,
  1488. -1, // we don't use this
  1489. QueueNode->TargetFilename,
  1490. MsgHandler,
  1491. Context,
  1492. IsMsgHandlerNativeCharWidth,
  1493. FALSE,
  1494. &BackupInUse
  1495. );
  1496. if (rc != NO_ERROR) {
  1497. MyFree(FullSourcePath);
  1498. MyFree(FullTargetPath);
  1499. goto clean0;
  1500. }
  1501. //
  1502. // Backup the file we're about to rename
  1503. //
  1504. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  1505. FullSourcePath,
  1506. LASTGOOD_OPERATION_DELETE,
  1507. NULL)) != NO_ERROR) {
  1508. MyFree(FullSourcePath);
  1509. MyFree(FullTargetPath);
  1510. goto clean0;
  1511. }
  1512. rc = pSetupCommitSingleBackup(Queue,
  1513. FullSourcePath,
  1514. QueueNode->SourcePath,
  1515. -1, // we don't use this????
  1516. QueueNode->SourceFilename,
  1517. MsgHandler,
  1518. Context,
  1519. IsMsgHandlerNativeCharWidth,
  1520. FALSE,
  1521. &b
  1522. );
  1523. if (rc != NO_ERROR) {
  1524. MyFree(FullSourcePath);
  1525. MyFree(FullTargetPath);
  1526. goto clean0;
  1527. }
  1528. if (b) {
  1529. //
  1530. // BackupInUse is the "OR" of the two backup In-Use flags
  1531. //
  1532. BackupInUse = TRUE;
  1533. }
  1534. FilePaths.Source = FullSourcePath;
  1535. FilePaths.Target = FullTargetPath;
  1536. FilePaths.Win32Error = NO_ERROR;
  1537. //
  1538. // Inform the callback that we are about to start a rename operation.
  1539. //
  1540. u = pSetupCallMsgHandler(
  1541. Queue->LogContext,
  1542. MsgHandler,
  1543. IsMsgHandlerNativeCharWidth,
  1544. Context,
  1545. SPFILENOTIFY_STARTRENAME,
  1546. (UINT_PTR)&FilePaths,
  1547. FILEOP_RENAME
  1548. );
  1549. if(u == FILEOP_ABORT) {
  1550. rc = GetLastError();
  1551. if(!rc) {
  1552. rc = ERROR_OPERATION_ABORTED;
  1553. }
  1554. MyFree(FullSourcePath);
  1555. MyFree(FullTargetPath);
  1556. goto clean0;
  1557. }
  1558. if(u == FILEOP_DOIT) {
  1559. //
  1560. // Attempt the rename. If it fails inform the callback,
  1561. // which may decide to abort, retry. or skip the file.
  1562. //
  1563. do {
  1564. if (BackupInUse) {
  1565. //
  1566. // backup is in use, must delay op. Check to see if either
  1567. // the source or target files are protected system files.
  1568. // If so (and all the catalog nodes associated with the
  1569. // queue were OK), then we'll allos this to happen.
  1570. // Otherwise, we'll silently fail the rename (and log it).
  1571. //
  1572. MYASSERT((Queue->Flags & FQF_DID_CATALOGS_OK) ||
  1573. (Queue->Flags & FQF_DID_CATALOGS_FAILED));
  1574. if(Queue->Flags & FQF_DID_CATALOGS_OK) {
  1575. TargetIsProtected = IsFileProtected(FullSourcePath,
  1576. Queue->LogContext,
  1577. NULL
  1578. );
  1579. if(!TargetIsProtected) {
  1580. TargetIsProtected = IsFileProtected(FullTargetPath,
  1581. Queue->LogContext,
  1582. NULL
  1583. );
  1584. }
  1585. if(b = PostDelayedMove(Queue,
  1586. FullSourcePath,
  1587. FullTargetPath,
  1588. -1,
  1589. TargetIsProtected)) {
  1590. rc = NO_ERROR;
  1591. }
  1592. else
  1593. {
  1594. rc = GetLastError();
  1595. }
  1596. if(rc) {
  1597. WriteLogEntry(
  1598. Queue->LogContext,
  1599. DEL_ERR_LOG_LEVEL(rc) | SETUP_LOG_BUFFER,
  1600. MSG_LOG_DELAYRENAME_FILE_ERROR,
  1601. NULL,
  1602. FullSourcePath,
  1603. FullTargetPath);
  1604. WriteLogError(Queue->LogContext,DEL_ERR_LOG_LEVEL(rc),rc);
  1605. } else {
  1606. WriteLogEntry(
  1607. Queue->LogContext,
  1608. SETUP_LOG_INFO,
  1609. MSG_LOG_DELAYRENAMED_FILE,
  1610. NULL,
  1611. FullSourcePath,
  1612. FullTargetPath);
  1613. }
  1614. } else {
  1615. //
  1616. // We're installing an unsigned package. Skip the
  1617. // delayed rename operation, and generate a log
  1618. // entry about this.
  1619. //
  1620. WriteLogEntry(Queue->LogContext,
  1621. SETUP_LOG_ERROR,
  1622. MSG_LOG_DELAYED_MOVE_SKIPPED_FOR_SFC,
  1623. NULL,
  1624. FullTargetPath
  1625. );
  1626. //
  1627. // act as if no error occurred.
  1628. //
  1629. rc = NO_ERROR;
  1630. }
  1631. } else {
  1632. rc = MoveFile(FullSourcePath,FullTargetPath) ? NO_ERROR : GetLastError();
  1633. if(rc) {
  1634. WriteLogEntry(
  1635. Queue->LogContext,
  1636. DEL_ERR_LOG_LEVEL(rc) | SETUP_LOG_BUFFER,
  1637. MSG_LOG_RENAME_FILE_ERROR,
  1638. NULL,
  1639. FullSourcePath,
  1640. FullTargetPath);
  1641. WriteLogError(Queue->LogContext,DEL_ERR_LOG_LEVEL(rc),rc);
  1642. } else {
  1643. WriteLogEntry(
  1644. Queue->LogContext,
  1645. SETUP_LOG_INFO,
  1646. MSG_LOG_RENAMED_FILE,
  1647. NULL,
  1648. FullSourcePath,
  1649. FullTargetPath);
  1650. }
  1651. }
  1652. if( rc == NO_ERROR )
  1653. {
  1654. rc = pSetupCallSCE(
  1655. ST_SCE_RENAME,
  1656. FullSourcePath,
  1657. NULL,
  1658. FullTargetPath,
  1659. -1,
  1660. NULL
  1661. );
  1662. SetLastError( rc );
  1663. }
  1664. if((rc == ERROR_FILE_NOT_FOUND) || (rc == ERROR_PATH_NOT_FOUND)) {
  1665. rc = NO_ERROR;
  1666. }
  1667. if(rc != NO_ERROR) {
  1668. FilePaths.Win32Error = rc;
  1669. u = pSetupCallMsgHandler(
  1670. Queue->LogContext,
  1671. MsgHandler,
  1672. IsMsgHandlerNativeCharWidth,
  1673. Context,
  1674. SPFILENOTIFY_RENAMEERROR,
  1675. (UINT_PTR)&FilePaths,
  1676. 0
  1677. );
  1678. if(u == FILEOP_ABORT) {
  1679. rc = GetLastError();
  1680. if(!rc) {
  1681. rc = ERROR_OPERATION_ABORTED;
  1682. }
  1683. MyFree(FullSourcePath);
  1684. MyFree(FullTargetPath);
  1685. goto clean0;
  1686. }
  1687. if(u == FILEOP_SKIP) {
  1688. break;
  1689. }
  1690. }
  1691. } while(rc != NO_ERROR);
  1692. } else {
  1693. rc = NO_ERROR;
  1694. }
  1695. FilePaths.Win32Error = rc;
  1696. pSetupCallMsgHandler(
  1697. Queue->LogContext,
  1698. MsgHandler,
  1699. IsMsgHandlerNativeCharWidth,
  1700. Context,
  1701. SPFILENOTIFY_ENDRENAME,
  1702. (UINT_PTR)&FilePaths,
  1703. 0
  1704. );
  1705. MyFree(FullSourcePath);
  1706. MyFree(FullTargetPath);
  1707. }
  1708. pSetupCallMsgHandler(
  1709. Queue->LogContext,
  1710. MsgHandler,
  1711. IsMsgHandlerNativeCharWidth,
  1712. Context,
  1713. SPFILENOTIFY_ENDSUBQUEUE,
  1714. FILEOP_RENAME,
  1715. 0
  1716. );
  1717. rc = NO_ERROR;
  1718. clean0:
  1719. SetLastError(rc);
  1720. return rc;
  1721. }
  1722. DWORD
  1723. pCommitCopyQueue(
  1724. IN PSP_FILE_QUEUE Queue,
  1725. IN PVOID MsgHandler,
  1726. IN PVOID Context,
  1727. IN BOOL IsMsgHandlerNativeCharWidth
  1728. )
  1729. /*++
  1730. Routine Description:
  1731. Process the copy sub-Queues
  1732. Copy each file specified in the sub-queues
  1733. Files are backed up before they are overwritten (if not already backed up)
  1734. See also pCommitBackupQueue, pCommitDeleteQueue and pCommitRenameQueue
  1735. Arguments:
  1736. Queue - queue that contains the copy sub-queues
  1737. MsgHandler - Supplies a callback routine to be notified
  1738. of various significant events in the queue processing.
  1739. Context - Supplies a value that is passed to the MsgHandler
  1740. callback function.
  1741. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  1742. Return Value:
  1743. DWORD indicating status or success
  1744. --*/
  1745. {
  1746. PSOURCE_MEDIA_INFO SourceMediaInfo;
  1747. SOURCE_MEDIA SourceMedia;
  1748. PTCHAR p, temp;
  1749. UINT SourcePathLen;
  1750. UINT u;
  1751. DWORD rc;
  1752. Q_CAB_CB_DATA QData;
  1753. BOOL b;
  1754. BOOL FirstIteration;
  1755. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  1756. TCHAR UserSourceRoot[MAX_PATH];
  1757. TCHAR UserSourcePath[MAX_PATH];
  1758. TCHAR FullSourcePath[MAX_PATH];
  1759. TCHAR UserOverride[MAX_PATH];
  1760. LPCTSTR RestorePath = NULL;
  1761. UINT DriveType;
  1762. BOOL IsRemovable, AnyProcessed, AnyNotProcessed, SkipMedia;
  1763. BOOL SpecialMedia = FALSE;
  1764. BOOL LocateCab;
  1765. PCTSTR MediaRoot;
  1766. DWORD MediaLogTag;
  1767. LONG Cabfile;
  1768. LONG Tagfile;
  1769. //
  1770. // The caller is supposed to skip calling us if there are no files
  1771. // to be copied.
  1772. //
  1773. MYASSERT(Queue->CopyNodeCount);
  1774. //
  1775. // Inform the callback that we are starting.
  1776. //
  1777. b = pSetupCallMsgHandler(
  1778. Queue->LogContext,
  1779. MsgHandler,
  1780. IsMsgHandlerNativeCharWidth,
  1781. Context,
  1782. SPFILENOTIFY_STARTSUBQUEUE,
  1783. FILEOP_COPY,
  1784. Queue->CopyNodeCount
  1785. );
  1786. if(!b) {
  1787. rc = GetLastError();
  1788. if(!rc) {
  1789. rc = ERROR_OPERATION_ABORTED;
  1790. }
  1791. return(rc);
  1792. }
  1793. if(Queue->RestorePathID != -1) {
  1794. RestorePath = pSetupStringTableStringFromId(Queue->StringTable, Queue->RestorePathID);
  1795. DiskPromptGetDriveType(RestorePath, &DriveType, &IsRemovable);
  1796. if(IsRemovable) {
  1797. //
  1798. // do not allow restore from removable media
  1799. //
  1800. RestorePath = NULL;
  1801. }
  1802. }
  1803. //
  1804. // Initially, no user-specified override path exists.
  1805. //
  1806. UserSourceRoot[0] = TEXT('\0');
  1807. UserSourcePath[0] = TEXT('\0');
  1808. //
  1809. // The outermost loop iterates through all the source media descriptors.
  1810. //
  1811. for(SourceMediaInfo=Queue->SourceMediaList; SourceMediaInfo; SourceMediaInfo=SourceMediaInfo->Next) {
  1812. //
  1813. // If there are no files on this particular media, skip it.
  1814. // Otherwise get pointer to queue node for first file on this media.
  1815. //
  1816. if(!SourceMediaInfo->CopyNodeCount) {
  1817. continue;
  1818. }
  1819. MYASSERT(SourceMediaInfo->CopyQueue);
  1820. //
  1821. // if last media was special media (see long discussion above),
  1822. // then forget about any user override
  1823. //
  1824. if (SpecialMedia) {
  1825. UserSourceRoot[0] = TEXT('\0');
  1826. UserSourcePath[0] = TEXT('\0');
  1827. SpecialMedia = FALSE;
  1828. }
  1829. //
  1830. // see if this media is special media
  1831. //
  1832. if (SourceMediaInfo->Flags & ( SMI_FLAG_USE_SVCPACK_SOURCE_ROOT_PATH |
  1833. SMI_FLAG_USE_LOCAL_SPCACHE |
  1834. SMI_FLAG_USE_LOCAL_SOURCE_CAB ) ) {
  1835. SpecialMedia = TRUE;
  1836. }
  1837. //
  1838. // If we're in restore-mode
  1839. // we've been given a directory to restore from
  1840. // ignore the media root, and use restore-point root
  1841. // restore as many files as we can
  1842. //
  1843. // note, we check for file presence via FileExists
  1844. // rather than trying to determine file name
  1845. // since we'll always backup in uncompressed form
  1846. // with same name as listed in [SourceDisksNames]
  1847. //
  1848. if(RestorePath) {
  1849. //
  1850. // Restore Symantics - prior to prompting for media, see
  1851. // if we can restore backup
  1852. //
  1853. QueueNode = NULL;
  1854. for(queueNode = SourceMediaInfo->CopyQueue;
  1855. queueNode;
  1856. queueNode=queueNode->Next) {
  1857. pSetupBuildSourceForCopy(
  1858. RestorePath,
  1859. NULL,
  1860. SourceMediaInfo->SourceRootPath,
  1861. Queue,
  1862. queueNode,
  1863. FullSourcePath
  1864. );
  1865. //
  1866. // don't allow alternate sourcenames in this case
  1867. //
  1868. if(FileExists(FullSourcePath,NULL)) {
  1869. //
  1870. // backup exists, copy it
  1871. //
  1872. rc = pSetupCopySingleQueuedFile(
  1873. Queue,
  1874. queueNode,
  1875. FullSourcePath,
  1876. MsgHandler,
  1877. Context,
  1878. UserOverride,
  1879. IsMsgHandlerNativeCharWidth,
  1880. SP_COPY_ALREADYDECOMP // backup already decomp'd.
  1881. );
  1882. if(rc == NO_ERROR) {
  1883. //
  1884. // we restored this file through backup
  1885. // carry on to next file
  1886. //
  1887. queueNode->InternalFlags |= IQF_PROCESSED;
  1888. continue;
  1889. }
  1890. //
  1891. // we know backup existed so if this failed
  1892. // consider it major enough to abort restore
  1893. // (eg, file unsigned, user specified abort)
  1894. //
  1895. SetLastError(rc);
  1896. return(rc);
  1897. }
  1898. if(!QueueNode) {
  1899. //
  1900. // first problematic file
  1901. //
  1902. QueueNode = queueNode;
  1903. }
  1904. }
  1905. if(!QueueNode) {
  1906. //
  1907. // we copied all files of this media from backup
  1908. // carry on to next media
  1909. //
  1910. continue;
  1911. }
  1912. } else {
  1913. //
  1914. // not restoring, start at first file
  1915. //
  1916. QueueNode = SourceMediaInfo->CopyQueue;
  1917. }
  1918. //
  1919. // We will need to prompt for media, which requires some preparation.
  1920. // We need to get the first file in the queue for this media, because
  1921. // its path is where we will expect to find it or its cabinet or tag
  1922. // file. If there is no tag file, then we will look for the file
  1923. // itself.
  1924. //
  1925. FirstIteration = TRUE;
  1926. SkipMedia = FALSE;
  1927. LocateCab = FALSE;
  1928. Tagfile = SourceMediaInfo->Tagfile;
  1929. Cabfile = SourceMediaInfo->Cabfile;
  1930. RepromptMedia:
  1931. //
  1932. // The case where we have non-removeable media and the path was
  1933. // previously overridden must be handled specially. For example, we
  1934. // could have files queued on the same source root but different
  1935. // subdirs. If the user changes the network location, for example,
  1936. // we have to be careful or we'll ignore the change in subdirectories
  1937. // as we move among the media.
  1938. //
  1939. // To work around this, we check on non-removable media to see if the
  1940. // queue node we're presently working with is in a subdirectory. If it
  1941. // is, then we reset our UserSourcePath string.
  1942. //
  1943. // (andrewr)...I don't get this comment above. The current code
  1944. // iterates through each source media info structure, which doesn't include
  1945. // subdirectory information, only source root path information. If it
  1946. // does, then the caller is doing something really wierd, since they
  1947. // should be using the SourcePath to define subdirectories from one master
  1948. // root.
  1949. //
  1950. // It appears that the reasoning behind the code below is as follows:
  1951. //
  1952. // The assumption is that if we have removable media and multiple source
  1953. // paths, then we will have to swap media out of the drive. We don't
  1954. // override source root paths if we are dealing with removable media.
  1955. // If the source root path is non removable, then all of the source media
  1956. // is "tied together." If the user overrides the source root path, then
  1957. // we override subsequent fixed media source root paths.
  1958. //
  1959. // In the case of dealing with service pack source media or a local cab-file
  1960. // drivers cache, the source media info for a queue will not be tied together,
  1961. // even though we're dealing with fixed media.
  1962. //
  1963. // To reconcile the comments above and the reasoning it uses with the
  1964. // contradiction that svc pack media imposes, we have 2 options:
  1965. //
  1966. // 1. If we encounter flags that indicate one of our special cases, then don't
  1967. // use any user override for the new source media. (or, put another way,
  1968. // if we know that the last media was actually one of these special media,
  1969. // then don't allow an override of the normal media.
  1970. //
  1971. // 2. Introduce some sort of hueristic that determines if the prior source media
  1972. // and the current source media are similar. If they are, then go ahead and
  1973. // use any user specified override, otherwise use the proper path.
  1974. //
  1975. //
  1976. // For simplicities sake, I use approach 1 above. This is made a little simpler
  1977. // by following the following rule. When adding source media to the media list,
  1978. // insert special media (ie, has flags identifying the media as svc pack media)
  1979. // at the head of the list, insert normal media after that. By following this
  1980. // approach we know that we can just "zero out" the user overrides for the special
  1981. // media and we'll just do the right thing for the regular media.
  1982. //
  1983. // In the case where there is an explicit cab-file to use
  1984. // then we ask the user to point to cab-file instead of source file (first iteration)
  1985. //
  1986. MediaRoot = *UserSourceRoot
  1987. ? UserSourceRoot
  1988. : pSetupStringTableStringFromId(Queue->StringTable, SourceMediaInfo->SourceRootPath);
  1989. DiskPromptGetDriveType(MediaRoot, &DriveType, &IsRemovable);
  1990. if(!IsRemovable && (QueueNode->SourcePath != -1)) {
  1991. *UserSourcePath = TEXT('\0');
  1992. }
  1993. pSetupBuildSourceForCopy(
  1994. UserSourceRoot,
  1995. UserSourcePath,
  1996. SourceMediaInfo->SourceRootPath,
  1997. Queue,
  1998. QueueNode,
  1999. FullSourcePath
  2000. );
  2001. if (FirstIteration
  2002. && (Tagfile != Cabfile)
  2003. && (Cabfile != -1)) {
  2004. MYASSERT(!SkipMedia);
  2005. MYASSERT(!(SourceMediaInfo->Flags & SMI_FLAG_USE_LOCAL_SOURCE_CAB));
  2006. //
  2007. // build location of cab file
  2008. //
  2009. temp = _tcsrchr(FullSourcePath,TEXT('\\'));
  2010. MYASSERT( temp );
  2011. if(temp) {
  2012. *(temp+1) = 0;
  2013. } else {
  2014. FullSourcePath[0] = 0;
  2015. }
  2016. //
  2017. // obtain path of (potential) cab file
  2018. //
  2019. pSetupConcatenatePaths( FullSourcePath, pSetupStringTableStringFromId(Queue->StringTable,Cabfile), MAX_PATH, NULL );
  2020. LocateCab = TRUE;
  2021. } else {
  2022. LocateCab = FALSE;
  2023. }
  2024. if((p = _tcsrchr(FullSourcePath,TEXT('\\')))!=NULL) {
  2025. *p++ = TEXT('\0');
  2026. } else {
  2027. //
  2028. // I'm being pedantic here, this should never happen
  2029. //
  2030. MYASSERT(p);
  2031. p = FullSourcePath;
  2032. }
  2033. //
  2034. // Now FullSourcePath has the path part and p has the file part
  2035. // for the first file in the queue for this media (or explicit cab file)
  2036. // Get the media in the drive by calling the callback function.
  2037. //
  2038. // Although it would be nice to not have to
  2039. // call this callback if we know that we don't have to (there is media
  2040. // where the caller said there should be (local media, media already in, etc.)
  2041. // we do need to call this so that we afford the caller the luxury of
  2042. // changing their mind one last time.
  2043. //
  2044. // the only exception to this rule is if we are using the local driver
  2045. // cache cab-file. In this case, we don't want the user to ever get
  2046. // prompted for this file, so we skip any media prompting. We know that
  2047. // if we have media added that has this flag set, then the cab already exists
  2048. // and we can just use it (otherwise we wouldn't have initialized it in the
  2049. // first place, we'd just use the os source path!)
  2050. //
  2051. SourceMedia.Tagfile = (Tagfile != -1 && FirstIteration)
  2052. ? pSetupStringTableStringFromId(
  2053. Queue->StringTable,
  2054. Tagfile
  2055. )
  2056. : NULL;
  2057. SourceMedia.Description = (SourceMediaInfo->Description != -1)
  2058. ? pSetupStringTableStringFromId(
  2059. Queue->StringTable,
  2060. SourceMediaInfo->DescriptionDisplayName
  2061. )
  2062. : NULL;
  2063. SourceMedia.SourcePath = FullSourcePath;
  2064. SourceMedia.SourceFile = p;
  2065. SourceMedia.Flags = (QueueNode->StyleFlags & (SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP | SP_COPY_NOBROWSE));
  2066. MediaLogTag = AllocLogInfoSlotOrLevel(Queue->LogContext,SETUP_LOG_INFO,FALSE);
  2067. WriteLogEntry(
  2068. Queue->LogContext,
  2069. MediaLogTag,
  2070. MSG_LOG_NEEDMEDIA,
  2071. NULL,
  2072. SourceMedia.Tagfile ? SourceMedia.Tagfile : TEXT(""),
  2073. SourceMedia.Description ? SourceMedia.Description : TEXT(""),
  2074. SourceMedia.SourcePath ? SourceMedia.SourcePath : TEXT(""),
  2075. SourceMedia.SourceFile ? SourceMedia.SourceFile : TEXT(""),
  2076. SourceMedia.Flags
  2077. );
  2078. if( SkipMedia || (FirstIteration && (SourceMediaInfo->Flags & SMI_FLAG_USE_LOCAL_SOURCE_CAB)) ) {
  2079. u = FILEOP_DOIT;
  2080. WriteLogEntry(
  2081. Queue->LogContext,
  2082. SETUP_LOG_VERBOSE,
  2083. MSG_LOG_NEEDMEDIA_AUTOSKIP,
  2084. NULL
  2085. );
  2086. } else {
  2087. u = pSetupCallMsgHandler(
  2088. Queue->LogContext,
  2089. MsgHandler,
  2090. IsMsgHandlerNativeCharWidth,
  2091. Context,
  2092. SPFILENOTIFY_NEEDMEDIA,
  2093. (UINT_PTR)&SourceMedia,
  2094. (UINT_PTR)UserOverride
  2095. );
  2096. }
  2097. if(u == FILEOP_ABORT) {
  2098. rc = GetLastError();
  2099. if(!rc) {
  2100. rc = ERROR_OPERATION_ABORTED;
  2101. }
  2102. WriteLogEntry(
  2103. Queue->LogContext,
  2104. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  2105. MSG_LOG_NEEDMEDIA_ABORT,
  2106. NULL);
  2107. WriteLogError(Queue->LogContext,
  2108. SETUP_LOG_ERROR,
  2109. rc
  2110. );
  2111. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2112. MediaLogTag = 0;
  2113. SetLastError(rc);
  2114. return(rc);
  2115. }
  2116. if(u == FILEOP_SKIP) {
  2117. //
  2118. // If this file was a bootfile replacement, then we need to restore
  2119. // the original file that was renamed to a temporary filename.
  2120. //
  2121. WriteLogEntry(
  2122. Queue->LogContext,
  2123. SETUP_LOG_WARNING,
  2124. MSG_LOG_NEEDMEDIA_SKIP,
  2125. NULL
  2126. );
  2127. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2128. MediaLogTag = 0;
  2129. if(QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE) {
  2130. RestoreBootReplacedFile(Queue, QueueNode);
  2131. }
  2132. //
  2133. // If there are more files on this media, then try another one.
  2134. // Otherwise we're done with this media.
  2135. //
  2136. QueueNode->InternalFlags |= IQF_PROCESSED;
  2137. for(QueueNode=QueueNode->Next; QueueNode; QueueNode=QueueNode->Next) {
  2138. if(!(QueueNode->InternalFlags & IQF_PROCESSED)) {
  2139. FirstIteration = FALSE;
  2140. goto RepromptMedia;
  2141. }
  2142. }
  2143. continue;
  2144. }
  2145. if(u == FILEOP_NEWPATH) {
  2146. //
  2147. // User gave us a new source path. See which parts of the new path
  2148. // match the existing path/overrides we are using.
  2149. //
  2150. WriteLogEntry(
  2151. Queue->LogContext,
  2152. SETUP_LOG_INFO,
  2153. MSG_LOG_NEEDMEDIA_NEWPATH,
  2154. NULL,
  2155. UserOverride
  2156. );
  2157. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2158. MediaLogTag = 0;
  2159. pSetupSetPathOverrides(
  2160. Queue->StringTable,
  2161. UserSourceRoot,
  2162. UserSourcePath,
  2163. SourceMediaInfo->SourceRootPath,
  2164. QueueNode->SourcePath,
  2165. UserOverride
  2166. );
  2167. }
  2168. //
  2169. // logging specific stuff
  2170. //
  2171. if(MediaLogTag!=0) {
  2172. //
  2173. // we explicitly cleared MediaLogTag for each case we handled
  2174. //
  2175. if (u != FILEOP_DOIT) {
  2176. WriteLogEntry(
  2177. Queue->LogContext,
  2178. SETUP_LOG_WARNING,
  2179. MSG_LOG_NEEDMEDIA_BADRESULT,
  2180. NULL,
  2181. u);
  2182. }
  2183. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2184. MediaLogTag = 0;
  2185. }
  2186. //
  2187. // If we get here, the media is now accessible.
  2188. // Some or all of the files might be in a cabinet whose name is the tagfile.
  2189. //
  2190. // NOTE: Win95 used the tagfile field to be the cabinet name instead.
  2191. // If present it is used as a tagfile of sorts. The absence of a tagfile
  2192. // means the files are not in cabinets. For NT, we don't bother
  2193. // with all of this but instead try to be a little smarter.
  2194. //
  2195. // Scan the media for all source files we expect to find on it.
  2196. // If we find a file, process it. Later we hit the cabinet and only
  2197. // process the files we didn't already find outside the cabinet.
  2198. //
  2199. // exception to this is "explicit cabinet"
  2200. //
  2201. if(LocateCab) {
  2202. //
  2203. // an explicit cabinet was specified
  2204. // this is first iteration
  2205. // we've gone through NEED_MEDIA to obtain disk for this cabinet
  2206. // don't try to process files outside cabinet
  2207. // we know there is at least one file not processed
  2208. //
  2209. b = TRUE;
  2210. queueNode=QueueNode;
  2211. } else {
  2212. //
  2213. // tagfile may also be a cabfile
  2214. // but process all files outside the cabfile first
  2215. //
  2216. for(queueNode=QueueNode; queueNode; queueNode=queueNode->Next) {
  2217. if(queueNode->InternalFlags & IQF_PROCESSED) {
  2218. //
  2219. // Already processed. Skip to next file.
  2220. //
  2221. continue;
  2222. }
  2223. pSetupBuildSourceForCopy(
  2224. UserSourceRoot,
  2225. UserSourcePath,
  2226. SourceMediaInfo->SourceRootPath,
  2227. Queue,
  2228. queueNode,
  2229. FullSourcePath
  2230. );
  2231. rc = SetupDetermineSourceFileName(FullSourcePath,&b,&p,NULL);
  2232. if(rc == NO_ERROR || SkipMedia) {
  2233. //
  2234. // Found the file outside a cabinet. Process it now.
  2235. //
  2236. if(rc == NO_ERROR) {
  2237. rc = pSetupCopySingleQueuedFile(
  2238. Queue,
  2239. queueNode,
  2240. p,
  2241. MsgHandler,
  2242. Context,
  2243. UserOverride,
  2244. IsMsgHandlerNativeCharWidth,
  2245. 0
  2246. );
  2247. MyFree(p);
  2248. } else {
  2249. //
  2250. // We didn't find the source file, but we're going to try
  2251. // to copy it anyway since we've decided not to skip the
  2252. // prompt for media.
  2253. //
  2254. rc = pSetupCopySingleQueuedFile(
  2255. Queue,
  2256. queueNode,
  2257. FullSourcePath,
  2258. MsgHandler,
  2259. Context,
  2260. UserOverride,
  2261. IsMsgHandlerNativeCharWidth,
  2262. 0
  2263. );
  2264. }
  2265. if(rc != NO_ERROR) {
  2266. return(rc);
  2267. }
  2268. //
  2269. // See if we have a new source path.
  2270. //
  2271. if(UserOverride[0]) {
  2272. pSetupSetPathOverrides(
  2273. Queue->StringTable,
  2274. UserSourceRoot,
  2275. UserSourcePath,
  2276. SourceMediaInfo->SourceRootPath,
  2277. queueNode->SourcePath,
  2278. UserOverride
  2279. );
  2280. }
  2281. }
  2282. }
  2283. //
  2284. // See if any files still need to be processed.
  2285. //
  2286. for(b=FALSE,queueNode=QueueNode; queueNode; queueNode=queueNode->Next) {
  2287. if(!(queueNode->InternalFlags & IQF_PROCESSED)) {
  2288. b = TRUE;
  2289. break;
  2290. }
  2291. }
  2292. }
  2293. //
  2294. // If any files still need to be processed and we have a potential
  2295. // cabinet file, go try to extract them from a cabinet.
  2296. //
  2297. if(b && (Cabfile != -1) && FirstIteration) {
  2298. pSetupBuildSourceForCopy(
  2299. UserSourceRoot,
  2300. UserSourcePath,
  2301. SourceMediaInfo->SourceRootPath,
  2302. Queue,
  2303. queueNode,
  2304. FullSourcePath
  2305. );
  2306. temp = _tcsrchr(FullSourcePath,TEXT('\\'));
  2307. MYASSERT( temp );
  2308. if(temp) {
  2309. *(temp+1) = 0;
  2310. }
  2311. //
  2312. // obtain path of (potential) cab file
  2313. //
  2314. pSetupConcatenatePaths( FullSourcePath, pSetupStringTableStringFromId(Queue->StringTable,Cabfile), MAX_PATH, NULL );
  2315. if(DiamondIsCabinet(FullSourcePath)) {
  2316. QData.Queue = Queue;
  2317. QData.SourceMedia = SourceMediaInfo;
  2318. QData.MsgHandler = MsgHandler;
  2319. QData.IsMsgHandlerNativeCharWidth = IsMsgHandlerNativeCharWidth;
  2320. QData.Context = Context;
  2321. QData.LogContext = Queue->LogContext;
  2322. rc = DiamondProcessCabinet(
  2323. FullSourcePath,
  2324. 0,
  2325. pSetupCabinetQueueCallback,
  2326. &QData,
  2327. TRUE
  2328. );
  2329. if(rc != NO_ERROR) {
  2330. return(rc);
  2331. }
  2332. //
  2333. // Now reset the cabfile to indicate that there is no cabinet.
  2334. // If we don't do this and there are still files that have not
  2335. // been processed, we'll end up in an infinite loop -- the prompt
  2336. // will come back successfully, and we'll just keep going around
  2337. // and around looking through the cabinet, etc.
  2338. //
  2339. Cabfile = -1;
  2340. Tagfile = -1; // for compatability
  2341. }
  2342. }
  2343. //
  2344. // If we get here and files *still* need to be processed,
  2345. // assume the files are in a different directory somewhere
  2346. // and start all over with this media.
  2347. //
  2348. FirstIteration = FALSE;
  2349. DiskPromptGetDriveType(FullSourcePath, &DriveType, &IsRemovable);
  2350. AnyProcessed = FALSE;
  2351. AnyNotProcessed = FALSE;
  2352. for(QueueNode = SourceMediaInfo->CopyQueue;
  2353. QueueNode;
  2354. QueueNode=QueueNode->Next) {
  2355. if(IsRemovable) {
  2356. if(!(QueueNode->InternalFlags & IQF_PROCESSED)) {
  2357. if(Tagfile != -1) {
  2358. SkipMedia = TRUE;
  2359. }
  2360. goto RepromptMedia;
  2361. }
  2362. } else { // Fixed media
  2363. if(QueueNode->InternalFlags & IQF_PROCESSED) {
  2364. AnyProcessed = TRUE;
  2365. } else {
  2366. AnyNotProcessed = TRUE;
  2367. }
  2368. }
  2369. }
  2370. if(!IsRemovable) {
  2371. if(AnyNotProcessed) {
  2372. //
  2373. // If some of the files are present on fixed media, we don't
  2374. // want to look elsewhere.
  2375. //
  2376. if(AnyProcessed) {
  2377. SkipMedia = TRUE;
  2378. }
  2379. //
  2380. // Find the first unprocessed file
  2381. //
  2382. for(QueueNode = SourceMediaInfo->CopyQueue;
  2383. QueueNode;
  2384. QueueNode = QueueNode->Next) {
  2385. if(!(QueueNode->InternalFlags & IQF_PROCESSED)) {
  2386. break;
  2387. }
  2388. }
  2389. MYASSERT(QueueNode);
  2390. goto RepromptMedia;
  2391. }
  2392. }
  2393. } // end for each source media info
  2394. //
  2395. // Tell handler we're done with the copy queue and return.
  2396. //
  2397. pSetupCallMsgHandler(
  2398. Queue->LogContext,
  2399. MsgHandler,
  2400. IsMsgHandlerNativeCharWidth,
  2401. Context,
  2402. SPFILENOTIFY_ENDSUBQUEUE,
  2403. FILEOP_COPY,
  2404. 0
  2405. );
  2406. return(NO_ERROR);
  2407. }
  2408. VOID
  2409. pSetupBuildSourceForCopy(
  2410. IN PCTSTR UserRoot,
  2411. IN PCTSTR UserPath,
  2412. IN LONG MediaRoot,
  2413. IN PSP_FILE_QUEUE Queue,
  2414. IN PSP_FILE_QUEUE_NODE QueueNode,
  2415. OUT PTSTR FullPath
  2416. )
  2417. {
  2418. PCTSTR p;
  2419. //
  2420. // If there is a user-specified override root path, use that instead of
  2421. // the root path specified in the source media descriptor.
  2422. //
  2423. MYASSERT(Queue);
  2424. MYASSERT(QueueNode);
  2425. MYASSERT(FullPath);
  2426. p = (UserRoot && UserRoot[0])
  2427. ? UserRoot
  2428. : pSetupStringTableStringFromId(Queue->StringTable,MediaRoot);
  2429. lstrcpyn(FullPath,p,MAX_PATH);
  2430. //
  2431. // If there is a user-specified override path, use that instead of any
  2432. // path specified in the copy node.
  2433. //
  2434. if(UserPath && UserPath[0]) {
  2435. p = UserPath;
  2436. } else {
  2437. if(QueueNode->SourcePath == -1) {
  2438. p = NULL;
  2439. } else {
  2440. p = pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourcePath);
  2441. }
  2442. }
  2443. if(p) {
  2444. pSetupConcatenatePaths(FullPath,p,MAX_PATH,NULL);
  2445. }
  2446. //
  2447. // Fetch the filename and append.
  2448. //
  2449. p = pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename),
  2450. pSetupConcatenatePaths(FullPath,p,MAX_PATH,NULL);
  2451. }
  2452. VOID
  2453. pSetupSetPathOverrides(
  2454. IN PVOID StringTable,
  2455. IN OUT PTSTR RootPath,
  2456. IN OUT PTSTR SubPath,
  2457. IN LONG RootPathId,
  2458. IN LONG SubPathId,
  2459. IN PTSTR NewPath
  2460. )
  2461. {
  2462. PCTSTR root,path;
  2463. UINT u,l;
  2464. //
  2465. // See if the existing root override or root path is a prefix
  2466. // of the path the user gave us.
  2467. //
  2468. MYASSERT(RootPath);
  2469. MYASSERT(SubPath);
  2470. root = RootPath[0] ? RootPath : pSetupStringTableStringFromId(StringTable,RootPathId);
  2471. u = lstrlen(root);
  2472. path = SubPath[0]
  2473. ? SubPath
  2474. : ((SubPathId == -1) ? NULL : pSetupStringTableStringFromId(StringTable,SubPathId));
  2475. if(path && (*path == TEXT('\\'))) {
  2476. path++;
  2477. }
  2478. if(_tcsnicmp(NewPath,root,u)) {
  2479. //
  2480. // Root path does not match what we're currently using, ie, the user
  2481. // supplied a new path. In this case, we will see if the currently in-use
  2482. // subpath matches the suffix of the new path, and if so, we'll assume
  2483. // that is the override subpath and shorten the override root path.
  2484. //
  2485. lstrcpy(RootPath,NewPath);
  2486. if(path) {
  2487. u = lstrlen(NewPath);
  2488. l = lstrlen(path);
  2489. if((u > l) && (NewPath[(u-l)-1] == TEXT('\\')) && !lstrcmpi(NewPath+u-l,path)) {
  2490. //
  2491. // Subpath tail matches. Truncate the root override and
  2492. // leave the subpath override alone.
  2493. //
  2494. RootPath[(u-l)-1] = 0;
  2495. } else {
  2496. //
  2497. // In this case, we need to indicate an override subpath of the root,
  2498. // or else all subsequent accesses will still try to append the subpath
  2499. // specified in the copy node, which is not what we want.
  2500. //
  2501. SubPath[0] = TEXT('\\');
  2502. SubPath[1] = 0;
  2503. }
  2504. }
  2505. } else {
  2506. //
  2507. // Root path matches what we are currently using.
  2508. //
  2509. // See if the tail of the user-specified path matches the existing
  2510. // subpath. If not, then use the rest of the root path as the subpath
  2511. // override. If the tail matches, then extend the user override root.
  2512. //
  2513. // Examples:
  2514. //
  2515. // File was queued with root = f:\, subpath = \amd64
  2516. //
  2517. // User override path is f:\amd64
  2518. //
  2519. // The new status will be leave override root alone;
  2520. // override subpath = \amd64
  2521. //
  2522. // File was queued with root = \\foo\bar, subpath = \i386
  2523. //
  2524. // User override path is \\foo\bar\new\i386
  2525. //
  2526. // The new status will be a root override of \\foo\bar\new;
  2527. // no override subpath.
  2528. //
  2529. NewPath += u;
  2530. if(*NewPath == TEXT('\\')) {
  2531. NewPath++;
  2532. }
  2533. if(path) {
  2534. u = lstrlen(NewPath);
  2535. l = lstrlen(path);
  2536. if((u >= l) && !lstrcmpi(NewPath+u-l,path)) {
  2537. //
  2538. // Change root override and indicate no override subpath.
  2539. //
  2540. SubPath[0] = TEXT('\0');
  2541. NewPath[u-l] = TEXT('\0');
  2542. lstrcpy(RootPath,root);
  2543. pSetupConcatenatePaths(RootPath,NewPath,MAX_PATH,NULL);
  2544. u = lstrlen(RootPath);
  2545. if(u && (*CharPrev(RootPath,RootPath+u) == TEXT('\\'))) {
  2546. RootPath[u-1] = TEXT('\0'); // valid to do if last char is '\'
  2547. }
  2548. } else {
  2549. //
  2550. // Leave override root alone but change subpath.
  2551. //
  2552. lstrcpy(SubPath,NewPath);
  2553. if(!SubPath[0]) {
  2554. SubPath[0] = TEXT('\\');
  2555. SubPath[1] = TEXT('\0');
  2556. }
  2557. }
  2558. } else {
  2559. //
  2560. // File was queued without a subpath. If there's a subpath
  2561. // in what the user gave us, use it as the override.
  2562. //
  2563. if(*NewPath) {
  2564. lstrcpy(SubPath,NewPath);
  2565. }
  2566. }
  2567. }
  2568. }
  2569. UINT
  2570. pSetupCabinetQueueCallback(
  2571. IN PVOID Context,
  2572. IN UINT Notification,
  2573. IN UINT_PTR Param1,
  2574. IN UINT_PTR Param2
  2575. )
  2576. {
  2577. UINT rc;
  2578. PCABINET_INFO CabinetInfo;
  2579. PFILE_IN_CABINET_INFO FileInfo;
  2580. TCHAR TempPath[MAX_PATH];
  2581. PTSTR CabinetFile;
  2582. PTSTR QueuedFile;
  2583. PTSTR FilePart1,FilePart2;
  2584. PTSTR FullTargetPath;
  2585. PFILEPATHS FilePaths;
  2586. PSP_FILE_QUEUE_NODE QueueNode,FirstNode,LastNode;
  2587. PQ_CAB_CB_DATA QData;
  2588. UINT h;
  2589. SOURCE_MEDIA SourceMedia;
  2590. DWORD status;
  2591. QData = (PQ_CAB_CB_DATA)Context;
  2592. switch(Notification) {
  2593. case SPFILENOTIFY_CABINETINFO:
  2594. //
  2595. // We don't do anything with this.
  2596. //
  2597. rc = NO_ERROR;
  2598. break;
  2599. case SPFILENOTIFY_FILEINCABINET:
  2600. //
  2601. // New file within a cabinet.
  2602. //
  2603. // Determine whether we want to copy this file.
  2604. // The context we get has all the stuff we need in it
  2605. // to make this determination.
  2606. //
  2607. // Note that the queue could contain multiple copy operations
  2608. // involving this file, but we only want to extract it once!
  2609. //
  2610. FileInfo = (PFILE_IN_CABINET_INFO)Param1;
  2611. CabinetFile = (PTSTR)Param2;
  2612. if(FilePart1 = _tcsrchr(FileInfo->NameInCabinet,TEXT('\\'))) {
  2613. FilePart1++;
  2614. } else {
  2615. FilePart1 = (PTSTR)FileInfo->NameInCabinet;
  2616. }
  2617. rc = FILEOP_SKIP;
  2618. FileInfo->Win32Error = NO_ERROR;
  2619. FirstNode = NULL;
  2620. //
  2621. // Find ALL instances of this file in the queue and mark them.
  2622. //
  2623. for(QueueNode=QData->SourceMedia->CopyQueue; QueueNode; QueueNode=QueueNode->Next) {
  2624. if(QueueNode->InternalFlags & IQF_PROCESSED) {
  2625. //
  2626. // This file was already processed. Ignore it.
  2627. //
  2628. continue;
  2629. }
  2630. //
  2631. // Check the filename in the cabinet against the file
  2632. // in the media's copy queue.
  2633. //
  2634. QueuedFile = pSetupStringTableStringFromId(
  2635. QData->Queue->StringTable,
  2636. QueueNode->SourceFilename
  2637. );
  2638. if(FilePart2 = _tcsrchr(QueuedFile,TEXT('\\'))) {
  2639. FilePart2++;
  2640. } else {
  2641. FilePart2 = QueuedFile;
  2642. }
  2643. if(!lstrcmpi(FilePart1,FilePart2)) {
  2644. //
  2645. // We want this file.
  2646. //
  2647. rc = FILEOP_DOIT;
  2648. QueueNode->InternalFlags |= IQF_PROCESSED | IQF_MATCH;
  2649. if(!FirstNode) {
  2650. FirstNode = QueueNode;
  2651. }
  2652. LastNode = QueueNode;
  2653. }
  2654. }
  2655. if(rc == FILEOP_DOIT) {
  2656. //
  2657. // We want this file. Tell the caller the full target pathname
  2658. // to be used, which is a temporary file in the directory
  2659. // where the first instance of the file will ultimately go.
  2660. // We do this so we can call SetupInstallFile later (perhaps
  2661. // multiple times), which will handle version checks, etc.
  2662. //
  2663. // Before attempting to create a temp file make sure the path exists.
  2664. //
  2665. lstrcpyn(
  2666. TempPath,
  2667. pSetupStringTableStringFromId(QData->Queue->StringTable,FirstNode->TargetDirectory),
  2668. MAX_PATH
  2669. );
  2670. pSetupConcatenatePaths(TempPath,TEXT("x"),MAX_PATH,NULL); // last component ignored
  2671. status = pSetupMakeSurePathExists(TempPath);
  2672. if(status == NO_ERROR) {
  2673. LastNode->InternalFlags |= IQF_LAST_MATCH;
  2674. if(GetTempFileName(
  2675. pSetupStringTableStringFromId(QData->Queue->StringTable,FirstNode->TargetDirectory),
  2676. TEXT("SETP"),
  2677. 0,
  2678. FileInfo->FullTargetName
  2679. )) {
  2680. QData->CurrentFirstNode = FirstNode;
  2681. } else {
  2682. status = GetLastError();
  2683. if(status == ERROR_ACCESS_DENIED) {
  2684. FileInfo->Win32Error = ERROR_INVALID_TARGET;
  2685. } else {
  2686. FileInfo->Win32Error = status;
  2687. }
  2688. rc = FILEOP_ABORT;
  2689. SetLastError(FileInfo->Win32Error);
  2690. }
  2691. } else {
  2692. if(status == ERROR_ACCESS_DENIED) {
  2693. FileInfo->Win32Error = ERROR_INVALID_TARGET;
  2694. } else {
  2695. FileInfo->Win32Error = status;
  2696. }
  2697. rc = FILEOP_ABORT;
  2698. SetLastError(FileInfo->Win32Error);
  2699. }
  2700. }
  2701. break;
  2702. case SPFILENOTIFY_FILEEXTRACTED:
  2703. FilePaths = (PFILEPATHS)Param1;
  2704. //
  2705. // The current file was extracted. If this was successful,
  2706. // then we need to call SetupInstallFile on it to perform version
  2707. // checks and move it into its final location or locations.
  2708. //
  2709. // The .Source member of FilePaths is the cabinet file.
  2710. //
  2711. // The .Target member is the name of the temporary file, which is
  2712. // very useful, as it is the name if the file to use as the source
  2713. // in copy operations.
  2714. //
  2715. // Process each file in the queue that we care about.
  2716. //
  2717. if((rc = FilePaths->Win32Error) == NO_ERROR) {
  2718. for(QueueNode=QData->CurrentFirstNode; QueueNode && (rc==NO_ERROR); QueueNode=QueueNode->Next) {
  2719. //
  2720. // If we don't care about this file, skip it.
  2721. //
  2722. if(!(QueueNode->InternalFlags & IQF_MATCH)) {
  2723. continue;
  2724. }
  2725. QueueNode->InternalFlags &= ~IQF_MATCH;
  2726. rc = pSetupCopySingleQueuedFileCabCase(
  2727. QData->Queue,
  2728. QueueNode,
  2729. FilePaths->Source,
  2730. FilePaths->Target,
  2731. QData->MsgHandler,
  2732. QData->Context,
  2733. QData->IsMsgHandlerNativeCharWidth
  2734. );
  2735. //
  2736. // If this was the last file that matched, break out.
  2737. //
  2738. if(QueueNode->InternalFlags & IQF_LAST_MATCH) {
  2739. QueueNode->InternalFlags &= ~IQF_LAST_MATCH;
  2740. break;
  2741. }
  2742. }
  2743. }
  2744. //
  2745. // Delete the temporary file we extracted -- we don't need it any more.
  2746. //
  2747. DeleteFile(FilePaths->Target);
  2748. break;
  2749. case SPFILENOTIFY_NEEDNEWCABINET:
  2750. //
  2751. // Need a new cabinet.
  2752. //
  2753. CabinetInfo = (PCABINET_INFO)Param1;
  2754. SourceMedia.Tagfile = NULL;
  2755. SourceMedia.Description = CabinetInfo->DiskName;
  2756. SourceMedia.SourcePath = CabinetInfo->CabinetPath;
  2757. SourceMedia.SourceFile = CabinetInfo->CabinetFile;
  2758. SourceMedia.Flags = SP_FLAG_CABINETCONTINUATION | SP_COPY_NOSKIP;
  2759. h = pSetupCallMsgHandler(
  2760. QData->LogContext,
  2761. QData->MsgHandler,
  2762. QData->IsMsgHandlerNativeCharWidth,
  2763. QData->Context,
  2764. SPFILENOTIFY_NEEDMEDIA,
  2765. (UINT_PTR)&SourceMedia,
  2766. Param2
  2767. );
  2768. switch(h) {
  2769. case FILEOP_NEWPATH:
  2770. case FILEOP_DOIT:
  2771. rc = NO_ERROR;
  2772. break;
  2773. case FILEOP_ABORT:
  2774. rc = GetLastError();
  2775. if(!rc) {
  2776. rc = ERROR_OPERATION_ABORTED;
  2777. }
  2778. break;
  2779. default:
  2780. rc = ERROR_OPERATION_ABORTED;
  2781. break;
  2782. }
  2783. //
  2784. // in this case, rc is a status code
  2785. // but also set it as last error
  2786. //
  2787. SetLastError(rc);
  2788. break;
  2789. default:
  2790. MYASSERT(0);
  2791. rc = 0; // indeterminate
  2792. }
  2793. return(rc);
  2794. }
  2795. DWORD
  2796. pSetupCopySingleQueuedFile(
  2797. IN PSP_FILE_QUEUE Queue,
  2798. IN PSP_FILE_QUEUE_NODE QueueNode,
  2799. IN PCTSTR FullSourceName,
  2800. IN PVOID MsgHandler,
  2801. IN PVOID Context,
  2802. OUT PTSTR NewSourcePath,
  2803. IN BOOL IsMsgHandlerNativeCharWidth,
  2804. IN DWORD CopyStyleFlags
  2805. )
  2806. {
  2807. PTSTR FullTargetName;
  2808. FILEPATHS FilePaths;
  2809. UINT u;
  2810. BOOL InUse;
  2811. TCHAR source[MAX_PATH],PathBuffer[MAX_PATH];
  2812. DWORD rc;
  2813. BOOL b;
  2814. BOOL BackupInUse = FALSE;
  2815. BOOL SignatureVerifyFailed;
  2816. NewSourcePath[0] = 0;
  2817. PathBuffer[0] = 0;
  2818. QueueNode->InternalFlags |= IQF_PROCESSED;
  2819. //
  2820. // Form the full target path of the file.
  2821. //
  2822. FullTargetName = pSetupFormFullPath(
  2823. Queue->StringTable,
  2824. QueueNode->TargetDirectory,
  2825. QueueNode->TargetFilename,
  2826. -1
  2827. );
  2828. if(!FullTargetName) {
  2829. return(ERROR_NOT_ENOUGH_MEMORY);
  2830. }
  2831. lstrcpyn(source,FullSourceName,MAX_PATH);
  2832. //
  2833. // check if we need to backup before we copy
  2834. //
  2835. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  2836. FullTargetName,
  2837. 0,
  2838. NULL)) != NO_ERROR) {
  2839. MyFree(FullTargetName);
  2840. goto clean0;
  2841. }
  2842. rc = pSetupCommitSingleBackup(Queue,
  2843. FullTargetName,
  2844. QueueNode->TargetDirectory,
  2845. -1,
  2846. QueueNode->TargetFilename,
  2847. MsgHandler,
  2848. Context,
  2849. IsMsgHandlerNativeCharWidth,
  2850. (QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE),
  2851. &BackupInUse
  2852. );
  2853. if (rc != NO_ERROR) {
  2854. MyFree(FullTargetName);
  2855. goto clean0;
  2856. }
  2857. if (BackupInUse) {
  2858. //
  2859. // if we couldn't do backup, force the IN_USE flag
  2860. //
  2861. QueueNode->StyleFlags |= SP_COPY_FORCE_IN_USE;
  2862. }
  2863. do {
  2864. //
  2865. // Form the full source name.
  2866. //
  2867. FilePaths.Source = source;
  2868. FilePaths.Target = FullTargetName;
  2869. FilePaths.Win32Error = NO_ERROR;
  2870. //
  2871. // Also, pass the callback routine the CopyStyle flags we're about to
  2872. // use.
  2873. //
  2874. // Callback flags are read-only.
  2875. //
  2876. FilePaths.Flags = QueueNode->StyleFlags;
  2877. //
  2878. // Notify the callback that the copy is starting.
  2879. //
  2880. u = pSetupCallMsgHandler(
  2881. Queue->LogContext,
  2882. MsgHandler,
  2883. IsMsgHandlerNativeCharWidth,
  2884. Context,
  2885. SPFILENOTIFY_STARTCOPY,
  2886. (UINT_PTR)&FilePaths,
  2887. FILEOP_COPY
  2888. );
  2889. if(u == FILEOP_ABORT) {
  2890. rc = GetLastError();
  2891. if(!rc) {
  2892. rc = ERROR_OPERATION_ABORTED;
  2893. }
  2894. WriteLogEntry(
  2895. Queue->LogContext,
  2896. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  2897. MSG_LOG_STARTCOPY_ABORT,
  2898. NULL);
  2899. WriteLogError(Queue->LogContext,
  2900. SETUP_LOG_ERROR,
  2901. rc);
  2902. break;
  2903. }
  2904. if(u == FILEOP_DOIT) {
  2905. //
  2906. // Attempt the copy.
  2907. //
  2908. //
  2909. b = _SetupInstallFileEx(
  2910. Queue,
  2911. QueueNode,
  2912. NULL, // no inf handle
  2913. NULL, // no inf context
  2914. source,
  2915. NULL, // source path root is part of FullSourcePath
  2916. FullTargetName,
  2917. QueueNode->StyleFlags | SP_COPY_SOURCE_ABSOLUTE | CopyStyleFlags,
  2918. MsgHandler,
  2919. Context,
  2920. &InUse,
  2921. IsMsgHandlerNativeCharWidth,
  2922. &SignatureVerifyFailed
  2923. );
  2924. rc = b ? NO_ERROR : GetLastError();
  2925. if(b || (rc == NO_ERROR)) {
  2926. if(!InUse && (QueueNode->SecurityDesc != -1)){
  2927. //
  2928. // Set security on the file
  2929. //
  2930. rc = pSetupCallSCE(ST_SCE_SET,
  2931. FullTargetName,
  2932. Queue,
  2933. NULL,
  2934. QueueNode->SecurityDesc,
  2935. NULL
  2936. );
  2937. }
  2938. }
  2939. if(rc == NO_ERROR) {
  2940. //
  2941. // File was copied or not copied, but it if was not copied
  2942. // the callback funtcion was already notified about why
  2943. // (version check failed, etc).
  2944. //
  2945. if(QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE) {
  2946. //
  2947. // _SetupInstallFileEx is responsible for failing the copy
  2948. // when some yahoo comes and copies over a new file (and
  2949. // locks it) before we get a chance to.
  2950. //
  2951. MYASSERT(!InUse);
  2952. //
  2953. // If the file was copied, we need to set the wants-reboot
  2954. // flag. Otherwise, we need to put back the original file.
  2955. //
  2956. if(b) {
  2957. QueueNode->InternalFlags |= INUSE_INF_WANTS_REBOOT;
  2958. } else {
  2959. RestoreBootReplacedFile(Queue, QueueNode);
  2960. }
  2961. } else {
  2962. if(InUse) {
  2963. QueueNode->InternalFlags |= (QueueNode->StyleFlags & SP_COPY_IN_USE_NEEDS_REBOOT)
  2964. ? INUSE_INF_WANTS_REBOOT
  2965. : INUSE_IN_USE;
  2966. }
  2967. }
  2968. } else {
  2969. DWORD LogTag = 0;
  2970. //
  2971. // File was not copied and a real error occurred.
  2972. // Notify the callback (unless the failure was due to a
  2973. // signature verification problem). Disallow skip if that is
  2974. // specified in the node's flags.
  2975. //
  2976. if(SignatureVerifyFailed) {
  2977. break;
  2978. } else {
  2979. LogTag = AllocLogInfoSlotOrLevel(Queue->LogContext,SETUP_LOG_INFO,FALSE);
  2980. FilePaths.Win32Error = rc;
  2981. FilePaths.Flags = QueueNode->StyleFlags & (SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP | SP_COPY_NOBROWSE);
  2982. WriteLogEntry(
  2983. Queue->LogContext,
  2984. LogTag,
  2985. MSG_LOG_COPYERROR,
  2986. NULL,
  2987. FilePaths.Source,
  2988. FilePaths.Target,
  2989. FilePaths.Flags,
  2990. FilePaths.Win32Error
  2991. );
  2992. u = pSetupCallMsgHandler(
  2993. Queue->LogContext,
  2994. MsgHandler,
  2995. IsMsgHandlerNativeCharWidth,
  2996. Context,
  2997. SPFILENOTIFY_COPYERROR,
  2998. (UINT_PTR)&FilePaths,
  2999. (UINT_PTR)PathBuffer
  3000. );
  3001. if(u == FILEOP_ABORT) {
  3002. rc = GetLastError();
  3003. if(!rc) {
  3004. rc = ERROR_OPERATION_ABORTED;
  3005. }
  3006. }
  3007. }
  3008. if(u == FILEOP_ABORT) {
  3009. WriteLogEntry(
  3010. Queue->LogContext,
  3011. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  3012. MSG_LOG_COPYERROR_ABORT,
  3013. NULL
  3014. );
  3015. WriteLogError(Queue->LogContext,
  3016. SETUP_LOG_ERROR,
  3017. rc
  3018. );
  3019. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3020. LogTag = 0;
  3021. break;
  3022. } else {
  3023. if(u == FILEOP_SKIP) {
  3024. //
  3025. // If this file was a bootfile replacement, then we need
  3026. // to restore the original file that was renamed to a
  3027. // temporary filename.
  3028. //
  3029. if(QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE) {
  3030. RestoreBootReplacedFile(Queue, QueueNode);
  3031. }
  3032. WriteLogEntry(
  3033. Queue->LogContext,
  3034. SETUP_LOG_WARNING,
  3035. MSG_LOG_COPYERROR_SKIP,
  3036. NULL
  3037. );
  3038. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3039. LogTag = 0;
  3040. //
  3041. // Force termination of processing for this file.
  3042. //
  3043. rc = NO_ERROR;
  3044. break;
  3045. } else {
  3046. if((u == FILEOP_NEWPATH) || ((u == FILEOP_RETRY) && PathBuffer[0])) {
  3047. WriteLogEntry(
  3048. Queue->LogContext,
  3049. SETUP_LOG_WARNING,
  3050. MSG_LOG_COPYERROR_NEWPATH,
  3051. NULL,
  3052. u,
  3053. PathBuffer
  3054. );
  3055. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3056. LogTag = 0;
  3057. //
  3058. // Note that rc is already set to something other than
  3059. // NO_ERROR or we wouldn't be here.
  3060. //
  3061. lstrcpyn(NewSourcePath,PathBuffer,MAX_PATH);
  3062. lstrcpyn(source,NewSourcePath,MAX_PATH);
  3063. pSetupConcatenatePaths(
  3064. source,
  3065. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename),
  3066. MAX_PATH,
  3067. NULL
  3068. );
  3069. }
  3070. //
  3071. // Else we don't have a new path.
  3072. // Just keep using the one we had.
  3073. //
  3074. }
  3075. }
  3076. if (LogTag != 0) {
  3077. //
  3078. // haven't done anything regards logging yet, do it now
  3079. //
  3080. WriteLogEntry(
  3081. Queue->LogContext,
  3082. SETUP_LOG_INFO,
  3083. MSG_LOG_COPYERROR_RETRY,
  3084. NULL,
  3085. u
  3086. );
  3087. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3088. LogTag = 0;
  3089. }
  3090. }
  3091. } else {
  3092. //
  3093. // skip file
  3094. //
  3095. WriteLogEntry(
  3096. Queue->LogContext,
  3097. SETUP_LOG_INFO, // info level as this would be due to override of callback
  3098. MSG_LOG_STARTCOPY_SKIP,
  3099. NULL,
  3100. u
  3101. );
  3102. rc = NO_ERROR;
  3103. }
  3104. } while(rc != NO_ERROR);
  3105. //
  3106. // Notify the callback that the copy is done.
  3107. //
  3108. FilePaths.Win32Error = rc;
  3109. pSetupCallMsgHandler(
  3110. Queue->LogContext,
  3111. MsgHandler,
  3112. IsMsgHandlerNativeCharWidth,
  3113. Context,
  3114. SPFILENOTIFY_ENDCOPY,
  3115. (UINT_PTR)&FilePaths,
  3116. 0
  3117. );
  3118. MyFree(FullTargetName);
  3119. clean0:
  3120. return(rc);
  3121. }
  3122. DWORD
  3123. pSetupCopySingleQueuedFileCabCase(
  3124. IN PSP_FILE_QUEUE Queue,
  3125. IN PSP_FILE_QUEUE_NODE QueueNode,
  3126. IN PCTSTR CabinetName,
  3127. IN PCTSTR FullSourceName,
  3128. IN PVOID MsgHandler,
  3129. IN PVOID Context,
  3130. IN BOOL IsMsgHandlerNativeCharWidth
  3131. )
  3132. {
  3133. PTSTR FullTargetName;
  3134. FILEPATHS FilePaths;
  3135. UINT u;
  3136. BOOL InUse;
  3137. TCHAR PathBuffer[MAX_PATH];
  3138. DWORD rc;
  3139. BOOL b;
  3140. BOOL BackupInUse = FALSE;
  3141. BOOL DontCare;
  3142. DWORD LogTag = 0;
  3143. LPCTSTR SourceName;
  3144. //
  3145. // Form the full target path of the file.
  3146. //
  3147. SourceName = pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename);
  3148. FullTargetName = pSetupFormFullPath(
  3149. Queue->StringTable,
  3150. QueueNode->TargetDirectory,
  3151. QueueNode->TargetFilename,
  3152. -1
  3153. );
  3154. if(!FullTargetName) {
  3155. return(ERROR_NOT_ENOUGH_MEMORY);
  3156. }
  3157. LogTag = AllocLogInfoSlotOrLevel(Queue->LogContext,SETUP_LOG_INFO,FALSE);
  3158. WriteLogEntry(
  3159. Queue->LogContext,
  3160. LogTag,
  3161. MSG_LOG_COPY_FROM_CAB,
  3162. NULL,
  3163. CabinetName,
  3164. SourceName,
  3165. FullSourceName,
  3166. FullTargetName
  3167. );
  3168. //
  3169. // check if we need to backup before we copy
  3170. //
  3171. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  3172. FullTargetName,
  3173. 0,
  3174. NULL)) != NO_ERROR) {
  3175. MyFree(FullTargetName);
  3176. goto clean0;
  3177. }
  3178. rc = pSetupCommitSingleBackup(Queue,
  3179. FullTargetName,
  3180. QueueNode->TargetDirectory,
  3181. -1,
  3182. QueueNode->TargetFilename,
  3183. MsgHandler,
  3184. Context,
  3185. IsMsgHandlerNativeCharWidth,
  3186. (QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE),
  3187. &BackupInUse
  3188. );
  3189. if (rc != NO_ERROR) {
  3190. MyFree(FullTargetName);
  3191. goto clean0;
  3192. }
  3193. if (BackupInUse) {
  3194. //
  3195. // if we couldn't do backup, force the IN_USE flag
  3196. //
  3197. QueueNode->StyleFlags |= SP_COPY_FORCE_IN_USE;
  3198. }
  3199. //
  3200. // We use the cabinet name as the source name so the display looks right
  3201. // to the user. Otherwise he sees the name of some temp file in the
  3202. // source field.
  3203. //
  3204. FilePaths.Source = CabinetName;
  3205. FilePaths.Target = FullTargetName;
  3206. FilePaths.Win32Error = NO_ERROR;
  3207. //
  3208. // Also, pass the callback routine the CopyStyle flags we're about to
  3209. // use.
  3210. //
  3211. // Callback flags are read-only.
  3212. //
  3213. FilePaths.Flags = QueueNode->StyleFlags;
  3214. do {
  3215. //
  3216. // Notify the callback that the copy is starting.
  3217. //
  3218. u = pSetupCallMsgHandler(
  3219. Queue->LogContext,
  3220. MsgHandler,
  3221. IsMsgHandlerNativeCharWidth,
  3222. Context,
  3223. SPFILENOTIFY_STARTCOPY,
  3224. (UINT_PTR)&FilePaths,
  3225. FILEOP_COPY
  3226. );
  3227. if(u == FILEOP_ABORT) {
  3228. rc = GetLastError();
  3229. if(!rc) {
  3230. rc = ERROR_OPERATION_ABORTED;
  3231. }
  3232. break;
  3233. }
  3234. if(u == FILEOP_DOIT) {
  3235. //
  3236. // Attempt the copy.
  3237. //
  3238. b = _SetupInstallFileEx(
  3239. Queue,
  3240. QueueNode,
  3241. NULL, // no inf handle
  3242. NULL, // no inf context
  3243. FullSourceName,
  3244. NULL, // source path root is part of FullSourcePath
  3245. FullTargetName,
  3246. QueueNode->StyleFlags | SP_COPY_SOURCE_ABSOLUTE,
  3247. MsgHandler,
  3248. Context,
  3249. &InUse,
  3250. IsMsgHandlerNativeCharWidth,
  3251. &DontCare
  3252. );
  3253. if(b || ((rc = GetLastError()) == NO_ERROR)) {
  3254. if(!InUse && (QueueNode->SecurityDesc != -1) ){
  3255. // Set security on the file
  3256. rc = pSetupCallSCE(
  3257. ST_SCE_SET,
  3258. FullTargetName,
  3259. Queue,
  3260. NULL,
  3261. QueueNode->SecurityDesc,
  3262. NULL
  3263. );
  3264. SetLastError( rc );
  3265. }
  3266. }
  3267. if(b || ((rc = GetLastError()) == NO_ERROR)) {
  3268. //
  3269. // File was copied or not copied, but it if was not copied
  3270. // the callback funtcion was already notified about why
  3271. // (version check failed, etc).
  3272. //
  3273. if(InUse) {
  3274. QueueNode->InternalFlags |= (QueueNode->StyleFlags & SP_COPY_IN_USE_NEEDS_REBOOT)
  3275. ? INUSE_INF_WANTS_REBOOT
  3276. : INUSE_IN_USE;
  3277. }
  3278. rc = NO_ERROR;
  3279. } else {
  3280. //
  3281. // File was not copied and a real error occurred.
  3282. // Break out and return the error.
  3283. //
  3284. break;
  3285. }
  3286. } else {
  3287. //
  3288. // skip file
  3289. //
  3290. rc = NO_ERROR;
  3291. }
  3292. } while(rc != NO_ERROR);
  3293. //
  3294. // Notify the callback that the copy is done.
  3295. //
  3296. FilePaths.Win32Error = rc;
  3297. pSetupCallMsgHandler(
  3298. Queue->LogContext,
  3299. MsgHandler,
  3300. IsMsgHandlerNativeCharWidth,
  3301. Context,
  3302. SPFILENOTIFY_ENDCOPY,
  3303. (UINT_PTR)&FilePaths,
  3304. 0
  3305. );
  3306. MyFree(FullTargetName);
  3307. clean0:
  3308. if(LogTag) {
  3309. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3310. }
  3311. return(rc);
  3312. }
  3313. PTSTR
  3314. pSetupFormFullPath(
  3315. IN PVOID StringTable,
  3316. IN LONG PathPart1,
  3317. IN LONG PathPart2, OPTIONAL
  3318. IN LONG PathPart3 OPTIONAL
  3319. )
  3320. /*++
  3321. Routine Description:
  3322. Form a full path based on components whose strings are in a string
  3323. table.
  3324. Arguments:
  3325. StringTable - supplies handle to string table.
  3326. PathPart1 - Supplies first part of path
  3327. PathPart2 - if specified, supplies second part of path
  3328. PathPart3 - if specified, supplies third part of path
  3329. Return Value:
  3330. Pointer to buffer containing full path. Caller can free with MyFree().
  3331. NULL if out of memory.
  3332. --*/
  3333. {
  3334. UINT RequiredSize;
  3335. PCTSTR p1,p2,p3;
  3336. TCHAR Buffer[MAX_PATH];
  3337. p1 = pSetupStringTableStringFromId(StringTable,PathPart1);
  3338. if (!p1) {
  3339. return NULL;
  3340. }
  3341. p2 = (PathPart2 == -1) ? NULL : pSetupStringTableStringFromId(StringTable,PathPart2);
  3342. p3 = (PathPart3 == -1) ? NULL : pSetupStringTableStringFromId(StringTable,PathPart3);
  3343. lstrcpy(Buffer,p1);
  3344. if(!p2 || pSetupConcatenatePaths(Buffer,p2,MAX_PATH,NULL)) {
  3345. if(p3) {
  3346. pSetupConcatenatePaths(Buffer,p3,MAX_PATH,NULL);
  3347. }
  3348. }
  3349. return(DuplicateString(Buffer));
  3350. }
  3351. DWORD
  3352. pSetupVerifyQueuedCatalogs(
  3353. IN HSPFILEQ FileQueue
  3354. )
  3355. /*++
  3356. Routine Description:
  3357. Silently verify all catalog nodes in the specified queue.
  3358. Arguments:
  3359. FileQueue - supplies a handle to the file queue containing catalog nodes
  3360. to be verified.
  3361. Return Value:
  3362. If all catalog nodes are valid, the return value is NO_ERROR. Otherwise,
  3363. it is a Win32 error code indicating the problem.
  3364. --*/
  3365. {
  3366. return _SetupVerifyQueuedCatalogs(NULL, // No UI, thus no HWND needed
  3367. (PSP_FILE_QUEUE)FileQueue,
  3368. VERCAT_NO_PROMPT_ON_ERROR,
  3369. NULL,
  3370. NULL
  3371. );
  3372. }
  3373. DWORD
  3374. _SetupVerifyQueuedCatalogs(
  3375. IN HWND Owner,
  3376. IN PSP_FILE_QUEUE Queue,
  3377. IN DWORD Flags,
  3378. OUT PTSTR DeviceInfFinalName, OPTIONAL
  3379. OUT PBOOL DeviceInfNewlyCopied OPTIONAL
  3380. )
  3381. /*++
  3382. Routine Description:
  3383. This routine verifies catalogs and infs in a given queue by traversing
  3384. the catalog node list associated with the queue and operating on the
  3385. catalog/inf pair described by each one.
  3386. If any catalog/inf fails verification, the user is notified via a dialog,
  3387. depending on current policy.
  3388. ** Behavior for native platform verification (w/o catalog override)
  3389. If an INF is from a system location, we assume that the catalog is
  3390. already installed on the system. Really there is no other option here,
  3391. since we would have no idea where to get the catalog in order to install it
  3392. even if we wanted to try. But the inf might have originally been an
  3393. oem inf which was copied and renamed by the Di stuff at device install
  3394. time. The catalog file knows nothing about the renamed file, so we must
  3395. track mappings from current inf filename to original inf filename.
  3396. In this case, we calculate the inf's hash value and then using that,
  3397. we ask the system for a catalog file that contains signing data
  3398. for that hash value. We then ask the system for info
  3399. about that catalog file. We keep repeating this process until we get
  3400. at the catalog we want (based on name). Finally we can call WinVerifyTrust
  3401. verify the catalog itself and the inf.
  3402. If an INF file is instead from an oem location, we copy the oem inf to a
  3403. unique name in the system inf directory (or create a zero-length placeholder
  3404. there, depending on whether or not the VERCAT_INSTALL_INF_AND_CAT flag is
  3405. set), and add the catalog using a filename based on that unique filename.
  3406. ** Behavior for non-native platform verification (w/o catalog override) **
  3407. We will validate the catalogs and INFs using the alternate platform info
  3408. provided in the file queue. Otherwise, the logic is the same as in the
  3409. native case.
  3410. ** Behavior for verification (w/catalog override) **
  3411. The actual verification will be done using native or non-native parameters
  3412. as discussed above, but INFs without a CatalogFile= entry will be validated
  3413. against the specified overriding catalog. This means that system INFs won't
  3414. get validated globally, and INF in OEM locations can be validated even if
  3415. they don't have a CatalogFile= entry. The overriding catalog file will be
  3416. installed under its current name, thus blowing away any existing catalog
  3417. having that name.
  3418. ** Behavior for verification via Authenticode catalog **
  3419. If the specified queue has the DRIVERSIGN_ALLOW_AUTHENTICODE bit set in its
  3420. driver signing policy, then we'll allow catalogs to be signed via
  3421. Authenticode, instead of our default (requiring MS cert chain and OS code-
  3422. signing usage OID).
  3423. Here's the algorithm for how we'll do digital signature verification for a
  3424. self-contained driver package:
  3425. * Check for WHQL signature on driver package INF using corresponding CAT.
  3426. * If valid WHQL signature - Install Driver (no UI)
  3427. * If invalid or no WHQL signature - log an entry to setupapi.log, check
  3428. if there's a WHQL program for this device setup class (list of
  3429. classes in %windir%\Inf\certclas.inf)
  3430. * If yes - check driver signing policy
  3431. * If Block - terminate installation
  3432. * If Warn - issue warning, install driver (customer option)
  3433. * If Ignore - install driver (no UI)
  3434. * If no - check for Authenticode (TM) signature on driver package
  3435. INF using corresponding CAT. (signature must chain up through an
  3436. existing root certificate)
  3437. * If valid Authenticode signature - check for matching signing
  3438. certificate in Authenticode certificate store
  3439. * If Authenticode signing certificate installed, install
  3440. driver (no UI)
  3441. * If Authenticode signing certificate not installed, check
  3442. driver signing policy
  3443. * If Block - terminate installation (Authenticode
  3444. signature does not allow vendors to by-pass Block
  3445. policy)
  3446. * If Warn - issue warning (but indicate that package is
  3447. signed by vendor), install driver (customer option)
  3448. * If Ignore - install driver (no UI)
  3449. * If invalid or no Authenticode signature, check driver signing
  3450. policy
  3451. * If Block, terminate installation
  3452. * If Warn, issue warning (indicating package's author/
  3453. integrity cannot be established), install driver
  3454. (customer option)
  3455. * If Ignore, install driver (no UI)
  3456. See the documentation on SetupSetFileQueueAlternatePlatform for more
  3457. details.
  3458. Arguments:
  3459. Owner - supplies window handle of window to own any ui. This HWND is stored
  3460. away in the queue for use later if any individual files fail verification.
  3461. Queue - supplies pointer to queue structure.
  3462. Flags - supplies flags that control behavior of this routine.
  3463. VERCAT_INSTALL_INF_AND_CAT - if this flag is set, any infs from
  3464. oem locations will be installed on the system, along with
  3465. their catalog files.
  3466. VERCAT_NO_PROMPT_ON_ERROR - if this flag is set, the user will _not_ be
  3467. notified about verification failures we encounter. If this flag is
  3468. set, then this was only a 'test', and no user prompting should take
  3469. place (nor should any PSS logging take place). If this flag is set,
  3470. then the VERCAT_INSTALL_INF_AND_CAT _should not_ be specified.
  3471. VERCAT_PRIMARY_DEVICE_INF_FROM_INET - specifies that the primary device
  3472. INF in the queue is from the internet, and should be marked as such
  3473. in the corresponding PNF when installed into the %windir%\Inf
  3474. directory via _SetupCopyOEMInf.
  3475. DeviceInfFinalName - optionally, supplies the address of a character buffer,
  3476. _at least_ MAX_PATH characters long, that upon success receives the
  3477. final name given to the INF under the %windir%\Inf directory (this will
  3478. be different than the INF's original name if it was an OEM INF).
  3479. DeviceInfNewlyCopied - optionally, supplies the address of a boolean
  3480. variable that, upon success, is set to indicate whether the INF name
  3481. returned in DeviceInfFinalName was newly-created. If this parameter is
  3482. supplied, then DeviceInfFinalName must also be specified.
  3483. Return Value:
  3484. If all catalogs/infs were verified and installed, or the user accepted
  3485. the risk if a verification failed, then the return value is NO_ERROR.
  3486. If one or more catalogs/infs were not verified, the return value is a Win32
  3487. error code indicating the cause of the failure. NOTE: This error will
  3488. only be returned if the policy is "block", or it it's "warn" and the
  3489. user decided to abort. In this case, the error returned is for the
  3490. catalog/INF where the error was encountered, and any subsequent catalog
  3491. nodes will not have been verified. An exception to this is when the
  3492. VERCAT_NO_PROMPT_ON_ERROR flag is set. In that case, we'll verify all
  3493. catalogs, even if we encounter improperly-signed ones.
  3494. Remarks:
  3495. There are some system INFs (for which global verification is required) that
  3496. don't live in %windir%\Inf. The OCM INFs are an example of this. Those
  3497. INFs use layout.inf (which _is_ located in %windir%\Inf) for the source
  3498. media information for any files they copy. There are other INFs that don't
  3499. live in %windir%\Inf which are extracted out of a binary as-needed (into a
  3500. temporary filename), processed in order to do registry munging, and then
  3501. deleted. Such INFs do not do file copying (thus their 'package' consists
  3502. of just the INF). To accommodate such INFs, we allow "OEM" INFs (i.e.,
  3503. those INFs not in %windir%\Inf) to be verified globally, but we remember the
  3504. fact that these INFs didn't contain a CatalogFile= entry, and if any files
  3505. are ever queued for copy using such INFs for source media information, then
  3506. we'll fail digital signature verification for such files, since there's no
  3507. way for us to know what catalog should be used for verification.
  3508. --*/
  3509. {
  3510. PSPQ_CATALOG_INFO CatalogNode;
  3511. LPCTSTR InfFullPath;
  3512. LPCTSTR CatName;
  3513. TCHAR PathBuffer[MAX_PATH];
  3514. TCHAR InfNameBuffer[MAX_PATH];
  3515. TCHAR CatalogName[MAX_PATH];
  3516. TCHAR *p;
  3517. DWORD Err, CatalogNodeStatus, ReturnStatus;
  3518. SetupapiVerifyProblem Problem;
  3519. LPCTSTR ProblemFile;
  3520. BOOL DeleteOemInfOnError;
  3521. BOOL OriginalNameDifferent;
  3522. LPCTSTR AltCatalogFile;
  3523. LONG CatStringId;
  3524. ULONG RequiredSize;
  3525. DWORD InfVerifyType;
  3526. DWORD SCOIFlags;
  3527. HANDLE hWVTStateData = NULL;
  3528. DWORD AuthSigPromptCount = 0;
  3529. DWORD CopyStyleFlags;
  3530. BOOL OemInfIsDeviceInf;
  3531. //
  3532. // Define values used to indicate how validation should be done on the INFs.
  3533. //
  3534. #define VERIFY_INF_AS_OEM 0 // verify solely against the specific
  3535. // catalog referenced by the INF
  3536. #define VERIFY_INF_AS_SYSTEM 1 // verify globally (using all catalogs)
  3537. #define VERIFY_OEM_INF_GLOBALLY 2 // verify OEM INF globally, but remember the
  3538. // original error, in case copy operations
  3539. // are queued using media descriptor info
  3540. // within this INF.
  3541. MYASSERT((Flags & (VERCAT_INSTALL_INF_AND_CAT | VERCAT_NO_PROMPT_ON_ERROR))
  3542. != (VERCAT_INSTALL_INF_AND_CAT | VERCAT_NO_PROMPT_ON_ERROR)
  3543. );
  3544. MYASSERT(!DeviceInfNewlyCopied || DeviceInfFinalName);
  3545. if(Queue->Flags & FQF_DID_CATALOGS_OK) {
  3546. //
  3547. // If the caller wants information about the primary device INF, then
  3548. // find the applicable catalog node.
  3549. //
  3550. if(DeviceInfFinalName) {
  3551. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3552. if(CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF) {
  3553. MYASSERT(CatalogNode->InfFinalPath != -1);
  3554. InfFullPath = pSetupStringTableStringFromId(Queue->StringTable, CatalogNode->InfFinalPath);
  3555. lstrcpy(DeviceInfFinalName, InfFullPath);
  3556. if(DeviceInfNewlyCopied) {
  3557. *DeviceInfNewlyCopied = (CatalogNode->Flags & CATINFO_FLAG_NEWLY_COPIED);
  3558. }
  3559. }
  3560. }
  3561. }
  3562. return NO_ERROR;
  3563. }
  3564. if(Queue->Flags & FQF_DID_CATALOGS_FAILED) {
  3565. //
  3566. // Scan the catalog nodes until we find the first one that failed
  3567. // verification, and return that failure code.
  3568. //
  3569. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3570. if(CatalogNode->VerificationFailureError != NO_ERROR) {
  3571. return CatalogNode->VerificationFailureError;
  3572. }
  3573. }
  3574. //
  3575. // We didn't find a failed catalog node in our catalog list--something's
  3576. // seriously wrong!
  3577. //
  3578. MYASSERT(0);
  3579. return ERROR_INVALID_DATA;
  3580. }
  3581. if(Queue->Flags & FQF_DID_CATALOGS_PROMPT_FOR_TRUST) {
  3582. //
  3583. // We've previously validated these catalogs, but we came across one
  3584. // Authenticode-signed catalog that we needed to prompt the user for in
  3585. // order to establish trust of the publisher. Unfortunately, we were
  3586. // invoked in "silent mode" (i.e., VERCAT_NO_PROMPT_ON_ERROR), so we
  3587. // simply flagged the queue as having an outstanding issue to resolve
  3588. // this.
  3589. //
  3590. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3591. if(CatalogNode->Flags & CATINFO_FLAG_PROMPT_FOR_TRUST) {
  3592. //
  3593. // Count how many of these we find (there'd better be exactly
  3594. // one).
  3595. //
  3596. AuthSigPromptCount++;
  3597. MYASSERT(CatalogNode->VerificationFailureError == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED);
  3598. //
  3599. // ...and we'd better have some WinVerifyTrust state data!
  3600. //
  3601. MYASSERT(CatalogNode->hWVTStateData);
  3602. if(Flags & VERCAT_NO_PROMPT_ON_ERROR) {
  3603. //
  3604. // We _still_ can't make any progress here. :-(
  3605. //
  3606. return CatalogNode->VerificationFailureError;
  3607. } else {
  3608. //
  3609. // OK, now we can finally ask the user if they trust this
  3610. // catalog's publisher!
  3611. //
  3612. MYASSERT(!(Queue->Flags & FQF_DIGSIG_ERRORS_NOUI));
  3613. if(_HandleFailedVerification(
  3614. Owner,
  3615. SetupapiVerifyCatalogProblem,
  3616. CatalogNode->CatalogFilenameOnSystem,
  3617. ((Queue->DeviceDescStringId == -1)
  3618. ? NULL
  3619. : pStringTableStringFromId(Queue->StringTable, Queue->DeviceDescStringId)),
  3620. Queue->DriverSigningPolicy,
  3621. FALSE,
  3622. CatalogNode->VerificationFailureError,
  3623. Queue->LogContext,
  3624. NULL,
  3625. NULL,
  3626. CatalogNode->hWVTStateData)) {
  3627. //
  3628. // The user said they trust the publisher--this catalog
  3629. // node can now be marked as successfully validated.
  3630. //
  3631. CatalogNode->Flags &= ~CATINFO_FLAG_PROMPT_FOR_TRUST;
  3632. CatalogNode->Flags |= CATINFO_FLAG_AUTHENTICODE_SIGNED;
  3633. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  3634. //
  3635. // Unless policy is "Ignore", we want to update the
  3636. // error value to indicate the user confirmed their
  3637. // trust of this Authenticode publisher.
  3638. //
  3639. MYASSERT(Queue->DriverSigningPolicy & DRIVERSIGN_ALLOW_AUTHENTICODE);
  3640. MYASSERT((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  3641. != DRIVERSIGN_BLOCKING);
  3642. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  3643. != DRIVERSIGN_NONE) {
  3644. CatalogNode->VerificationFailureError = ERROR_AUTHENTICODE_TRUSTED_PUBLISHER;
  3645. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  3646. }
  3647. //
  3648. // We can free the WinVerifyTrust state data now that
  3649. // the user has indicated they trust the publisher.
  3650. //
  3651. pSetupCloseWVTStateData(CatalogNode->hWVTStateData);
  3652. CatalogNode->hWVTStateData = NULL;
  3653. } else {
  3654. //
  3655. // The user doesn't trust the publisher--clear the
  3656. // string buffer containing the Authenticode catalog's
  3657. // filename.
  3658. //
  3659. CatalogNode->CatalogFilenameOnSystem[0] = TEXT('\0');
  3660. //
  3661. // Also, clear the "prompt for trust" flag on this
  3662. // catalog node, since we've already done this.
  3663. //
  3664. CatalogNode->Flags &= ~CATINFO_FLAG_PROMPT_FOR_TRUST;
  3665. //
  3666. // Likewise, we can clear the "prompt for trust" flag
  3667. // for the queue, and in its place set the "catalog
  3668. // verification failed" flag.
  3669. //
  3670. Queue->Flags &= ~FQF_DID_CATALOGS_PROMPT_FOR_TRUST;
  3671. Queue->Flags |= FQF_DID_CATALOGS_FAILED;
  3672. //
  3673. // Go ahead and free the WinVerifyTrust state data...
  3674. //
  3675. pSetupCloseWVTStateData(CatalogNode->hWVTStateData);
  3676. CatalogNode->hWVTStateData = NULL;
  3677. //
  3678. // Change our error to now indicate that the user
  3679. // explicitly indicated they didn't want to trust the
  3680. // publisher (unless policy was block, in which case
  3681. // they didn't have a choice).
  3682. //
  3683. CatalogNode->VerificationFailureError =
  3684. ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED;
  3685. return CatalogNode->VerificationFailureError;
  3686. }
  3687. }
  3688. } else {
  3689. //
  3690. // We'd better have a successful validation reported for this
  3691. // node!
  3692. //
  3693. MYASSERT((CatalogNode->VerificationFailureError == NO_ERROR) ||
  3694. (CatalogNode->VerificationFailureError == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER));
  3695. //
  3696. // ...and we'd better not have any WinVerifyTrust state data!
  3697. //
  3698. MYASSERT(!(CatalogNode->hWVTStateData));
  3699. }
  3700. }
  3701. MYASSERT(AuthSigPromptCount == 1);
  3702. //
  3703. // OK, we've gotten confirmation from the user that they trust the
  3704. // Authenticode publisher (thus, the validation of the catalogs in this
  3705. // queue can be considered successful).
  3706. //
  3707. Queue->Flags &= ~FQF_DID_CATALOGS_PROMPT_FOR_TRUST;
  3708. Queue->Flags |= FQF_DID_CATALOGS_OK;
  3709. //
  3710. // If the caller wants information about the primary device INF, then
  3711. // find the applicable catalog node.
  3712. //
  3713. if(DeviceInfFinalName) {
  3714. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3715. if(CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF) {
  3716. MYASSERT(CatalogNode->InfFinalPath != -1);
  3717. InfFullPath = pSetupStringTableStringFromId(Queue->StringTable, CatalogNode->InfFinalPath);
  3718. lstrcpy(DeviceInfFinalName, InfFullPath);
  3719. if(DeviceInfNewlyCopied) {
  3720. *DeviceInfNewlyCopied = (CatalogNode->Flags & CATINFO_FLAG_NEWLY_COPIED);
  3721. }
  3722. }
  3723. }
  3724. }
  3725. return NO_ERROR;
  3726. }
  3727. //
  3728. // If the queue has an alternate default catalog file associated with it,
  3729. // then retrieve that catalog's name for use later.
  3730. //
  3731. AltCatalogFile = (Queue->AltCatalogFile != -1)
  3732. ? pSetupStringTableStringFromId(Queue->StringTable, Queue->AltCatalogFile)
  3733. : NULL;
  3734. Queue->hWndDriverSigningUi = Owner;
  3735. ReturnStatus = NO_ERROR;
  3736. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3737. //
  3738. // Assume success for verification of this catalog node.
  3739. //
  3740. CatalogNodeStatus = NO_ERROR;
  3741. MYASSERT(CatalogNode->InfFullPath != -1);
  3742. InfFullPath = pStringTableStringFromId(Queue->StringTable, CatalogNode->InfFullPath);
  3743. if(Queue->Flags & FQF_USE_ALT_PLATFORM) {
  3744. //
  3745. // We have an alternate platform override, so use the alternate
  3746. // platform's CatalogFile= entry.
  3747. //
  3748. CatStringId = CatalogNode->AltCatalogFileFromInf;
  3749. } else {
  3750. //
  3751. // We're running native--use the native CatalogFile= entry.
  3752. //
  3753. CatStringId = CatalogNode->CatalogFileFromInf;
  3754. }
  3755. CatName = (CatStringId != -1)
  3756. ? pStringTableStringFromId(Queue->StringTable, CatStringId)
  3757. : NULL;
  3758. InfVerifyType = pSetupInfIsFromOemLocation(InfFullPath, TRUE)
  3759. ? VERIFY_INF_AS_OEM
  3760. : VERIFY_INF_AS_SYSTEM;
  3761. if(InfVerifyType == VERIFY_INF_AS_OEM) {
  3762. //
  3763. // If the caller wants us to, we'll now install the catalog. In
  3764. // addition, if it's a (native platform) device installation, we'll
  3765. // install the INF as well.
  3766. //
  3767. // (Note: we specify the 'no overwrite' switch so that we won't
  3768. // blow away any existing PNF source path information for this INF.
  3769. // We'll only consider an OEM INF to match up with an existing
  3770. // %windir%\Inf\Oem*.INF entry if the catalogs also match up, so
  3771. // we're not going to get into any trouble doing this.
  3772. //
  3773. if(Flags & VERCAT_INSTALL_INF_AND_CAT) {
  3774. //
  3775. // Check to see whether the INF is a device INF. The queue may
  3776. // not be marked as a device install queue, even though we have
  3777. // a device INF. This could happen if a device INF is being
  3778. // used for some purpose other than a device install. It could
  3779. // also happen if we're explicitly forcing non-driver signing
  3780. // policy (i.e., the INF's class isn't listed in certclas.inf).
  3781. //
  3782. OemInfIsDeviceInf = TRUE; // assume INF is a device INF.
  3783. if(!(Queue->Flags & FQF_DEVICE_INSTALL)) {
  3784. HINF hInf;
  3785. //
  3786. // The queue isn't marked as a device install queue, but we
  3787. // still may be dealing with a device INF. Check to be
  3788. // sure...
  3789. //
  3790. hInf = SetupOpenInfFile(InfFullPath,
  3791. NULL,
  3792. INF_STYLE_WIN4,
  3793. NULL
  3794. );
  3795. if(hInf != INVALID_HANDLE_VALUE) {
  3796. try {
  3797. //
  3798. // We don't need to lock the INF because it'll
  3799. // never be accessible outside of this routine.
  3800. //
  3801. if(!IsInfForDeviceInstall(Queue->LogContext,
  3802. NULL,
  3803. (PLOADED_INF)hInf,
  3804. NULL,
  3805. NULL,
  3806. NULL,
  3807. NULL,
  3808. FALSE)) {
  3809. //
  3810. // The INF really isn't a device INF.
  3811. //
  3812. OemInfIsDeviceInf = FALSE;
  3813. }
  3814. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3815. pSetupExceptionHandler(GetExceptionCode(),
  3816. ERROR_INVALID_PARAMETER,
  3817. NULL
  3818. );
  3819. }
  3820. SetupCloseInfFile(hInf);
  3821. } else {
  3822. //
  3823. // This shouldn't happen. For now, just assume the INF
  3824. // isn't a device INF. We're probably going to fail
  3825. // down below when we actually try to copy the INF.
  3826. //
  3827. OemInfIsDeviceInf = FALSE;
  3828. }
  3829. }
  3830. CopyStyleFlags = SP_COPY_NOOVERWRITE;
  3831. if(OemInfIsDeviceInf) {
  3832. SCOIFlags = 0;
  3833. //
  3834. // If we're doing a non-native install, then we only want
  3835. // to install the INF's associated catalog (if any).
  3836. //
  3837. if(Queue->Flags & FQF_USE_ALT_PLATFORM) {
  3838. CopyStyleFlags |= SP_COPY_OEMINF_CATALOG_ONLY;
  3839. }
  3840. } else {
  3841. //
  3842. // Since we're not working with a device INF, we want to
  3843. // suppress popups and error log entries if the INF doesn't
  3844. // reference a catalog. This is because we want to allow
  3845. // such INFs to be validated globally, unless they
  3846. // subsequently try to copy files.
  3847. //
  3848. SCOIFlags = SCOI_NO_ERRLOG_ON_MISSING_CATALOG;
  3849. //
  3850. // We always want to do catalog-only installs for
  3851. // non-device INFs.
  3852. //
  3853. CopyStyleFlags |= SP_COPY_OEMINF_CATALOG_ONLY;
  3854. }
  3855. //
  3856. // If we're not supposed to generate popups/log entries at all
  3857. // for signature verification failures (e.g., because we've
  3858. // already done so previously), then set that flag as well.
  3859. //
  3860. if(Queue->Flags & FQF_DIGSIG_ERRORS_NOUI) {
  3861. SCOIFlags |= SCOI_NO_UI_ON_SIGFAIL;
  3862. }
  3863. if(Queue->Flags & FQF_KEEP_INF_AND_CAT_ORIGINAL_NAMES) {
  3864. SCOIFlags |= SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES;
  3865. //
  3866. // This is an exception package, so we'd better not even
  3867. // think about allowing Authenticode signed files!
  3868. //
  3869. MYASSERT(!(Queue->DriverSigningPolicy & DRIVERSIGN_ALLOW_AUTHENTICODE));
  3870. }
  3871. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  3872. SCOIFlags |= SCOI_ABORT_IF_UNSIGNED;
  3873. }
  3874. CatalogNodeStatus =
  3875. GLE_FN_CALL(FALSE,
  3876. _SetupCopyOEMInf(
  3877. InfFullPath,
  3878. NULL, // default source location to where INF presently is
  3879. ((Flags & VERCAT_PRIMARY_DEVICE_INF_FROM_INET)
  3880. ? SPOST_URL
  3881. : SPOST_PATH),
  3882. CopyStyleFlags,
  3883. PathBuffer,
  3884. SIZECHARS(PathBuffer),
  3885. NULL,
  3886. &p,
  3887. ((CatalogNode->InfOriginalName != -1)
  3888. ? pStringTableStringFromId(Queue->StringTable,
  3889. CatalogNode->InfOriginalName)
  3890. : pSetupGetFileTitle(InfFullPath)),
  3891. CatName,
  3892. Owner,
  3893. ((Queue->DeviceDescStringId == -1)
  3894. ? NULL
  3895. : pStringTableStringFromId(Queue->StringTable,
  3896. Queue->DeviceDescStringId)),
  3897. Queue->DriverSigningPolicy,
  3898. SCOIFlags,
  3899. AltCatalogFile,
  3900. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  3901. ? &(Queue->AltPlatformInfo)
  3902. : Queue->ValidationPlatform),
  3903. &Err,
  3904. CatalogNode->CatalogFilenameOnSystem,
  3905. Queue->LogContext,
  3906. &(Queue->VerifyContext),
  3907. &hWVTStateData)
  3908. );
  3909. if(CatalogNodeStatus == NO_ERROR) {
  3910. //
  3911. // If we got back a WinVerifyTrust state data handle, we'd
  3912. // better have gotten one of our two Authenticode status
  3913. // codes back...
  3914. //
  3915. MYASSERT(!hWVTStateData ||
  3916. ((Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) || (Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)));
  3917. //
  3918. // If Err indicates that there was a digital signature
  3919. // problem that the user chose to ignore (or was silently
  3920. // ignored), then set a flag in the queue indicating the
  3921. // user should not be warned about subsequent failures.
  3922. // Don't set this flag if the queue's policy is "Ignore",
  3923. // however, on the chance that the policy might be altered
  3924. // later, and we'd want the user to get informed on any
  3925. // subsequent errors.
  3926. //
  3927. // (Note: if the error was due to the INF not having a
  3928. // CatalogFile= entry, and if we're supposed to ignore such
  3929. // problems, then just set the flag to do global validation
  3930. // later.)
  3931. //
  3932. if((Err == ERROR_NO_CATALOG_FOR_OEM_INF) &&
  3933. (SCOIFlags & SCOI_NO_ERRLOG_ON_MISSING_CATALOG)) {
  3934. MYASSERT(!hWVTStateData);
  3935. InfVerifyType = VERIFY_OEM_INF_GLOBALLY;
  3936. } else if(Err != NO_ERROR) {
  3937. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  3938. != DRIVERSIGN_NONE) {
  3939. MYASSERT(Err != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED);
  3940. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  3941. }
  3942. }
  3943. if(*PathBuffer) {
  3944. //
  3945. // Store the INF's final path into our catalog node.
  3946. // This will be under %windir%\Inf unless the INF didn't
  3947. // specify a CatalogFile= entry and we did an alternate
  3948. // catalog installation (i.e., because the file queue had
  3949. // an associated alternate catalog).
  3950. //
  3951. CatalogNode->InfFinalPath = pSetupStringTableAddString(
  3952. Queue->StringTable,
  3953. PathBuffer,
  3954. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  3955. );
  3956. } else {
  3957. //
  3958. // _SetupCopyOEMInf returned an empty string for the
  3959. // destination INF name, which means that we were doing
  3960. // a catalog-only install, and it didn't find the INF
  3961. // already existing in %windir%\Inf. In this case, just
  3962. // use the INF's original pathname as its final pathname.
  3963. //
  3964. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  3965. }
  3966. if(CatalogNode->InfFinalPath == -1) {
  3967. CatalogNodeStatus = ERROR_NOT_ENOUGH_MEMORY;
  3968. if(Err == NO_ERROR) {
  3969. Err = CatalogNodeStatus;
  3970. }
  3971. //
  3972. // Since we couldn't add this filename to the string
  3973. // table, we won't be able to undo this copy later--it
  3974. // must be done here. Delete the INF, PNF, and CAT.
  3975. //
  3976. // NOTE: we should never get here if we did an alternate
  3977. // catalog file-only install, because in that case our
  3978. // new INF name is the same as the INF's original name,
  3979. // thus the string is already in the buffer and there's
  3980. // no way we could run out of memory.
  3981. //
  3982. MYASSERT(lstrcmpi(PathBuffer, InfFullPath));
  3983. pSetupUninstallOEMInf(PathBuffer,
  3984. Queue->LogContext,
  3985. SUOI_FORCEDELETE,
  3986. NULL
  3987. );
  3988. } else {
  3989. //
  3990. // Set a flag in the catalog node indicating that this
  3991. // INF was newly-copied into %windir%\Inf. If the
  3992. // string ID for our INF's original name and that of its
  3993. // new name are equal, then we know we did an alternate
  3994. // catalog installation only, and we don't want to set
  3995. // this flag.
  3996. //
  3997. if(CatalogNode->InfFinalPath != CatalogNode->InfFullPath) {
  3998. CatalogNode->Flags |= CATINFO_FLAG_NEWLY_COPIED;
  3999. }
  4000. //
  4001. // If this is the primary device INF, and the caller
  4002. // requested information about that INF's final
  4003. // pathname, then store that information in the caller-
  4004. // supplied buffer(s) now.
  4005. //
  4006. if(DeviceInfFinalName &&
  4007. (CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF)) {
  4008. //
  4009. // We'd better not just've done an alternate catalog
  4010. // installation.
  4011. //
  4012. MYASSERT(CatalogNode->InfFinalPath != CatalogNode->InfFullPath);
  4013. lstrcpy(DeviceInfFinalName, PathBuffer);
  4014. if(DeviceInfNewlyCopied) {
  4015. *DeviceInfNewlyCopied = TRUE;
  4016. }
  4017. }
  4018. //
  4019. // If this INF was signed by an Authenticode catalog,
  4020. // then set a flag indicating that.
  4021. //
  4022. if((Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  4023. (Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  4024. //
  4025. // In either case, we should trust the catalog's
  4026. // publisher, because either the cert was in the
  4027. // TrustedPublisher store, or the user agreed to
  4028. // trust the publisher.
  4029. //
  4030. CatalogNode->Flags |= CATINFO_FLAG_AUTHENTICODE_SIGNED;
  4031. MYASSERT(hWVTStateData);
  4032. pSetupCloseWVTStateData(hWVTStateData);
  4033. hWVTStateData = NULL;
  4034. }
  4035. }
  4036. } else {
  4037. if(CatalogNodeStatus == ERROR_FILE_EXISTS) {
  4038. //
  4039. // INF and CAT already there--this isn't a failure.
  4040. //
  4041. // Store the name under which we found this OEM INF
  4042. // into the catalog node's InfFinalPath field.
  4043. //
  4044. CatalogNode->InfFinalPath = pSetupStringTableAddString(
  4045. Queue->StringTable,
  4046. PathBuffer,
  4047. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  4048. );
  4049. if(CatalogNode->InfFinalPath == -1) {
  4050. CatalogNodeStatus = ERROR_NOT_ENOUGH_MEMORY;
  4051. } else {
  4052. CatalogNodeStatus = NO_ERROR;
  4053. //
  4054. // If Err indicates that there was a digital
  4055. // signature problem that the user chose to ignore
  4056. // (or was silently ignored), then set a flag in
  4057. // the queue indicating the user should not be
  4058. // warned about subsequent failures. Don't set
  4059. // this flag if the queue's policy is "Ignore",
  4060. // however, on the chance that the policy might be
  4061. // altered later, and we'd want the user to get
  4062. // informed on any subsequent errors.
  4063. //
  4064. if(Err != NO_ERROR) {
  4065. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  4066. != DRIVERSIGN_NONE) {
  4067. MYASSERT(Err != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED);
  4068. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  4069. }
  4070. }
  4071. //
  4072. // If this is the primary device INF, and the
  4073. // caller requested information about that INF's
  4074. // final pathname, then store that information in
  4075. // the caller-supplied buffer(s) now.
  4076. //
  4077. if(DeviceInfFinalName &&
  4078. (CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF)) {
  4079. lstrcpy(DeviceInfFinalName, PathBuffer);
  4080. if(DeviceInfNewlyCopied) {
  4081. *DeviceInfNewlyCopied = FALSE;
  4082. }
  4083. }
  4084. //
  4085. // If this INF was signed by an Authenticode
  4086. // catalog, then set a flag indicating that.
  4087. //
  4088. if((Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  4089. (Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  4090. //
  4091. // In either case, we should trust the
  4092. // catalog's publisher, because either the cert
  4093. // was in the TrustedPublisher store, or the
  4094. // user agreed to trust the publisher.
  4095. //
  4096. CatalogNode->Flags |= CATINFO_FLAG_AUTHENTICODE_SIGNED;
  4097. pSetupCloseWVTStateData(hWVTStateData);
  4098. hWVTStateData = NULL;
  4099. }
  4100. }
  4101. } else {
  4102. //
  4103. // For any error other than ERROR_FILE_EXISTS, we
  4104. // shouldn't be getting any WinVerifyTrust state data.
  4105. //
  4106. MYASSERT(!hWVTStateData);
  4107. if(CatalogNodeStatus == ERROR_SET_SYSTEM_RESTORE_POINT) {
  4108. //
  4109. // We should only get this error if the queue flag is
  4110. // set that causes us to abort unsigned installations.
  4111. //
  4112. MYASSERT(Queue->Flags & FQF_ABORT_IF_UNSIGNED);
  4113. //
  4114. // We don't want the user to see the driver signing
  4115. // UI again when the queue is re-committed...
  4116. //
  4117. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  4118. != DRIVERSIGN_NONE) {
  4119. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  4120. }
  4121. //
  4122. // Make sure that Err is also set to this same
  4123. // "special" error code...
  4124. //
  4125. Err = CatalogNodeStatus;
  4126. }
  4127. }
  4128. //
  4129. // If we had a real failure from _SetupCopyOEMInf (or we're
  4130. // out of memory and couldn't add a string to the string
  4131. // table above), then we need to propagate the value of
  4132. // CatalogNodeStatus to Err, if Err doesn't already have a
  4133. // failure code.
  4134. //
  4135. if((CatalogNodeStatus != NO_ERROR) && (Err == NO_ERROR)) {
  4136. Err = CatalogNodeStatus;
  4137. }
  4138. }
  4139. } else {
  4140. //
  4141. // We were told not to copy any files, but we've encountered an
  4142. // OEM INF that needs to be installed. Hence, we have a failure.
  4143. // Note that we _don't_ look to see if this OEM INF (and its
  4144. // corresponding catalog) might happen to already be properly
  4145. // installed. That isn't necessary, because
  4146. // _SetupDiInstallDevice calls _SetupVerifyQueuedCatalogs with
  4147. // the VERCAT_INSTALL_INF_AND_CAT flag _before_ calling
  4148. // SetupScanFileQueue, thus all INFs/CATs should be present when
  4149. // we're called to do simple verification of the catalog nodes.
  4150. //
  4151. Err = CatalogNodeStatus = ERROR_CANNOT_COPY;
  4152. }
  4153. }
  4154. if(InfVerifyType != VERIFY_INF_AS_OEM) {
  4155. //
  4156. // Inf is in system location (%windir%\Inf), or we're going to try
  4157. // validating an "OEM" INF globally. Figure out the expected name
  4158. // of the catalog file. If the file was originally copied in by the
  4159. // Di stuff, then we need to use a name based on the name Di gave
  4160. // the inf. Otherwise we use the name from the inf's CatalogFile=
  4161. // entry, if present. Finally, if the INF doesn't specify a
  4162. // CatalogFile= entry, we assume it's a system component and
  4163. // attempt to validate against any catalog that we find a hash
  4164. // match in.
  4165. //
  4166. Err = NO_ERROR; // assume success
  4167. ProblemFile = PathBuffer; // default buffer to store problem file
  4168. if(CatalogNode->InfOriginalName != -1) {
  4169. RequiredSize = SIZECHARS(InfNameBuffer);
  4170. if(pSetupStringTableStringFromIdEx(Queue->StringTable,
  4171. CatalogNode->InfOriginalName,
  4172. InfNameBuffer,
  4173. &RequiredSize)) {
  4174. OriginalNameDifferent = TRUE;
  4175. } else {
  4176. //
  4177. // This should never fail!
  4178. //
  4179. MYASSERT(0);
  4180. Err = ERROR_INVALID_DATA;
  4181. //
  4182. // Blame the INF!
  4183. //
  4184. Problem = SetupapiVerifyInfProblem;
  4185. MYVERIFY(SUCCEEDED(StringCchCopy(PathBuffer,
  4186. SIZECHARS(PathBuffer),
  4187. InfFullPath)));
  4188. }
  4189. } else {
  4190. OriginalNameDifferent = FALSE;
  4191. }
  4192. if(Err == NO_ERROR) {
  4193. if(CatName) {
  4194. //
  4195. // If there is a catalog name, then we'd better not be
  4196. // doing our "verify OEM INF globally" trick!
  4197. //
  4198. MYASSERT(InfVerifyType == VERIFY_INF_AS_SYSTEM);
  4199. if(OriginalNameDifferent) {
  4200. //
  4201. // If the INF specified a catalog file, then we know we
  4202. // would've installed that catalog file using a name
  4203. // based on the unique name we assigned the INF when
  4204. // copying it into the INF directory.
  4205. //
  4206. lstrcpy(CatalogName, pSetupGetFileTitle(InfFullPath));
  4207. p = _tcsrchr(CatalogName, TEXT('.'));
  4208. if(!p) {
  4209. p = CatalogName + lstrlen(CatalogName);
  4210. }
  4211. lstrcpy(p, pszCatSuffix);
  4212. } else {
  4213. lstrcpy(CatalogName, CatName);
  4214. }
  4215. } else {
  4216. //
  4217. // This system INF didn't specify a CatalogFile= entry. If
  4218. // an alternate catalog is associated with this file queue,
  4219. // then use that catalog for verification.
  4220. //
  4221. if(AltCatalogFile) {
  4222. lstrcpy(CatalogName, AltCatalogFile);
  4223. CatName = pSetupGetFileTitle(CatalogName);
  4224. }
  4225. }
  4226. //
  4227. // (Note: in the call below, we don't want to store the
  4228. // validating catalog filename in our CatalogFilenameOnSystem
  4229. // field if the INF didn't specify a CatalogFile= entry (and
  4230. // there was no alternate catalog specified), because we want
  4231. // any queue nodes that reference this catalog entry to use
  4232. // global validation as well.)
  4233. //
  4234. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  4235. //
  4236. // Don't attempt to call _VerifyFile, because we're
  4237. // asking for the validating catalog's name, and that makes
  4238. // no sense in the "minimal embedded" case.
  4239. //
  4240. *(CatalogNode->CatalogFilenameOnSystem) = TEXT('\0');
  4241. //
  4242. // (Err is already set to NO_ERROR.)
  4243. //
  4244. } else {
  4245. if(!CatName) {
  4246. *(CatalogNode->CatalogFilenameOnSystem) = TEXT('\0');
  4247. }
  4248. Err = _VerifyFile(
  4249. Queue->LogContext,
  4250. &(Queue->VerifyContext),
  4251. (CatName ? CatalogName : NULL),
  4252. NULL,
  4253. 0,
  4254. (OriginalNameDifferent ? InfNameBuffer : pSetupGetFileTitle(InfFullPath)),
  4255. InfFullPath,
  4256. &Problem,
  4257. PathBuffer,
  4258. FALSE,
  4259. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  4260. ? &(Queue->AltPlatformInfo)
  4261. : Queue->ValidationPlatform),
  4262. (VERIFY_FILE_IGNORE_SELFSIGNED
  4263. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4264. (CatName ? CatalogNode->CatalogFilenameOnSystem : NULL),
  4265. NULL,
  4266. NULL,
  4267. NULL,
  4268. NULL
  4269. );
  4270. if((Err != NO_ERROR) && (Err != ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH) &&
  4271. CatName &&
  4272. !(Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) &&
  4273. (Queue->DriverSigningPolicy & DRIVERSIGN_ALLOW_AUTHENTICODE)) {
  4274. //
  4275. // We failed to validate via OS codesigning policy--now
  4276. // we should see if the INF validates using
  4277. // Authenticode policy.
  4278. //
  4279. Err = _VerifyFile(Queue->LogContext,
  4280. &(Queue->VerifyContext),
  4281. CatalogName,
  4282. NULL,
  4283. 0,
  4284. (OriginalNameDifferent
  4285. ? InfNameBuffer
  4286. : pSetupGetFileTitle(InfFullPath)),
  4287. InfFullPath,
  4288. &Problem,
  4289. PathBuffer,
  4290. FALSE,
  4291. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  4292. ? &(Queue->AltPlatformInfo)
  4293. : Queue->ValidationPlatform),
  4294. (VERIFY_FILE_IGNORE_SELFSIGNED
  4295. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK
  4296. | VERIFY_FILE_USE_AUTHENTICODE_CATALOG),
  4297. CatalogNode->CatalogFilenameOnSystem,
  4298. NULL,
  4299. NULL,
  4300. NULL,
  4301. &hWVTStateData
  4302. );
  4303. if(Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) {
  4304. CatalogNode->VerificationFailureError = Err;
  4305. //
  4306. // Treat this as success...
  4307. //
  4308. Err = NO_ERROR;
  4309. Problem = SetupapiVerifyNoProblem;
  4310. CatalogNode->Flags |= CATINFO_FLAG_AUTHENTICODE_SIGNED;
  4311. pSetupCloseWVTStateData(hWVTStateData);
  4312. hWVTStateData = NULL;
  4313. } else if(Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED) {
  4314. //
  4315. // This isn't really a verification error, but
  4316. // since we're going to have to prompt the user
  4317. // to establish trust of this publisher, we
  4318. // need to have a problem and problem file
  4319. // identified. We'll blame the catalog...
  4320. //
  4321. Problem = SetupapiVerifyCatalogProblem;
  4322. ProblemFile = CatalogNode->CatalogFilenameOnSystem;
  4323. //
  4324. // We only support one Authenticode-signed
  4325. // catalog (that isn't pre-trusted) per file
  4326. // queue, so we keep a count to make sure we
  4327. // don't find more than one.
  4328. //
  4329. AuthSigPromptCount++;
  4330. }
  4331. }
  4332. }
  4333. }
  4334. if(Err == NO_ERROR) {
  4335. //
  4336. // INF/CAT was successfully verified--store the INF's final
  4337. // path (which is the same as its current path) into the
  4338. // catalog node.
  4339. //
  4340. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  4341. } else {
  4342. MYASSERT(Problem != SetupapiVerifyNoProblem);
  4343. if(Problem != SetupapiVerifyCatalogProblem) {
  4344. //
  4345. // If the problem was not a catalog problem, then it's an
  4346. // INF problem (the _VerifyFile routine doesn't know the
  4347. // file we passed it is an INF).
  4348. //
  4349. Problem = SetupapiVerifyInfProblem;
  4350. }
  4351. if(AuthSigPromptCount > 1) {
  4352. //
  4353. // We don't want to popup more than one Authenticode trust
  4354. // dialog!
  4355. //
  4356. CatalogNodeStatus = Err = ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED;
  4357. MYASSERT(hWVTStateData);
  4358. pSetupCloseWVTStateData(hWVTStateData);
  4359. hWVTStateData = NULL;
  4360. } else if(Flags & VERCAT_NO_PROMPT_ON_ERROR) {
  4361. if(hWVTStateData) {
  4362. //
  4363. // The INF is signed via an Authenticode catalog, but
  4364. // the signing certificate isn't in the trusted
  4365. // publisher store. Since we're prevented from asking
  4366. // the user whether they trust the publisher, we'll
  4367. // simply set a flag on this catalog node for the time
  4368. // being indicating that the user needs to be so
  4369. // prompted. We'll also store the WinVerifyTrust data
  4370. // in the catalog node so that when we do get around to
  4371. // prompting the user, we'll be able to give them info
  4372. // on who the publisher was, when the catalog was
  4373. // signed, etc.
  4374. //
  4375. MYASSERT(AuthSigPromptCount == 1);
  4376. MYASSERT(Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED);
  4377. CatalogNode->Flags |= CATINFO_FLAG_PROMPT_FOR_TRUST;
  4378. CatalogNode->hWVTStateData = hWVTStateData;
  4379. hWVTStateData = NULL; // successfully transferred to catalog node
  4380. }
  4381. CatalogNodeStatus = Err;
  4382. } else if(Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) {
  4383. //
  4384. // Don't notify the caller or log anything--just remember
  4385. // the error. (Note: we never want to consider
  4386. // Authenticode signatures in this case.
  4387. //
  4388. CatalogNodeStatus = Err;
  4389. MYASSERT(!hWVTStateData);
  4390. } else {
  4391. //
  4392. // Notify the caller of the failure (based on policy).
  4393. //
  4394. if(_HandleFailedVerification(
  4395. Owner,
  4396. Problem,
  4397. ProblemFile,
  4398. ((Queue->DeviceDescStringId == -1)
  4399. ? NULL
  4400. : pStringTableStringFromId(Queue->StringTable, Queue->DeviceDescStringId)),
  4401. Queue->DriverSigningPolicy,
  4402. Queue->Flags & FQF_DIGSIG_ERRORS_NOUI,
  4403. Err,
  4404. Queue->LogContext,
  4405. NULL,
  4406. NULL,
  4407. hWVTStateData))
  4408. {
  4409. if(hWVTStateData) {
  4410. //
  4411. // The user agreed that they trust the publisher of
  4412. // this Authenticode catalog (or, trust was
  4413. // implicitly granted because policy was Ignore).
  4414. //
  4415. CatalogNode->Flags |= CATINFO_FLAG_AUTHENTICODE_SIGNED;
  4416. //
  4417. // Unless policy is "Ignore", we want to update the
  4418. // error value to indicate the user confirmed their
  4419. // trust of this Authenticode publisher.
  4420. //
  4421. MYASSERT((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  4422. != DRIVERSIGN_BLOCKING);
  4423. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  4424. != DRIVERSIGN_NONE) {
  4425. Err = ERROR_AUTHENTICODE_TRUSTED_PUBLISHER;
  4426. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  4427. }
  4428. //
  4429. // INF/CAT was successfully verified--store the
  4430. // INF's final path (which is the same as its
  4431. // current path) into the catalog node.
  4432. //
  4433. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  4434. } else {
  4435. //
  4436. // If the user actally saw UI (i.e., policy isn't
  4437. // "Ignore", then set a flag so we don't popup any
  4438. // more digital signature verification UI...
  4439. //
  4440. if((Queue->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE)
  4441. != DRIVERSIGN_NONE) {
  4442. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  4443. }
  4444. //
  4445. // If the caller wants a chance to set a system
  4446. // restore point prior to doing any unsigned
  4447. // installations, then we abort now with a
  4448. // "special" error code that tells them what to
  4449. // do...
  4450. //
  4451. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  4452. CatalogNodeStatus = Err = ERROR_SET_SYSTEM_RESTORE_POINT;
  4453. } else {
  4454. //
  4455. // Since we're going to use the INF/CAT anyway,
  4456. // in spite of digital signature problems, then
  4457. // we need to set the INF's final path to be
  4458. // the same as its current path.
  4459. //
  4460. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  4461. }
  4462. }
  4463. } else {
  4464. //
  4465. // The caller doesn't want to proceed (or policy was
  4466. // block)
  4467. //
  4468. if(Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED) {
  4469. //
  4470. // Change error to indicate that we have a real
  4471. // failure (instead of a "wait and see" condition).
  4472. //
  4473. Err = ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED;
  4474. }
  4475. CatalogNodeStatus = Err;
  4476. }
  4477. if(hWVTStateData) {
  4478. //
  4479. // Don't need the WinVerifyTrust state data any
  4480. // longer...
  4481. //
  4482. pSetupCloseWVTStateData(hWVTStateData);
  4483. hWVTStateData = NULL;
  4484. }
  4485. }
  4486. }
  4487. if((CatalogNodeStatus == NO_ERROR) ||
  4488. (CatalogNodeStatus == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  4489. //
  4490. // If this is the primary device INF, and the caller requested
  4491. // information about that INF's final pathname, then store that
  4492. // information in the caller-supplied buffer(s) now.
  4493. //
  4494. if(DeviceInfFinalName &&
  4495. (CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF)) {
  4496. lstrcpy(DeviceInfFinalName, InfFullPath);
  4497. if(DeviceInfNewlyCopied) {
  4498. *DeviceInfNewlyCopied = FALSE;
  4499. }
  4500. }
  4501. }
  4502. }
  4503. //
  4504. // At this point, there are really 3 successful status codes we can
  4505. // have...
  4506. //
  4507. if((Err == NO_ERROR) ||
  4508. (Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED) ||
  4509. (Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER)) {
  4510. //
  4511. // If we successfully validated an "OEM" INF globally, then we want
  4512. // to remember this fact. This will allow us to generate a
  4513. // signature verification failure against any file copy nodes
  4514. // associated with this catalog node.
  4515. //
  4516. if(InfVerifyType == VERIFY_OEM_INF_GLOBALLY) {
  4517. MYASSERT(!(CatalogNode->Flags &
  4518. (CATINFO_FLAG_PROMPT_FOR_TRUST | CATINFO_FLAG_AUTHENTICODE_SIGNED)));
  4519. MYASSERT(Err == NO_ERROR);
  4520. CatalogNode->VerificationFailureError = ERROR_NO_CATALOG_FOR_OEM_INF;
  4521. } else {
  4522. CatalogNode->VerificationFailureError = Err;
  4523. }
  4524. } else {
  4525. //
  4526. // CatalogNodeStatus may or may not be NO_ERROR, since it's
  4527. // possible we encountered a digital signature verification failure
  4528. // for this catalog node, but the user elected to proceed anyway.
  4529. // Mark this node with the failure encountered...
  4530. //
  4531. CatalogNode->VerificationFailureError = Err;
  4532. CatalogNode->CatalogFilenameOnSystem[0] = TEXT('\0');
  4533. }
  4534. if((ReturnStatus == NO_ERROR) && (CatalogNodeStatus != NO_ERROR)) {
  4535. //
  4536. // First critical error we've encountered--propagate the failure
  4537. // for this catalog to our return status that will be returned to
  4538. // the caller once we've finished looking at all the catalogs.
  4539. //
  4540. ReturnStatus = CatalogNodeStatus;
  4541. //
  4542. // Unless the VERCAT_NO_PROMPT_ON_ERROR flag has been set, we
  4543. // should abort right now--there's no sense in going any further.
  4544. //
  4545. if(!(Flags & VERCAT_NO_PROMPT_ON_ERROR)) {
  4546. break;
  4547. }
  4548. //
  4549. // If we've found more than one untrusted publisher, we should also
  4550. // break.
  4551. //
  4552. if(AuthSigPromptCount > 1) {
  4553. MYASSERT(CatalogNodeStatus == ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED);
  4554. break;
  4555. }
  4556. }
  4557. }
  4558. //
  4559. // If the caller requested no prompting, then we don't want to mark this
  4560. // queue as 'failed', since the user never heard about it. However, if the
  4561. // verification succeeded, then we _do_ want to mark it as successful.
  4562. //
  4563. if(Flags & VERCAT_NO_PROMPT_ON_ERROR) {
  4564. if(ReturnStatus == NO_ERROR) {
  4565. Queue->Flags |= FQF_DID_CATALOGS_OK;
  4566. //
  4567. // We'd better not have any outstanding Authenticode trust issues.
  4568. //
  4569. MYASSERT(AuthSigPromptCount == 0);
  4570. } else {
  4571. //
  4572. // If we were still need to confirm with the user that they trust
  4573. // the publisher of an Authenticode-signed catalog, then set a flag
  4574. // so we can track that.
  4575. //
  4576. if((ReturnStatus == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED) &&
  4577. (AuthSigPromptCount == 1)) {
  4578. Queue->Flags |= FQF_DID_CATALOGS_PROMPT_FOR_TRUST;
  4579. }
  4580. }
  4581. } else {
  4582. Queue->Flags |= (ReturnStatus == NO_ERROR) ? FQF_DID_CATALOGS_OK
  4583. : FQF_DID_CATALOGS_FAILED;
  4584. //
  4585. // If we were successful, then we would've encountered at most 1
  4586. // Authenticode-signed catalog that required user-prompting to confirm
  4587. // trust of the publisher...
  4588. //
  4589. MYASSERT((ReturnStatus != NO_ERROR) || (AuthSigPromptCount < 2));
  4590. }
  4591. return ReturnStatus;
  4592. }
  4593. VOID
  4594. LogFailedVerification(
  4595. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  4596. IN DWORD MessageId,
  4597. IN DWORD Error,
  4598. IN LPCTSTR ProblemFile,
  4599. IN LPCTSTR DeviceDesc, OPTIONAL
  4600. IN DWORD LogLevel
  4601. )
  4602. /*++
  4603. Routine Description:
  4604. This routine logs when a verification failed but the file was installed
  4605. anyway.
  4606. Arguments:
  4607. LogContext - optionally supplies a pointer to the context for logging.
  4608. If this is not supplied, errors will be logged to the default context.
  4609. MessageId - Message to display
  4610. Error - supplies the code the the error that caused the failure.
  4611. ProblemFile - supplies the file path to the file associated with
  4612. the problem. In some cases this is a full path, in others it's just a
  4613. filename. The caller decides which makes sense in a particular
  4614. scenario. For example, a system catalog is in some funky directory
  4615. and there is no need to tell the user the full path. But in the case
  4616. where a catalog comes from an oem location, there might be some benefit
  4617. to telling the user the full path.
  4618. DeviceDesc - Optionally, supplies the device description to be used in the
  4619. digital signature verification error dialogs that may be popped up.
  4620. LogLevel - Either SETUP_LOG_ERROR, SETUP_LOG_WARNING, or SETUP_LOG_INFO.
  4621. Return Value:
  4622. NONE.
  4623. --*/
  4624. {
  4625. PSETUP_LOG_CONTEXT lc = NULL;
  4626. MYASSERT(Error != NO_ERROR);
  4627. MYASSERT(ProblemFile && *ProblemFile);
  4628. if (!LogContext) {
  4629. if (CreateLogContext(NULL, TRUE, &lc) == NO_ERROR) {
  4630. //
  4631. // success
  4632. //
  4633. LogContext = lc;
  4634. } else {
  4635. lc = NULL;
  4636. }
  4637. }
  4638. //
  4639. // a device install failed
  4640. //
  4641. WriteLogEntry(
  4642. LogContext,
  4643. LogLevel | SETUP_LOG_BUFFER,
  4644. MessageId,
  4645. NULL,
  4646. ProblemFile,
  4647. DeviceDesc);
  4648. WriteLogError(
  4649. LogContext,
  4650. LogLevel,
  4651. Error);
  4652. if (lc) {
  4653. DeleteLogContext(lc);
  4654. }
  4655. }
  4656. BOOL
  4657. pSetupHandleFailedVerification(
  4658. IN HWND Owner,
  4659. IN SetupapiVerifyProblem Problem,
  4660. IN LPCTSTR ProblemFile,
  4661. IN LPCTSTR DeviceDesc, OPTIONAL
  4662. IN DWORD DriverSigningPolicy,
  4663. IN BOOL NoUI,
  4664. IN DWORD Error,
  4665. IN PVOID LogContext, OPTIONAL
  4666. OUT PDWORD Flags, OPTIONAL
  4667. IN LPCTSTR TargetFile OPTIONAL
  4668. )
  4669. /*++
  4670. Routine Description:
  4671. This routine deals with a failed verification.
  4672. System policy is checked. If the policy is block, UI is displayed telling
  4673. the user that they're hosed. If the policy is ask-user, then ui is
  4674. displayed requesting the user's decision about whether to ignore the
  4675. verification failure and take the risk. If the policy is ignore, nothing
  4676. is done.
  4677. Arguments:
  4678. Owner - supplies window to own the dialog.
  4679. Problem - supplies a constant indicating what caused the failure. This
  4680. value indicates what type of file is specified in the ProblemFile
  4681. argument.
  4682. ProblemFile - supplies the file path to the file associated with
  4683. the problem. In some cases this is a full path, in others it's just a
  4684. filename. The caller decides which makes sense in a particular
  4685. scenario. For example, a system catalog is in some funky directory
  4686. and there is no need to tell the user the full path. But in the case
  4687. where a catalog comes from an oem location, there might be some benefit
  4688. to telling the user the full path.
  4689. NOTE: if this API is being called because of a blocked driver then a
  4690. full path should always be passed in.
  4691. DeviceDesc - Optionally, supplies the device description to be used in the
  4692. digital signature verification error dialogs that may be popped up.
  4693. DriverSigningPolicy - supplies the driver signing policy currently in
  4694. effect. May be one of the three following values:
  4695. DRIVERSIGN_NONE - silently succeed installation of unsigned/
  4696. incorrectly-signed files. A PSS log entry will
  4697. be generated, however.
  4698. DRIVERSIGN_WARNING - warn the user, but let them choose whether or not
  4699. they still want to install the problematic file.
  4700. If the user elects to proceed with the
  4701. installation, A PSS log entry will be generated
  4702. noting this fact.
  4703. DRIVERSIGN_BLOCKING - do not allow the file to be installed
  4704. The above values may be OR'ed with DRIVERSIGN_ALLOW_AUTHENTICODE. This
  4705. indicates that Authenticode-signed catalogs are permissable. The fact
  4706. that we were called with this bit set means that either:
  4707. (a) the catalog was Authenticode-signed, but the publisher's cert
  4708. wasn't contained in the TrustedPublisher cert store. Thus, the
  4709. user must be prompted in order to establish their trust of the
  4710. publisher. (This is only allowed for "Warn"--in the "Block"
  4711. case, the user doesn't get the chance to trust the publisher--
  4712. that requires that the publisher's cert is in the
  4713. TrustedPublisher store.)
  4714. (b) the file isn't signed at all. The fact that this bit is set
  4715. indicates that we should give the user that tells them that the
  4716. package could've been signed by Authenticode, but wasn't.
  4717. Without this bit, we want to give the standard driver signing
  4718. dialog that extolls the merits of WHQL.
  4719. NoUI - if TRUE, then a dialog box should not be displayed to the user, even
  4720. if policy is warn or block. This will typically be set to TRUE after
  4721. the user has previously been informed of a digital signature problem
  4722. with the package they're attempting to install, but have elected to
  4723. proceed with the installation anyway. The behavior of the "Yes" button,
  4724. then, is really a "yes to all".
  4725. Error - supplies the code of the error that caused the failure.
  4726. LogContext - optionally supplies a pointer to the context for logging.
  4727. If this is not supplied, errors will be logged to the default context.
  4728. This is declared as a PVOID so external functions don't need to know
  4729. what a SETUP_LOG_CONTEXT is.
  4730. Flags - optionally supplies a pointer to a DWORD that receives one or more
  4731. of the following file queue node flags indicating that we made an
  4732. exemption for installing a protected system file:
  4733. IQF_TARGET_PROTECTED - TargetFile (see below) is a protected system
  4734. file.
  4735. IQF_ALLOW_UNSIGNED - An exception has been granted so that TargetFile
  4736. (see below) may be replaced by an unsigned file.
  4737. TargetFile - optionally supplies a pointer to a string that specifies a
  4738. destination file if one exists. This is only used if we want to exempt
  4739. a file operation on this file. If this parameter is not specified, then
  4740. it is assumed the file will _not_ be replaced (i.e., it may already be
  4741. on the system in its unsigned state), and no SFP exemption will be
  4742. attempted.
  4743. Return Value:
  4744. Boolean value indicating whether the caller should continue.
  4745. If FALSE, then the current operation should be aborted, as the combination
  4746. of system policy and user input indicated that the risk should not
  4747. be taken.
  4748. --*/
  4749. {
  4750. //
  4751. // This routine should not be called when Authenticode validation is a
  4752. // possibility...
  4753. //
  4754. MYASSERT((DriverSigningPolicy == DRIVERSIGN_NONE) ||
  4755. (DriverSigningPolicy == DRIVERSIGN_WARNING) ||
  4756. (DriverSigningPolicy == DRIVERSIGN_BLOCKING));
  4757. MYASSERT(Problem != SetupapiVerifyNoProblem);
  4758. MYASSERT(ProblemFile && *ProblemFile);
  4759. MYASSERT(Error != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED);
  4760. return _HandleFailedVerification(Owner,
  4761. Problem,
  4762. ProblemFile,
  4763. DeviceDesc,
  4764. DriverSigningPolicy,
  4765. NoUI,
  4766. Error,
  4767. LogContext,
  4768. Flags,
  4769. TargetFile,
  4770. NULL
  4771. );
  4772. }
  4773. BOOL
  4774. _HandleFailedVerification(
  4775. IN HWND Owner,
  4776. IN SetupapiVerifyProblem Problem,
  4777. IN LPCTSTR ProblemFile,
  4778. IN LPCTSTR DeviceDesc, OPTIONAL
  4779. IN DWORD DriverSigningPolicy,
  4780. IN BOOL NoUI,
  4781. IN DWORD Error,
  4782. IN PVOID LogContext, OPTIONAL
  4783. OUT PDWORD Flags, OPTIONAL
  4784. IN LPCTSTR TargetFile, OPTIONAL
  4785. IN HANDLE hWVTStateData OPTIONAL
  4786. )
  4787. /*++
  4788. Routine Description:
  4789. (See pSetupHandleFailedVerification)
  4790. Arguments:
  4791. See pSetupHandleFailedVerification, with following differences:
  4792. DriverSigningPolicy - supplies the driver signing policy currently in
  4793. effect. May be one of the three following values...
  4794. DRIVERSIGN_NONE - silently succeed installation of unsigned/
  4795. incorrectly-signed files. A PSS log entry will
  4796. be generated, however.
  4797. DRIVERSIGN_WARNING - warn the user, but let them choose whether or not
  4798. they still want to install the problematic file.
  4799. If the user elects to proceed with the
  4800. installation, A PSS log entry will be generated
  4801. noting this fact.
  4802. DRIVERSIGN_BLOCKING - do not allow the file to be installed
  4803. ...potentially OR'ed with DRIVERSIGN_ALLOW_AUTHENTICODE (i.e., high bit
  4804. set). This flag indicates that policy allows for validation via an
  4805. Authenticode catalog.
  4806. hWVTStateData - optionally supplies a handle that provides WinVerifyTrust
  4807. state data retrieved upon successful validation of an Authenticode
  4808. catalog, in the case where the publisher isn't in the TrustedPublisher
  4809. store. This handle is used for the Authenticode confirmation dialog
  4810. in order to present the user with explicit information about the
  4811. Authenticode package they're about to install (i.e., publisher, signed
  4812. date, etc.). NOTE: if this handle is non-NULL, then the
  4813. DRIVERSIGN_ALLOW_AUTHENTICODE bit must also be set in the specified
  4814. DriverSigningPolicy.
  4815. Return Value:
  4816. Boolean value indicating whether the caller should continue.
  4817. If FALSE, then the current operation should be aborted, as the combination
  4818. of system policy and user input indicated that the risk should not
  4819. be taken.
  4820. NOTE: If this function returns TRUE (i.e., non-zero), and if the caller
  4821. specified (via the AuthSigPromptUser) that the user was to be prompted
  4822. regarding their trust of the publisher, then the caller should subsequently
  4823. treat the file and catalog as valid, and validate subsequent files via that
  4824. catalog as if its publisher were in the trusted store (because the user's
  4825. choice last for the duration of the queue committal currently underway).
  4826. --*/
  4827. {
  4828. BOOL b;
  4829. INT_PTR iRes;
  4830. HANDLE hDialogEvent = NULL;
  4831. MYASSERT(Error != NO_ERROR);
  4832. MYASSERT((Problem != SetupapiVerifyNoProblem) && ProblemFile && *ProblemFile);
  4833. //
  4834. // If we're being called to prompt the user about whether they trust an
  4835. // Authenticode publisher, then our ProblemFile had better be a catalog...
  4836. //
  4837. MYASSERT((Error != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED) ||
  4838. (Problem == SetupapiVerifyCatalogProblem));
  4839. //
  4840. // If we already established that the Authenticode publisher should be
  4841. // trusted, then we shouldn't be calling this routine...
  4842. //
  4843. MYASSERT(Error != ERROR_AUTHENTICODE_TRUSTED_PUBLISHER);
  4844. //
  4845. // If we've been asked to prompt the user about whether they trust the
  4846. // publisher of an Authenticode catalog, then policy had better indicate
  4847. // that this is OK!
  4848. //
  4849. MYASSERT(!hWVTStateData || (DriverSigningPolicy & DRIVERSIGN_ALLOW_AUTHENTICODE));
  4850. //
  4851. // If we're running non-interactive, then we always silently block,
  4852. // regardless of policy.
  4853. //
  4854. if(GlobalSetupFlags & PSPGF_NONINTERACTIVE) {
  4855. //
  4856. // SPLOG -- log a PSS entry recording this event.
  4857. //
  4858. if(Problem == SetupapiVerifyDriverBlocked) {
  4859. LogFailedVerification(
  4860. (PSETUP_LOG_CONTEXT) LogContext,
  4861. DeviceDesc ? MSG_LOG_DRIVER_BLOCKED_FOR_DEVICE_ERROR_NONINTERACTIVE : MSG_LOG_DRIVER_BLOCKED_ERROR_NONINTERACTIVE,
  4862. Error,
  4863. ProblemFile,
  4864. DeviceDesc,
  4865. DRIVER_LOG_ERROR
  4866. );
  4867. } else {
  4868. LogFailedVerification(
  4869. (PSETUP_LOG_CONTEXT) LogContext,
  4870. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_NONINTERACTIVE : MSG_LOG_SIGNING_ERROR_NONINTERACTIVE,
  4871. Error,
  4872. ProblemFile,
  4873. DeviceDesc,
  4874. DRIVER_LOG_ERROR
  4875. );
  4876. }
  4877. return FALSE;
  4878. }
  4879. if(GuiSetupInProgress) {
  4880. hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
  4881. }
  4882. if(Problem == SetupapiVerifyDriverBlocked) {
  4883. //
  4884. // Handle a driver block failure.
  4885. // only applicable to UNICODE
  4886. // ANSI won't report this problem code
  4887. //
  4888. HSDB hSDBDrvMain = NULL;
  4889. TAGREF tagref = TAGREF_NULL;
  4890. DRIVERBLOCK_PROMPT DriverBlockPrompt = {0};
  4891. //
  4892. // Never continue if the driver is in the bad driver database!
  4893. //
  4894. b = FALSE;
  4895. LogFailedVerification(
  4896. (PSETUP_LOG_CONTEXT) LogContext,
  4897. DeviceDesc ? MSG_LOG_DRIVER_BLOCKED_FOR_DEVICE_ERROR : MSG_LOG_DRIVER_BLOCKED_ERROR,
  4898. Error,
  4899. ProblemFile,
  4900. DeviceDesc,
  4901. DRIVER_LOG_ERROR
  4902. );
  4903. if(!(GlobalSetupFlags & PSPGF_UNATTENDED_SETUP)) {
  4904. //
  4905. // Show the driver blocking UI
  4906. //
  4907. DriverBlockPrompt.lpszFile = (TargetFile != NULL)
  4908. ? TargetFile
  4909. : ProblemFile;
  4910. if((hSDBDrvMain = SdbInitDatabaseEx(SDB_DATABASE_MAIN_DRIVERS,
  4911. NULL,
  4912. DEFAULT_IMAGE))) {
  4913. HANDLE hFile = INVALID_HANDLE_VALUE;
  4914. //
  4915. // We are probably dealing with a temp file name at this point,
  4916. // so we need to get a file handle to pass to SdbGetDatabaseMatch
  4917. // along with the final destination file name.
  4918. //
  4919. hFile = CreateFile(ProblemFile,
  4920. GENERIC_READ,
  4921. FILE_SHARE_READ,
  4922. NULL,
  4923. OPEN_EXISTING,
  4924. 0,
  4925. NULL
  4926. );
  4927. if (hFile != INVALID_HANDLE_VALUE) {
  4928. //
  4929. // Pass the TargetFile (the destination filename) to
  4930. // SdbGetDatabaseMatch because that will be what is
  4931. // in the bad driver database.
  4932. //
  4933. tagref = SdbGetDatabaseMatch(hSDBDrvMain,
  4934. (TargetFile != NULL)
  4935. ? pSetupGetFileTitle(TargetFile)
  4936. : ProblemFile,
  4937. hFile,
  4938. NULL,
  4939. 0);
  4940. if (tagref != TAGREF_NULL) {
  4941. SdbReadDriverInformation(hSDBDrvMain,
  4942. tagref,
  4943. &(DriverBlockPrompt.entryinfo));
  4944. }
  4945. CloseHandle(hFile);
  4946. }
  4947. SdbReleaseDatabase(hSDBDrvMain);
  4948. }
  4949. //
  4950. // Always call the dialog code, even if we could access the database.
  4951. //
  4952. iRes = DialogBoxParam(MyDllModuleHandle,
  4953. MAKEINTRESOURCE(IDD_DRIVERBLOCK),
  4954. IsWindow(Owner) ? Owner : NULL,
  4955. DriverBlockDlgProc,
  4956. (LPARAM)&DriverBlockPrompt
  4957. );
  4958. }
  4959. } else {
  4960. //
  4961. // Handle a digital signature failure.
  4962. //
  4963. // If the policy is block, then the user always gets informed of a
  4964. // problem (i.e., there is no "yes" option, hence no "yes to all"
  4965. // semantics).
  4966. //
  4967. CERT_PROMPT CertPrompt;
  4968. AUTHENTICODE_CERT_PROMPT AuthenticodeCertPrompt;
  4969. MYASSERT(((DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE) != DRIVERSIGN_BLOCKING)
  4970. || !NoUI);
  4971. CertPrompt.lpszDescription = DeviceDesc;
  4972. CertPrompt.lpszFile = ProblemFile;
  4973. CertPrompt.ProblemType = Problem;
  4974. CertPrompt.DriverSigningPolicy = DriverSigningPolicy;
  4975. AuthenticodeCertPrompt.lpszDescription = DeviceDesc;
  4976. AuthenticodeCertPrompt.hWVTStateData = hWVTStateData;
  4977. AuthenticodeCertPrompt.Error = Error;
  4978. switch(DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE) {
  4979. case DRIVERSIGN_NONE :
  4980. //
  4981. // SPLOG -- log a PSS entry recording this event.
  4982. //
  4983. LogFailedVerification(
  4984. (PSETUP_LOG_CONTEXT) LogContext,
  4985. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_POLICY_NONE : MSG_LOG_SIGNING_ERROR_POLICY_NONE,
  4986. Error,
  4987. ProblemFile,
  4988. DeviceDesc,
  4989. DRIVER_LOG_WARNING
  4990. );
  4991. //
  4992. // If requested, find out if the file is protected (we may need
  4993. // to skip it if it's being queued up for delayed copy).
  4994. //
  4995. if(Flags && TargetFile) {
  4996. MYASSERT(Error != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED);
  4997. if(IsFileProtected(TargetFile,
  4998. (PSETUP_LOG_CONTEXT)LogContext,
  4999. NULL)) {
  5000. *Flags = IQF_TARGET_PROTECTED;
  5001. }
  5002. }
  5003. b = TRUE;
  5004. goto exit;
  5005. case DRIVERSIGN_WARNING :
  5006. if(NoUI) {
  5007. //
  5008. // SPLOG -- log a PSS entry recording this event.
  5009. //
  5010. LogFailedVerification(
  5011. (PSETUP_LOG_CONTEXT) LogContext,
  5012. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_AUTO_YES : MSG_LOG_SIGNING_ERROR_AUTO_YES,
  5013. Error,
  5014. ProblemFile,
  5015. DeviceDesc,
  5016. ((Error == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)
  5017. ? DRIVER_LOG_INFO
  5018. : DRIVER_LOG_WARNING)
  5019. );
  5020. iRes = IDC_VERIFY_WARN_YES;
  5021. } else if(GlobalSetupFlags & PSPGF_UNATTENDED_SETUP) {
  5022. //
  5023. // SPLOG -- log a PSS entry recording this event.
  5024. //
  5025. LogFailedVerification(
  5026. (PSETUP_LOG_CONTEXT) LogContext,
  5027. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_AUTO_NO : MSG_LOG_SIGNING_ERROR_AUTO_NO,
  5028. Error,
  5029. ProblemFile,
  5030. DeviceDesc,
  5031. DRIVER_LOG_ERROR
  5032. );
  5033. iRes = IDC_VERIFY_WARN_NO;
  5034. } else {
  5035. if (hDialogEvent) {
  5036. SetEvent(hDialogEvent);
  5037. }
  5038. if(DriverSigningPolicy & DRIVERSIGN_ALLOW_AUTHENTICODE) {
  5039. if(AuthenticodeCertPrompt.Error == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED) {
  5040. iRes = DialogBoxParam(MyDllModuleHandle,
  5041. AuthenticodeCertPrompt.lpszDescription ?
  5042. MAKEINTRESOURCE(IDD_DEVICE_VERIFY_AUTHENTICODE) :
  5043. MAKEINTRESOURCE(IDD_SOFTWARE_VERIFY_AUTHENTICODE),
  5044. IsWindow(Owner) ? Owner : NULL,
  5045. AuthenticodeCertifyDlgProc,
  5046. (LPARAM)&AuthenticodeCertPrompt
  5047. );
  5048. } else {
  5049. iRes = DialogBoxParam(MyDllModuleHandle,
  5050. AuthenticodeCertPrompt.lpszDescription ?
  5051. MAKEINTRESOURCE(IDD_DEVICE_VERIFY_NO_AUTHENTICODE) :
  5052. MAKEINTRESOURCE(IDD_SOFTWARE_VERIFY_NO_AUTHENTICODE),
  5053. IsWindow(Owner) ? Owner : NULL,
  5054. NoAuthenticodeCertifyDlgProc,
  5055. (LPARAM)&AuthenticodeCertPrompt
  5056. );
  5057. }
  5058. } else {
  5059. iRes = DialogBoxParam(MyDllModuleHandle,
  5060. CertPrompt.lpszDescription ?
  5061. MAKEINTRESOURCE(IDD_DEVICE_VERIFY_WARNING) :
  5062. MAKEINTRESOURCE(IDD_SOFTWARE_VERIFY_WARNING),
  5063. IsWindow(Owner) ? Owner : NULL,
  5064. CertifyDlgProc,
  5065. (LPARAM)&CertPrompt
  5066. );
  5067. }
  5068. LogFailedVerification(
  5069. (PSETUP_LOG_CONTEXT) LogContext,
  5070. DeviceDesc
  5071. ?(iRes == IDC_VERIFY_WARN_YES ? MSG_LOG_DRIVER_SIGNING_ERROR_WARN_YES : MSG_LOG_DRIVER_SIGNING_ERROR_WARN_NO)
  5072. :(iRes == IDC_VERIFY_WARN_YES ? MSG_LOG_SIGNING_ERROR_WARN_YES : MSG_LOG_SIGNING_ERROR_WARN_NO),
  5073. Error,
  5074. ProblemFile,
  5075. DeviceDesc,
  5076. ((Error == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)
  5077. ? ((iRes == IDC_VERIFY_WARN_YES) ? DRIVER_LOG_INFO : DRIVER_LOG_ERROR)
  5078. : ((iRes == IDC_VERIFY_WARN_YES) ? DRIVER_LOG_WARNING : DRIVER_LOG_ERROR))
  5079. );
  5080. }
  5081. break;
  5082. case DRIVERSIGN_BLOCKING :
  5083. if(GlobalSetupFlags & PSPGF_UNATTENDED_SETUP) {
  5084. //
  5085. // During UNATTENDED, we block silently
  5086. //
  5087. LogFailedVerification(
  5088. (PSETUP_LOG_CONTEXT) LogContext,
  5089. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_SILENT_BLOCK : MSG_LOG_SIGNING_ERROR_SILENT_BLOCK,
  5090. Error,
  5091. ProblemFile,
  5092. DeviceDesc,
  5093. DRIVER_LOG_ERROR
  5094. );
  5095. iRes = IDC_VERIFY_BLOCK_OK;
  5096. } else {
  5097. LogFailedVerification(
  5098. (PSETUP_LOG_CONTEXT) LogContext,
  5099. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_POLICY_BLOCK : MSG_LOG_SIGNING_ERROR_POLICY_BLOCK,
  5100. Error,
  5101. ProblemFile,
  5102. DeviceDesc,
  5103. DRIVER_LOG_ERROR
  5104. );
  5105. if (hDialogEvent) {
  5106. SetEvent(hDialogEvent);
  5107. }
  5108. iRes = DialogBoxParam(MyDllModuleHandle,
  5109. CertPrompt.lpszDescription ?
  5110. MAKEINTRESOURCE(IDD_DEVICE_VERIFY_BLOCK) :
  5111. MAKEINTRESOURCE(IDD_SOFTWARE_VERIFY_BLOCK),
  5112. IsWindow(Owner) ? Owner : NULL,
  5113. CertifyDlgProc,
  5114. (LPARAM)&CertPrompt
  5115. );
  5116. }
  5117. break;
  5118. default :
  5119. //
  5120. // We don't know about any other policy values!
  5121. //
  5122. MYASSERT(0);
  5123. b = FALSE;
  5124. goto exit;
  5125. }
  5126. switch(iRes) {
  5127. case IDC_VERIFY_WARN_NO:
  5128. case IDC_VERIFY_BLOCK_OK:
  5129. b = FALSE;
  5130. break;
  5131. case IDC_VERIFY_WARN_YES:
  5132. if(TargetFile) {
  5133. pSetupExemptFileFromProtection(TargetFile,
  5134. (DWORD) -1,
  5135. (PSETUP_LOG_CONTEXT)LogContext,
  5136. Flags
  5137. );
  5138. }
  5139. b = TRUE;
  5140. break;
  5141. default:
  5142. //
  5143. // Shouldn't get any other values.
  5144. //
  5145. MYASSERT(0);
  5146. b = FALSE;
  5147. }
  5148. }
  5149. exit:
  5150. if(hDialogEvent) {
  5151. ResetEvent(hDialogEvent);
  5152. CloseHandle(hDialogEvent);
  5153. }
  5154. return b;
  5155. }
  5156. INT_PTR
  5157. CALLBACK
  5158. CertifyDlgProc(
  5159. IN HWND hwnd,
  5160. IN UINT msg,
  5161. IN WPARAM wParam,
  5162. IN LPARAM lParam
  5163. )
  5164. /*++
  5165. Routine Description:
  5166. This is the dialog procedure for the driver signing UI that is presented to
  5167. the user when a verification failure is encountered. This dialog handles
  5168. both the 'warn' and 'block' cases.
  5169. --*/
  5170. {
  5171. LOGFONT LogFont;
  5172. HFONT hFontBold = NULL;
  5173. HICON hIcon = NULL;
  5174. OSVERSIONINFOEX osVersionInfoEx;
  5175. PCERT_PROMPT lpCertPrompt;
  5176. lpCertPrompt = (PCERT_PROMPT)GetWindowLongPtr(hwnd, DWLP_USER);
  5177. switch(msg) {
  5178. case WM_INITDIALOG:
  5179. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  5180. MessageBeep(MB_ICONASTERISK);
  5181. lpCertPrompt = (PCERT_PROMPT)lParam;
  5182. //
  5183. // If lpszDescription is not NULL then this is the device verify
  5184. // warning dialog, otherwise it is the software warning dialog.
  5185. //
  5186. if(lpCertPrompt->lpszDescription != NULL) {
  5187. SetDlgItemText(hwnd, IDC_VERIFY_FILENAME, lpCertPrompt->lpszDescription);
  5188. SetDlgText(hwnd, IDC_VERIFY_BOLD, IDS_DEVICE_VERIFY_MSG1, IDS_DEVICE_VERIFY_MSG2);
  5189. } else {
  5190. SetDlgText(hwnd, IDC_VERIFY_BOLD, IDS_SOFTWARE_VERIFY_MSG1, IDS_SOFTWARE_VERIFY_MSG2);
  5191. }
  5192. //
  5193. // Create the bold font and bold any necessary text.
  5194. //
  5195. hFontBold = (HFONT)SendMessage(GetDlgItem(hwnd, IDC_VERIFY_BOLD),
  5196. WM_GETFONT, 0, 0);
  5197. GetObject(hFontBold, sizeof(LogFont), &LogFont);
  5198. LogFont.lfWeight = FW_BOLD;
  5199. hFontBold = CreateFontIndirect(&LogFont);
  5200. if (hFontBold) {
  5201. SetWindowFont(GetDlgItem(hwnd, IDC_VERIFY_BOLD), hFontBold, TRUE);
  5202. }
  5203. //
  5204. // Set the appropriate warning or error icon.
  5205. //
  5206. // (We shouldn't be here if policy is "Ignore", nor if we're
  5207. // allowing for Authenticode signatures.)
  5208. //
  5209. MYASSERT((lpCertPrompt->DriverSigningPolicy == DRIVERSIGN_WARNING) ||
  5210. ((lpCertPrompt->DriverSigningPolicy & ~DRIVERSIGN_ALLOW_AUTHENTICODE) == DRIVERSIGN_BLOCKING));
  5211. hIcon = LoadIcon(NULL,
  5212. (lpCertPrompt->DriverSigningPolicy == DRIVERSIGN_WARNING) ?
  5213. IDI_WARNING :
  5214. IDI_ERROR
  5215. );
  5216. SendDlgItemMessage(hwnd, IDC_VERIFY_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  5217. //
  5218. // The link won't work in GUI mode setup since help center has not yet
  5219. // been installed, so we will just show the static text instead.
  5220. //
  5221. ShowWindow(GetDlgItem(hwnd, IDC_VERIFY_TESTING_LINK), !GuiSetupInProgress);
  5222. ShowWindow(GetDlgItem(hwnd, IDC_VERIFY_TESTING_TEXT), GuiSetupInProgress);
  5223. //
  5224. // If we are in GUI mode setup then we want to change the text of
  5225. // the buttons to be "Yes" and "No". We also add the following line
  5226. // of text: "Do you want to continue installing the software for
  5227. // this hardware?"
  5228. //
  5229. ShowWindow(GetDlgItem(hwnd, IDC_VERIFY_SETUP_TEXT), GuiSetupInProgress);
  5230. if (GuiSetupInProgress) {
  5231. TCHAR szButtonText[MAX_PATH];
  5232. if (LoadString(MyDllModuleHandle, IDS_YES, szButtonText, SIZECHARS(szButtonText))) {
  5233. SetDlgItemText(hwnd, IDC_VERIFY_WARN_YES, szButtonText);
  5234. }
  5235. if (LoadString(MyDllModuleHandle, IDS_NO, szButtonText, SIZECHARS(szButtonText))) {
  5236. SetDlgItemText(hwnd, IDC_VERIFY_WARN_NO, szButtonText);
  5237. }
  5238. }
  5239. //
  5240. // Make sure this dialog is in the foreground (at least for this
  5241. // process).
  5242. //
  5243. SetForegroundWindow(hwnd);
  5244. if(lpCertPrompt->DriverSigningPolicy == DRIVERSIGN_WARNING) {
  5245. SetFocus(GetDlgItem(hwnd, IDC_VERIFY_WARN_NO));
  5246. }
  5247. return FALSE;
  5248. case WM_DESTROY:
  5249. if (hFontBold) {
  5250. DeleteObject(hFontBold);
  5251. hFontBold = NULL;
  5252. }
  5253. if (hIcon) {
  5254. DestroyIcon(hIcon);
  5255. }
  5256. break;
  5257. case WM_NOTIFY:
  5258. switch (((NMHDR FAR *)lParam)->code) {
  5259. case NM_RETURN:
  5260. case NM_CLICK:
  5261. //
  5262. // We need to know if this is a server machine or a workstation
  5263. // machine since there are different help topic structures for
  5264. // the different products.
  5265. //
  5266. ZeroMemory(&osVersionInfoEx, sizeof(osVersionInfoEx));
  5267. osVersionInfoEx.dwOSVersionInfoSize = sizeof(osVersionInfoEx);
  5268. if (!GetVersionEx((LPOSVERSIONINFO)&osVersionInfoEx)) {
  5269. //
  5270. // If GetVersionEx fails then assume this is a workstation
  5271. // machine.
  5272. //
  5273. osVersionInfoEx.wProductType = VER_NT_WORKSTATION;
  5274. }
  5275. ShellExecute(hwnd,
  5276. TEXT("open"),
  5277. TEXT("HELPCTR.EXE"),
  5278. (osVersionInfoEx.wProductType == VER_NT_WORKSTATION)
  5279. ? TEXT("HELPCTR.EXE -url hcp://services/subsite?node=TopLevelBucket_4/Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm")
  5280. : TEXT("HELPCTR.EXE -url hcp://services/subsite?node=Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm"),
  5281. NULL,
  5282. SW_SHOWNORMAL
  5283. );
  5284. break;
  5285. }
  5286. break;
  5287. case WM_COMMAND:
  5288. switch(wParam) {
  5289. case IDC_VERIFY_WARN_NO:
  5290. case IDC_VERIFY_WARN_YES:
  5291. case IDC_VERIFY_BLOCK_OK:
  5292. EndDialog(hwnd, (int)wParam);
  5293. break;
  5294. default:
  5295. break;
  5296. }
  5297. break;
  5298. default:
  5299. break;
  5300. }
  5301. return FALSE;
  5302. }
  5303. PTSTR
  5304. GetCryptoErrorString(
  5305. HRESULT hr
  5306. )
  5307. /*++
  5308. Routine Description:
  5309. This routine takes in an HRESULT error result returned by WinVerifyTrust
  5310. and returns a buffer containing a friendly error string that can be
  5311. presented to the user.
  5312. NOTE: This API calls FormatMessage and so the returned string MUST be freed
  5313. using LocalFree and not MyFree
  5314. Arguments:
  5315. hr - HRESULT returned from WinVerifyTrust.
  5316. Return Value:
  5317. Pointer to the error string, or NULL if an error occured.
  5318. --*/
  5319. {
  5320. UINT ResourceId = 0;
  5321. DWORD_PTR MessageArgument;
  5322. ULONG CchLength;
  5323. PTSTR CryptoError = NULL;
  5324. PTSTR TempBuffer = NULL;
  5325. TCHAR Error[33];
  5326. try {
  5327. //
  5328. // See if it maps to some non system error code
  5329. //
  5330. switch (hr) {
  5331. case TRUST_E_SYSTEM_ERROR:
  5332. case ERROR_NOT_ENOUGH_MEMORY:
  5333. case ERROR_INVALID_PARAMETER:
  5334. //
  5335. // Set the resourceid to zero... these will be mapped to
  5336. // IDS_SPC_UNKNOWN and the error code displayed.
  5337. //
  5338. ResourceId = 0;
  5339. break;
  5340. case HRESULT_FROM_WIN32(ERROR_NOT_FOUND):
  5341. ResourceId = IDS_ELEMENT_NOT_FOUND;
  5342. break;
  5343. case CRYPT_E_FILE_ERROR:
  5344. ResourceId = IDS_FILE_NOT_FOUND;
  5345. break;
  5346. case TRUST_E_PROVIDER_UNKNOWN:
  5347. ResourceId = IDS_SPC_PROVIDER;
  5348. break;
  5349. case TRUST_E_SUBJECT_FORM_UNKNOWN:
  5350. ResourceId = IDS_SPC_SUBJECT;
  5351. break;
  5352. case TRUST_E_NOSIGNATURE:
  5353. ResourceId = IDS_SPC_NO_SIGNATURE;
  5354. break;
  5355. case CRYPT_E_BAD_MSG:
  5356. ResourceId = IDS_SPC_BAD_SIGNATURE;
  5357. break;
  5358. case TRUST_E_BAD_DIGEST:
  5359. ResourceId = IDS_SPC_BAD_FILE_DIGEST;
  5360. break;
  5361. case CRYPT_E_NO_SIGNER:
  5362. ResourceId = IDS_SPC_NO_VALID_SIGNER;
  5363. break;
  5364. case TRUST_E_NO_SIGNER_CERT:
  5365. ResourceId = IDS_SPC_SIGNER_CERT;
  5366. break;
  5367. case TRUST_E_COUNTER_SIGNER:
  5368. ResourceId = IDS_SPC_VALID_COUNTERSIGNER;
  5369. break;
  5370. case CERT_E_EXPIRED:
  5371. ResourceId = IDS_SPC_CERT_EXPIRED;
  5372. break;
  5373. case TRUST_E_CERT_SIGNATURE:
  5374. ResourceId = IDS_SPC_CERT_SIGNATURE;
  5375. break;
  5376. case CERT_E_CHAINING:
  5377. ResourceId = IDS_SPC_CHAINING;
  5378. break;
  5379. case CERT_E_UNTRUSTEDROOT:
  5380. ResourceId = IDS_SPC_UNTRUSTED_ROOT;
  5381. break;
  5382. case CERT_E_UNTRUSTEDTESTROOT:
  5383. ResourceId = IDS_SPC_UNTRUSTED_TEST_ROOT;
  5384. break;
  5385. case CERT_E_VALIDITYPERIODNESTING:
  5386. ResourceId = IDS_SPC_INVALID_CERT_NESTING;
  5387. break;
  5388. case CERT_E_PURPOSE:
  5389. ResourceId = IDS_SPC_INVALID_PURPOSE;
  5390. break;
  5391. case TRUST_E_BASIC_CONSTRAINTS:
  5392. ResourceId = IDS_SPC_INVALID_BASIC_CONSTRAINTS;
  5393. break;
  5394. case TRUST_E_FINANCIAL_CRITERIA:
  5395. ResourceId = IDS_SPC_INVALID_FINANCIAL;
  5396. break;
  5397. case TRUST_E_TIME_STAMP:
  5398. ResourceId = IDS_SPC_TIMESTAMP;
  5399. break;
  5400. case CERT_E_REVOKED:
  5401. ResourceId = IDS_SPC_CERT_REVOKED;
  5402. break;
  5403. case CERT_E_REVOCATION_FAILURE:
  5404. ResourceId = IDS_SPC_REVOCATION_ERROR;
  5405. break;
  5406. case CRYPT_E_SECURITY_SETTINGS:
  5407. ResourceId = IDS_SPC_SECURITY_SETTINGS;
  5408. break;
  5409. case CERT_E_MALFORMED:
  5410. ResourceId = IDS_SPC_INVALID_EXTENSION;
  5411. break;
  5412. case CERT_E_WRONG_USAGE:
  5413. ResourceId = IDS_WRONG_USAGE;
  5414. break;
  5415. default:
  5416. ResourceId = 0;
  5417. break;
  5418. }
  5419. //
  5420. // If it does, load the string out of our resource string tables and
  5421. // return that. Otherwise, try to format the message from the system
  5422. //
  5423. if (ResourceId != 0) {
  5424. CryptoError = LocalAlloc(LPTR, (MAX_PATH*sizeof(TCHAR)));
  5425. if (CryptoError) {
  5426. CchLength = LoadString(MyDllModuleHandle,
  5427. ResourceId,
  5428. CryptoError,
  5429. MAX_PATH);
  5430. //
  5431. // Assert that CchLength is between 0 and MAX_PATH, if it is
  5432. // greater than MAX_PATH then the whole string won't fit into
  5433. // the buffer.
  5434. //
  5435. MYASSERT((CchLength > 0) && (CchLength < MAX_PATH));
  5436. //
  5437. // if LoadString returned 0 then free the memory we just allocated
  5438. // and return NULL.
  5439. //
  5440. if (!CchLength) {
  5441. LocalFree(CryptoError);
  5442. CryptoError = NULL;
  5443. leave;
  5444. }
  5445. }
  5446. } else if (( hr >= 0x80093000) && (hr <= 0x80093999)) {
  5447. TempBuffer = LocalAlloc(LPTR, (MAX_PATH*sizeof(TCHAR)));
  5448. if (!TempBuffer) {
  5449. leave;
  5450. }
  5451. CchLength = LoadString(MyDllModuleHandle,
  5452. IDS_SPC_OSS_ERROR,
  5453. TempBuffer,
  5454. MAX_PATH);
  5455. //
  5456. // Assert that CchLength is between 0 and MAX_PATH, if it is
  5457. // greater than MAX_PATH then the whole string won't fit into
  5458. // the buffer.
  5459. //
  5460. MYASSERT((CchLength > 0) && (CchLength < MAX_PATH));
  5461. //
  5462. // if LoadString returned 0 then free the memory we just allocated
  5463. // and return NULL.
  5464. //
  5465. if (!CchLength) {
  5466. LocalFree(TempBuffer);
  5467. TempBuffer = NULL;
  5468. leave;
  5469. }
  5470. StringCchPrintf(Error, SIZECHARS(Error), TEXT("%lx"), hr);
  5471. MessageArgument = (DWORD_PTR)Error;
  5472. if (FormatMessage(
  5473. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  5474. FORMAT_MESSAGE_FROM_STRING |
  5475. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  5476. TempBuffer,
  5477. 0,
  5478. 0,
  5479. (LPWSTR)&CryptoError,
  5480. 0,
  5481. (va_list *)&MessageArgument
  5482. ) == 0) {
  5483. CryptoError = NULL;
  5484. leave;
  5485. }
  5486. } else {
  5487. if (FormatMessage(
  5488. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  5489. FORMAT_MESSAGE_IGNORE_INSERTS |
  5490. FORMAT_MESSAGE_FROM_SYSTEM,
  5491. NULL,
  5492. hr,
  5493. 0,
  5494. (LPWSTR)&CryptoError,
  5495. 0,
  5496. NULL
  5497. ) == 0) {
  5498. TempBuffer = LocalAlloc(LPTR, (MAX_PATH*sizeof(TCHAR)));
  5499. if (!TempBuffer) {
  5500. leave;
  5501. }
  5502. CchLength = LoadString(MyDllModuleHandle,
  5503. IDS_SPC_UNKNOWN,
  5504. TempBuffer,
  5505. MAX_PATH);
  5506. //
  5507. // Assert that CchLength is between 0 and MAX_PATH, if it is
  5508. // greater than MAX_PATH then the whole string won't fit into
  5509. // the buffer.
  5510. //
  5511. MYASSERT((CchLength > 0) && (CchLength < MAX_PATH));
  5512. //
  5513. // if LoadString returned 0 then free the memory we just allocated
  5514. // and return NULL.
  5515. //
  5516. if (!CchLength) {
  5517. LocalFree(TempBuffer);
  5518. TempBuffer = NULL;
  5519. leave;
  5520. }
  5521. StringCchPrintf(Error, SIZECHARS(Error), TEXT("%lx"), hr);
  5522. MessageArgument = (DWORD_PTR)Error;
  5523. if (FormatMessage(
  5524. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  5525. FORMAT_MESSAGE_FROM_STRING |
  5526. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  5527. TempBuffer,
  5528. 0,
  5529. 0,
  5530. (LPWSTR)&CryptoError,
  5531. 0,
  5532. (va_list *)&MessageArgument
  5533. ) == 0) {
  5534. MYASSERT(0);
  5535. CryptoError = NULL;
  5536. leave;
  5537. }
  5538. }
  5539. }
  5540. } except(EXCEPTION_EXECUTE_HANDLER) {
  5541. if(CryptoError) {
  5542. LocalFree(CryptoError);
  5543. CryptoError = NULL;
  5544. }
  5545. }
  5546. if (TempBuffer) {
  5547. LocalFree(TempBuffer);
  5548. }
  5549. return CryptoError;
  5550. }
  5551. INT_PTR
  5552. CALLBACK
  5553. AuthenticodeCertifyDlgProc(
  5554. IN HWND hwnd,
  5555. IN UINT msg,
  5556. IN WPARAM wParam,
  5557. IN LPARAM lParam
  5558. )
  5559. /*++
  5560. Routine Description:
  5561. This is the dialog procedure for the Authenticode driver signing UI that is
  5562. presented to the user when a verification failure is encountered for a non-
  5563. WHQL tested class but there is a valid Authenticode signature associated
  5564. with the package.
  5565. --*/
  5566. {
  5567. HICON hIcon = NULL;
  5568. PAUTHENTICODE_CERT_PROMPT AuthenticodePrompt;
  5569. PCRYPT_PROVIDER_DATA ProviderData;
  5570. PCRYPT_PROVIDER_SGNR ProviderSigner;
  5571. PCRYPT_PROVIDER_CERT ProviderCert;
  5572. FILETIME ftTimestamp;
  5573. SYSTEMTIME stTimestamp;
  5574. PTSTR Provider, Issuer, Timestamp;
  5575. ULONG CchSize;
  5576. TCHAR UnknownBuffer[MAX_PATH];
  5577. AuthenticodePrompt = (PAUTHENTICODE_CERT_PROMPT)GetWindowLongPtr(hwnd, DWLP_USER);
  5578. switch(msg) {
  5579. case WM_INITDIALOG:
  5580. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  5581. MessageBeep(MB_ICONASTERISK);
  5582. AuthenticodePrompt = (PAUTHENTICODE_CERT_PROMPT)lParam;
  5583. //
  5584. // If lpszDescription is not NULL then this is the device verify
  5585. // warning dialog, otherwise it is the software warning dialog.
  5586. //
  5587. if(AuthenticodePrompt->lpszDescription != NULL) {
  5588. SetDlgItemText(hwnd, IDC_VERIFY_FILENAME, AuthenticodePrompt->lpszDescription);
  5589. }
  5590. //
  5591. // In order to get the publisher, issuer, and timestamp, we have
  5592. // to get the PCRYPT_PROVIDER_CERT structure, which we get from
  5593. // the CRYPT_PROVIDER_SGNR structure, which we get from the
  5594. // CRYPT_PROVIDER_DATA structure.
  5595. //
  5596. Provider = Issuer = Timestamp = NULL;
  5597. ProviderData = WTHelperProvDataFromStateData(AuthenticodePrompt->hWVTStateData);
  5598. MYASSERT(ProviderData);
  5599. if (ProviderData) {
  5600. ProviderSigner = WTHelperGetProvSignerFromChain(ProviderData,
  5601. 0,
  5602. FALSE,
  5603. 0);
  5604. MYASSERT(ProviderSigner);
  5605. if (ProviderSigner) {
  5606. ProviderCert = WTHelperGetProvCertFromChain(ProviderSigner,
  5607. 0);
  5608. MYASSERT(ProviderCert);
  5609. if (ProviderCert) {
  5610. //
  5611. // Get the publisher.
  5612. // Note that we want the string to be of the form:
  5613. // <A>publisher</A> so it will show up as a link.
  5614. //
  5615. CchSize = CertGetNameString(ProviderCert->pCert,
  5616. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  5617. 0,
  5618. NULL,
  5619. NULL,
  5620. 0);
  5621. if (CchSize > 1) {
  5622. CchSize += lstrlen(LINK_START) + lstrlen(LINK_END);
  5623. Provider = MyMalloc(CchSize * sizeof(TCHAR));
  5624. if (Provider) {
  5625. if (FAILED(StringCchCopy(Provider, CchSize, LINK_START)) ||
  5626. (0 == CertGetNameString(ProviderCert->pCert,
  5627. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  5628. 0,
  5629. NULL,
  5630. &Provider[lstrlen(LINK_START)],
  5631. CchSize)) ||
  5632. FAILED(StringCchCat(Provider, CchSize, LINK_END))) {
  5633. //
  5634. // We failed to create the string so just
  5635. // free the memory and set Provider to NULL,
  5636. // which will cause us to use the generic
  5637. // string down below.
  5638. //
  5639. MYASSERT(0);
  5640. MyFree(Provider);
  5641. Provider = NULL;
  5642. }
  5643. }
  5644. }
  5645. //
  5646. // Get the issuer
  5647. //
  5648. CchSize = CertGetNameString(ProviderCert->pCert,
  5649. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  5650. CERT_NAME_ISSUER_FLAG,
  5651. NULL,
  5652. NULL,
  5653. 0);
  5654. if (CchSize > 1) {
  5655. Issuer = MyMalloc(CchSize * sizeof(TCHAR));
  5656. if (0 == CertGetNameString(ProviderCert->pCert,
  5657. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  5658. CERT_NAME_ISSUER_FLAG,
  5659. NULL,
  5660. Issuer,
  5661. CchSize)) {
  5662. //
  5663. // We failed to create the Issuer string so just
  5664. // free the memory and set Issuer to NULL, which
  5665. // will cause us to use the generic string down
  5666. // below.
  5667. //
  5668. MYASSERT(0);
  5669. MyFree(Issuer);
  5670. Issuer = NULL;
  5671. }
  5672. }
  5673. //
  5674. // Get the timestamp
  5675. //
  5676. if (FileTimeToLocalFileTime(&ProviderSigner->sftVerifyAsOf,
  5677. &ftTimestamp) &&
  5678. FileTimeToSystemTime(&ftTimestamp, &stTimestamp)) {
  5679. int CchDate, CchTime;
  5680. CchDate = GetDateFormat(LOCALE_USER_DEFAULT,
  5681. DATE_SHORTDATE,
  5682. &stTimestamp,
  5683. NULL,
  5684. NULL,
  5685. 0);
  5686. CchTime = GetTimeFormat(LOCALE_USER_DEFAULT,
  5687. TIME_NOSECONDS,
  5688. &stTimestamp,
  5689. NULL,
  5690. NULL,
  5691. 0);
  5692. MYASSERT(CchDate);
  5693. MYASSERT(CchTime);
  5694. if ((CchDate > 0) && (CchTime > 0)) {
  5695. //
  5696. // Allocate enough memory to hold the date, the
  5697. // time, plus a space inbetween them as well as
  5698. // the terminating NULL.
  5699. //
  5700. Timestamp = MyMalloc((CchDate + CchTime + 2) * sizeof(TCHAR));
  5701. if (Timestamp) {
  5702. if ((0 == GetDateFormat(LOCALE_USER_DEFAULT,
  5703. DATE_SHORTDATE,
  5704. &stTimestamp,
  5705. NULL,
  5706. Timestamp,
  5707. CchDate + 1)) ||
  5708. FAILED(StringCchCat(Timestamp,
  5709. (CchDate + CchTime + 2),
  5710. TEXT(" "))) ||
  5711. (0 == GetTimeFormat(LOCALE_USER_DEFAULT,
  5712. TIME_NOSECONDS,
  5713. &stTimestamp,
  5714. NULL,
  5715. &Timestamp[CchDate+1],
  5716. CchTime + 1))) {
  5717. //
  5718. // We failed to create the Timestamp
  5719. // string so just free the memory and
  5720. // set Timestamp to NULL, which will
  5721. // cause us to use the generic string
  5722. // down below.
  5723. //
  5724. MYASSERT(0);
  5725. MyFree(Timestamp);
  5726. Timestamp = NULL;
  5727. }
  5728. }
  5729. }
  5730. }
  5731. }
  5732. }
  5733. }
  5734. //
  5735. // Set the Provider, Issuer, and Timestamp strings. Note that we
  5736. // will provide "unknown" defaults for Provider and Issuer if
  5737. // they don't exist.
  5738. //
  5739. if (Provider) {
  5740. SetDlgItemText(hwnd, IDC_VERIFY_PUBLISHER_LINK, Provider);
  5741. } else {
  5742. if (LoadString(MyDllModuleHandle,
  5743. IDS_UNKNOWNPUBLISHER,
  5744. UnknownBuffer,
  5745. SIZECHARS(UnknownBuffer))) {
  5746. SetDlgItemText(hwnd, IDC_VERIFY_PUBLISHER_LINK, UnknownBuffer);
  5747. }
  5748. }
  5749. if (Issuer) {
  5750. if (LoadString(MyDllModuleHandle,
  5751. IDS_AUTHENTICITY,
  5752. UnknownBuffer,
  5753. SIZECHARS(UnknownBuffer))) {
  5754. StringCchCat(UnknownBuffer, SIZECHARS(UnknownBuffer), Issuer);
  5755. SetDlgItemText(hwnd, IDC_VERIFY_IDENTITY, UnknownBuffer);
  5756. }
  5757. } else {
  5758. if (LoadString(MyDllModuleHandle,
  5759. IDS_AUTHENTICITY,
  5760. UnknownBuffer,
  5761. SIZECHARS(UnknownBuffer)) &&
  5762. LoadString(MyDllModuleHandle,
  5763. IDS_UNKNOWNPUBLISHERCERTISSUER,
  5764. &UnknownBuffer[lstrlen(UnknownBuffer)],
  5765. (SIZECHARS(UnknownBuffer) - lstrlen(UnknownBuffer)))) {
  5766. SetDlgItemText(hwnd, IDC_VERIFY_IDENTITY, UnknownBuffer);
  5767. }
  5768. }
  5769. if (Timestamp) {
  5770. SetDlgItemText(hwnd, IDC_VERIFY_DATE_PUBLISHED, Timestamp);
  5771. }
  5772. //
  5773. // Set the security alert icon.
  5774. //
  5775. hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(IDI_SECURITY));
  5776. SendDlgItemMessage(hwnd, IDC_VERIFY_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  5777. //
  5778. // Make sure this dialog is in the foreground (at least for this
  5779. // process).
  5780. //
  5781. SetForegroundWindow(hwnd);
  5782. //
  5783. // Set the focus on the "No" button.
  5784. //
  5785. SetFocus(GetDlgItem(hwnd, IDC_VERIFY_WARN_NO));
  5786. return FALSE;
  5787. case WM_DESTROY:
  5788. if (hIcon) {
  5789. DestroyIcon(hIcon);
  5790. }
  5791. break;
  5792. case WM_NOTIFY:
  5793. switch (((NMHDR FAR *)lParam)->code) {
  5794. case NM_RETURN:
  5795. case NM_CLICK:
  5796. switch (((LPNMHDR)lParam)->idFrom) {
  5797. case IDC_VERIFY_TESTING_LINK:
  5798. //
  5799. // NTRAID#NTBUG9-707966-2002/09/24-jasonc
  5800. // We need to change the URL to point to the Authenticode
  5801. // topic.
  5802. //
  5803. ShellExecute(hwnd,
  5804. TEXT("open"),
  5805. TEXT("HELPCTR.EXE"),
  5806. TEXT("HELPCTR.EXE -url hcp://services/subsite?node=TopLevelBucket_4/Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm"),
  5807. NULL,
  5808. SW_SHOWNORMAL
  5809. );
  5810. break;
  5811. case IDC_VERIFY_PUBLISHER_LINK:
  5812. ProviderData = WTHelperProvDataFromStateData(AuthenticodePrompt->hWVTStateData);
  5813. MYASSERT(ProviderData);
  5814. if(ProviderData) {
  5815. ProviderSigner = WTHelperGetProvSignerFromChain(ProviderData,
  5816. 0,
  5817. FALSE,
  5818. 0);
  5819. MYASSERT(ProviderSigner);
  5820. if(ProviderSigner) {
  5821. ProviderCert = WTHelperGetProvCertFromChain(ProviderSigner,
  5822. 0);
  5823. MYASSERT(ProviderCert);
  5824. if(ProviderCert) {
  5825. CRYPTUI_VIEWCERTIFICATE_STRUCT vcs;
  5826. BOOL bPropertiesChanged = FALSE;
  5827. ZeroMemory(&vcs, sizeof(vcs));
  5828. vcs.dwSize = sizeof(vcs);
  5829. vcs.hwndParent = hwnd;
  5830. vcs.pCryptProviderData = ProviderData;
  5831. vcs.fpCryptProviderDataTrustedUsage = TRUE;
  5832. vcs.pCertContext = ProviderCert->pCert;
  5833. CryptUIDlgViewCertificate(
  5834. &vcs,
  5835. &bPropertiesChanged);
  5836. }
  5837. }
  5838. }
  5839. break;
  5840. }
  5841. break;
  5842. }
  5843. break;
  5844. case WM_COMMAND:
  5845. switch(wParam) {
  5846. case IDC_VERIFY_WARN_NO:
  5847. case IDC_VERIFY_WARN_YES:
  5848. EndDialog(hwnd, (int)wParam);
  5849. break;
  5850. case IDC_VERIFY_WARN_MORE_INFO:
  5851. WinHelp(hwnd, TEXT("SECAUTH.HLP"), HELP_CONTEXT, IDH_SECAUTH_SIGNED);
  5852. break;
  5853. default:
  5854. break;
  5855. }
  5856. break;
  5857. default:
  5858. break;
  5859. }
  5860. return FALSE;
  5861. }
  5862. INT_PTR
  5863. CALLBACK
  5864. NoAuthenticodeCertifyDlgProc(
  5865. IN HWND hwnd,
  5866. IN UINT msg,
  5867. IN WPARAM wParam,
  5868. IN LPARAM lParam
  5869. )
  5870. /*++
  5871. Routine Description:
  5872. This is the dialog procedure for the Authenticode driver signing UI that is
  5873. presented to the user when a verification failure is encountered for a non-
  5874. WHQL tested class.
  5875. --*/
  5876. {
  5877. HICON hIcon = NULL;
  5878. PAUTHENTICODE_CERT_PROMPT AuthenticodePrompt;
  5879. PTSTR ErrorString;
  5880. AuthenticodePrompt = (PAUTHENTICODE_CERT_PROMPT)GetWindowLongPtr(hwnd, DWLP_USER);
  5881. switch(msg) {
  5882. case WM_INITDIALOG:
  5883. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  5884. MessageBeep(MB_ICONASTERISK);
  5885. AuthenticodePrompt = (PAUTHENTICODE_CERT_PROMPT)lParam;
  5886. //
  5887. // If lpszDescription is not NULL then this is the device verify
  5888. // warning dialog, otherwise it is the software warning dialog.
  5889. //
  5890. if(AuthenticodePrompt->lpszDescription != NULL) {
  5891. SetDlgItemText(hwnd, IDC_VERIFY_FILENAME, AuthenticodePrompt->lpszDescription);
  5892. }
  5893. ErrorString = GetCryptoErrorString(HRESULT_FROM_SETUPAPI(AuthenticodePrompt->Error));
  5894. if (ErrorString) {
  5895. SetDlgItemText(hwnd, IDC_VERIFY_AUTHENTICODE_PROBLEM, ErrorString);
  5896. }
  5897. //
  5898. // Set the security alert icon.
  5899. //
  5900. hIcon = LoadIcon(NULL,
  5901. IDI_WARNING
  5902. );
  5903. SendDlgItemMessage(hwnd, IDC_VERIFY_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  5904. //
  5905. // Make sure this dialog is in the foreground (at least for this
  5906. // process).
  5907. //
  5908. SetForegroundWindow(hwnd);
  5909. //
  5910. // Set the focus on the "No" button.
  5911. //
  5912. SetFocus(GetDlgItem(hwnd, IDC_VERIFY_WARN_NO));
  5913. return FALSE;
  5914. case WM_DESTROY:
  5915. if (hIcon) {
  5916. DestroyIcon(hIcon);
  5917. }
  5918. break;
  5919. case WM_NOTIFY:
  5920. switch (((NMHDR FAR *)lParam)->code) {
  5921. case NM_RETURN:
  5922. case NM_CLICK:
  5923. switch (((LPNMHDR)lParam)->idFrom) {
  5924. case IDC_VERIFY_TESTING_LINK:
  5925. //
  5926. // NTRAID#NTBUG9-707966-2002/09/24-jasonc
  5927. // We need to change the URL to point to the Authenticode
  5928. // topic.
  5929. //
  5930. ShellExecute(hwnd,
  5931. TEXT("open"),
  5932. TEXT("HELPCTR.EXE"),
  5933. TEXT("HELPCTR.EXE -url hcp://services/subsite?node=TopLevelBucket_4/Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm"),
  5934. NULL,
  5935. SW_SHOWNORMAL
  5936. );
  5937. break;
  5938. }
  5939. break;
  5940. }
  5941. break;
  5942. case WM_COMMAND:
  5943. switch(wParam) {
  5944. case IDC_VERIFY_WARN_NO:
  5945. case IDC_VERIFY_WARN_YES:
  5946. EndDialog(hwnd, (int)wParam);
  5947. break;
  5948. case IDC_VERIFY_WARN_MORE_INFO:
  5949. WinHelp(hwnd, TEXT("SECAUTH.HLP"), HELP_CONTEXT, IDH_SECAUTH_UNSIGNED);
  5950. break;
  5951. default:
  5952. break;
  5953. }
  5954. break;
  5955. default:
  5956. break;
  5957. }
  5958. return FALSE;
  5959. }
  5960. INT_PTR
  5961. CALLBACK
  5962. DriverBlockDlgProc(
  5963. IN HWND hwnd,
  5964. IN UINT msg,
  5965. IN WPARAM wParam,
  5966. IN LPARAM lParam
  5967. )
  5968. /*++
  5969. Routine Description:
  5970. This is the dialog procedure for the driver blocking UI that is presented to
  5971. the user when a a driver that is about to be installed is found in the bad
  5972. driver database.
  5973. --*/
  5974. {
  5975. HICON hIcon = NULL;
  5976. LPTSTR pBuffer = NULL;
  5977. ULONG BufferSize;
  5978. static HAPPHELPINFOCONTEXT hAppHelpInfoContext = NULL;
  5979. static SDBENTRYINFO SdbEntryInfo;
  5980. PDRIVERBLOCK_PROMPT lpDriverBlockPrompt;
  5981. lpDriverBlockPrompt = (PDRIVERBLOCK_PROMPT)GetWindowLongPtr(hwnd, DWLP_USER);
  5982. switch(msg) {
  5983. case WM_INITDIALOG:
  5984. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  5985. MessageBeep(MB_ICONASTERISK);
  5986. lpDriverBlockPrompt = (PDRIVERBLOCK_PROMPT)lParam;
  5987. hIcon = LoadIcon(MyDllModuleHandle,
  5988. MAKEINTRESOURCE(IDI_DRIVERBLOCK));
  5989. SendDlgItemMessage(hwnd, IDC_DRIVERBLOCK_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  5990. hAppHelpInfoContext = SdbOpenApphelpInformation(&lpDriverBlockPrompt->entryinfo.guidDB,
  5991. &lpDriverBlockPrompt->entryinfo.guidID);
  5992. if ((hAppHelpInfoContext) &&
  5993. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  5994. ApphelpAppName,
  5995. NULL,
  5996. 0)) != 0) &&
  5997. (pBuffer = MyMalloc(BufferSize)) &&
  5998. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  5999. ApphelpAppName,
  6000. pBuffer,
  6001. BufferSize)) != 0)) {
  6002. SetDlgItemText(hwnd, IDC_DRIVERBLOCK_APPNAME, pBuffer);
  6003. MyFree(pBuffer);
  6004. } else if (lpDriverBlockPrompt->lpszFile) {
  6005. SetDlgItemText(hwnd, IDC_DRIVERBLOCK_APPNAME, pSetupGetFileTitle(lpDriverBlockPrompt->lpszFile));
  6006. }
  6007. if ((hAppHelpInfoContext) &&
  6008. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  6009. ApphelpDetails,
  6010. NULL,
  6011. 0)) != 0) &&
  6012. (pBuffer = MyMalloc(BufferSize)) &&
  6013. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  6014. ApphelpDetails,
  6015. pBuffer,
  6016. BufferSize)) != 0)) {
  6017. SetDlgItemText(hwnd, IDC_DRIVERBLOCK_SUMMARY, pBuffer);
  6018. MyFree(pBuffer);
  6019. }
  6020. //
  6021. // Make sure this dialog is in the foreground (at least for this
  6022. // process).
  6023. //
  6024. SetForegroundWindow(hwnd);
  6025. return FALSE;
  6026. case WM_DESTROY:
  6027. if (hIcon) {
  6028. DestroyIcon(hIcon);
  6029. }
  6030. if (hAppHelpInfoContext) {
  6031. SdbCloseApphelpInformation(hAppHelpInfoContext);
  6032. }
  6033. break;
  6034. case WM_COMMAND:
  6035. switch(LOWORD(wParam)) {
  6036. case IDCANCEL:
  6037. EndDialog(hwnd, (int)wParam);
  6038. break;
  6039. case IDC_DRIVERBLOCK_DETAILS:
  6040. if (hAppHelpInfoContext) {
  6041. BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  6042. ApphelpHelpCenterURL,
  6043. NULL,
  6044. 0);
  6045. if (BufferSize && (pBuffer = MyMalloc(BufferSize + (lstrlen(TEXT("HELPCTR.EXE -url ")) * sizeof(TCHAR))))) {
  6046. lstrcpy(pBuffer, TEXT("HELPCTR.EXE -url "));
  6047. BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  6048. ApphelpHelpCenterURL,
  6049. (PVOID)&pBuffer[lstrlen(TEXT("HELPCTR.EXE -url "))],
  6050. BufferSize);
  6051. if (BufferSize) {
  6052. ShellExecute(hwnd,
  6053. TEXT("open"),
  6054. TEXT("HELPCTR.EXE"),
  6055. pBuffer,
  6056. NULL,
  6057. SW_SHOWNORMAL);
  6058. }
  6059. MyFree(pBuffer);
  6060. }
  6061. }
  6062. break;
  6063. default:
  6064. break;
  6065. }
  6066. break;
  6067. default:
  6068. break;
  6069. }
  6070. return FALSE;
  6071. }
  6072. DWORD
  6073. pGetInfOriginalNameAndCatalogFile(
  6074. IN PLOADED_INF Inf, OPTIONAL
  6075. IN LPCTSTR CurrentName, OPTIONAL
  6076. OUT PBOOL DifferentName, OPTIONAL
  6077. OUT LPTSTR OriginalName, OPTIONAL
  6078. IN DWORD OriginalNameSize,
  6079. OUT LPTSTR OriginalCatalogName, OPTIONAL
  6080. IN DWORD OriginalCatalogNameSize,
  6081. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo OPTIONAL
  6082. )
  6083. /*++
  6084. Routine Description:
  6085. This routine determines whether a specified inf once had a different
  6086. original name, such as in the case where the Di stuff copied and renamed a
  6087. device inf.
  6088. (Information about an INF's original name comes from the PNF.)
  6089. This routine can also optionally return the original name of the catalog
  6090. file for this INF.
  6091. Arguments:
  6092. Inf - optionally, supplies a pointer to a LOADED_INF whose original name
  6093. and catalog file are to be queried. If this parameter isn't specified,
  6094. then CurrentName must be specified.
  6095. CurrentName - optionally, supplies the path to the INF whose original name
  6096. is to be queried. If Inf parameter is specified, this parameter is
  6097. ignored.
  6098. DifferentName - optionally, supplies the address of a boolean variable that,
  6099. upon successful return, is set to TRUE if the INF's current name is
  6100. different than its original name.
  6101. OriginalName - if this routine returns successfully, and the DifferentName
  6102. boolean was set to TRUE, then this optional buffer receives
  6103. the INF's original name, which _will not_ be the same as the current
  6104. name.
  6105. OriginalNameSize - supplies size of buffer (bytes for ansi, chars for
  6106. unicode) of OriginalName buffer, or zero if OriginalName is NULL.
  6107. OriginalCatalogName - optionally, supplies a buffer that receives the
  6108. original name of the catalog specified by this INF. If the catalog
  6109. doesn't specify a catalog file, this buffer will be set to an empty
  6110. string.
  6111. OriginalCatalogNameSize - supplies size, in characters, of
  6112. OriginalCatalogName buffer (zero if buffer not supplied).
  6113. AltPlatformInfo - optionally, supplies the address of a structure describing
  6114. the platform parameters that should be used in formulating the decorated
  6115. CatalogFile= entry to be used when searching for the INF's associated
  6116. catalog file.
  6117. Return Value:
  6118. If information is successfully retrieved from the INF, the return value is
  6119. NO_ERROR. Otherwise, it is a Win32 error code indicating the cause of
  6120. failure.
  6121. --*/
  6122. {
  6123. DWORD d;
  6124. HINF hInf = INVALID_HANDLE_VALUE;
  6125. MYASSERT((DifferentName && OriginalName && OriginalNameSize) ||
  6126. !(DifferentName || OriginalName || OriginalNameSize));
  6127. MYASSERT((OriginalCatalogName && OriginalCatalogNameSize) ||
  6128. !(OriginalCatalogName || OriginalCatalogNameSize));
  6129. MYASSERT(Inf || CurrentName);
  6130. if(DifferentName) {
  6131. *DifferentName = FALSE;
  6132. }
  6133. if(!Inf) {
  6134. //
  6135. // Open the INF.
  6136. //
  6137. hInf = SetupOpenInfFile(CurrentName,
  6138. NULL,
  6139. INF_STYLE_OLDNT | INF_STYLE_WIN4,
  6140. NULL
  6141. );
  6142. if(hInf == INVALID_HANDLE_VALUE) {
  6143. return GetLastError();
  6144. }
  6145. //
  6146. // We don't need to lock the INF because it'll never be accessible
  6147. // outside of this routine.
  6148. //
  6149. Inf = (PLOADED_INF)hInf;
  6150. }
  6151. //
  6152. // Enclose in try/except in case we hit an inpage error while using this
  6153. // memory-mapped image.
  6154. //
  6155. d = NO_ERROR;
  6156. try {
  6157. if(DifferentName) {
  6158. if(Inf->OriginalInfName) {
  6159. lstrcpyn(OriginalName, Inf->OriginalInfName, OriginalNameSize);
  6160. *DifferentName = TRUE;
  6161. }
  6162. }
  6163. if(OriginalCatalogName) {
  6164. if(!pSetupGetCatalogFileValue(&(Inf->VersionBlock),
  6165. OriginalCatalogName,
  6166. OriginalCatalogNameSize,
  6167. AltPlatformInfo)) {
  6168. //
  6169. // The INF didn't specify an associated catalog file
  6170. //
  6171. *OriginalCatalogName = TEXT('\0');
  6172. }
  6173. }
  6174. } except(EXCEPTION_EXECUTE_HANDLER) {
  6175. //
  6176. // If we hit an AV, then use invalid parameter error, otherwise, assume
  6177. // an inpage error when dealing with a mapped-in file.
  6178. //
  6179. d = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  6180. }
  6181. if(hInf != INVALID_HANDLE_VALUE) {
  6182. SetupCloseInfFile(hInf);
  6183. }
  6184. return d;
  6185. }
  6186. PSECURITY_DESCRIPTOR
  6187. pSetupConvertTextToSD(
  6188. IN PCWSTR SDS,
  6189. OUT PULONG SecDescSize
  6190. )
  6191. /*++
  6192. Routine Description:
  6193. Helper for cfgmgr.lib
  6194. Obtains a binary security descriptor from an SDS
  6195. Resulting buffer must be free'd using LocalFree (not MyFree)
  6196. returns NULL if not supported and sets last error
  6197. Arguments:
  6198. SDS - string to obtain security descriptor from
  6199. SecDescSize - filled in with size of security descriptor
  6200. Return Value:
  6201. returns security descriptor (use LocalFree to release)
  6202. or NULL with GetLastError indicating error
  6203. --*/
  6204. {
  6205. SCESTATUS status;
  6206. PSECURITY_DESCRIPTOR pSD = NULL;
  6207. ULONG ulSDSize;
  6208. SECURITY_INFORMATION siSeInfo;
  6209. //
  6210. // If we're in "Disable SCE" mode on embedded, don't do security stuff...
  6211. //
  6212. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  6213. SetLastError(ERROR_SCE_DISABLED);
  6214. return NULL;
  6215. }
  6216. try {
  6217. status = SceSvcConvertTextToSD((PWSTR)SDS,&pSD,&ulSDSize,&siSeInfo);
  6218. switch (status ) {
  6219. case SCESTATUS_SUCCESS:
  6220. MYASSERT(pSD);
  6221. MYASSERT(ulSDSize);
  6222. if (SecDescSize) {
  6223. *SecDescSize = ulSDSize;
  6224. }
  6225. SetLastError(NO_ERROR);
  6226. break;
  6227. case SCESTATUS_INVALID_PARAMETER:
  6228. SetLastError(ERROR_INVALID_PARAMETER);
  6229. pSD = NULL;
  6230. break;
  6231. case SCESTATUS_NOT_ENOUGH_RESOURCE:
  6232. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  6233. pSD = NULL;
  6234. break;
  6235. case SCESTATUS_RECORD_NOT_FOUND:
  6236. default:
  6237. SetLastError(ERROR_INVALID_DATA);
  6238. pSD = NULL;
  6239. }
  6240. } except(EXCEPTION_EXECUTE_HANDLER) {
  6241. //
  6242. // If we hit an AV, then use invalid parameter error, otherwise, assume
  6243. // an inpage error when dealing with a mapped-in file.
  6244. //
  6245. SetLastError(ERROR_INVALID_DATA);
  6246. pSD = NULL;
  6247. }
  6248. return pSD;
  6249. }
  6250. PWSTR
  6251. pSetupConvertSDToText(
  6252. IN PSECURITY_DESCRIPTOR SD,
  6253. OUT PULONG pSDSSize
  6254. )
  6255. /*++
  6256. Routine Description:
  6257. Helper for cfgmgr.lib
  6258. Obtains an SDS from a binary security descriptor
  6259. Resulting buffer must be free'd using LocalFree (not MyFree)
  6260. returns NULL if not supported and sets last error
  6261. Arguments:
  6262. SD - security descriptor to convert to a string
  6263. pSDSSize - return size of string
  6264. Return Value:
  6265. returns security descriptor string (use LocalFree to release)
  6266. or NULL with GetLastError indicating error
  6267. --*/
  6268. {
  6269. HINSTANCE Dll_Handle;
  6270. FARPROC SceFileProc;
  6271. SCESTATUS status;
  6272. DWORD LoadStatus;
  6273. SECURITY_INFORMATION securityInformation = 0;
  6274. PSID sid;
  6275. PACL acl;
  6276. BOOLEAN tmp,present;
  6277. LPWSTR SDS = NULL;
  6278. ULONG ulSSDSize;
  6279. SECURITY_INFORMATION siSeInfo;
  6280. //
  6281. // If we're in "Disable SCE" mode on embedded, don't do security stuff...
  6282. //
  6283. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  6284. //
  6285. // Report an empty string
  6286. //
  6287. return LocalAlloc(LPTR, sizeof(WCHAR)); // LPTR zeroes out the char
  6288. }
  6289. try {
  6290. //
  6291. // find out what relevent information is in the descriptor
  6292. // up a securityInformation block to go with it.
  6293. //
  6294. status = RtlGetOwnerSecurityDescriptor(SD, &sid, &tmp);
  6295. if(NT_SUCCESS(status) && (sid != NULL)) {
  6296. securityInformation |= OWNER_SECURITY_INFORMATION;
  6297. }
  6298. status = RtlGetGroupSecurityDescriptor(SD, &sid, &tmp);
  6299. if(NT_SUCCESS(status) && (sid != NULL)) {
  6300. securityInformation |= GROUP_SECURITY_INFORMATION;
  6301. }
  6302. status = RtlGetSaclSecurityDescriptor(SD,
  6303. &present,
  6304. &acl,
  6305. &tmp);
  6306. if(NT_SUCCESS(status) && (present)) {
  6307. securityInformation |= SACL_SECURITY_INFORMATION;
  6308. }
  6309. status = RtlGetDaclSecurityDescriptor(SD,
  6310. &present,
  6311. &acl,
  6312. &tmp);
  6313. if(NT_SUCCESS(status) && (present)) {
  6314. securityInformation |= DACL_SECURITY_INFORMATION;
  6315. }
  6316. //
  6317. // now obtain an SDS
  6318. //
  6319. status = SceSvcConvertSDToText(SD,securityInformation,&SDS,&ulSSDSize);
  6320. switch (status ) {
  6321. case SCESTATUS_SUCCESS:
  6322. MYASSERT(SDS);
  6323. MYASSERT(ulSSDSize);
  6324. if(pSDSSize != NULL) {
  6325. *pSDSSize = ulSSDSize;
  6326. }
  6327. SetLastError(NO_ERROR);
  6328. break;
  6329. case SCESTATUS_INVALID_PARAMETER:
  6330. SetLastError(ERROR_INVALID_PARAMETER);
  6331. SDS = NULL;
  6332. break;
  6333. case SCESTATUS_NOT_ENOUGH_RESOURCE:
  6334. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  6335. SDS = NULL;
  6336. break;
  6337. case SCESTATUS_RECORD_NOT_FOUND:
  6338. default:
  6339. SetLastError(ERROR_INVALID_DATA);
  6340. SDS = NULL;
  6341. }
  6342. } except(EXCEPTION_EXECUTE_HANDLER) {
  6343. if (SDS) {
  6344. LocalFree(SDS);
  6345. }
  6346. SetLastError(ERROR_INVALID_DATA);
  6347. SDS = NULL;
  6348. }
  6349. return SDS;
  6350. }
  6351. DWORD
  6352. pSetupCallSCE(
  6353. IN DWORD Operation,
  6354. IN PCWSTR FullName,
  6355. IN PSP_FILE_QUEUE Queue,
  6356. IN PCWSTR String1,
  6357. IN DWORD Index1,
  6358. IN PSECURITY_DESCRIPTOR SecDesc OPTIONAL
  6359. )
  6360. /*
  6361. Operation ST_SCE_SET : - Sets security on a File in File Queue and informs SCE database
  6362. FullName : - Filename (Needed)
  6363. Queue : - Pointer to FileQueue (Needed)
  6364. Index : - Index in String Table of Queue (Needed)
  6365. Operation ST_SCE_RENAME : - Sets security on a File in File Queue and informs SCE database to
  6366. record it for the filename mentioned in String1
  6367. FullName : - Filename (Needed)
  6368. Queue : - Pointer to FileQueue (Needed)
  6369. String1 ; - Filename to record in Database (Needed)
  6370. Index : - Index in String Table of Queue (Optional - only if it needs to be set otherwise -1)
  6371. Operation ST_SCE_DELETE : - Removes record of file in SCE database
  6372. FullName : - Filename (Needed)
  6373. Operation ST_SCE_UNWIND : - Used for Backup Unwinds when we reset the security on a dirty file
  6374. FullName : - Filename (Needed)
  6375. SecDesc : - Pointer to Security Descriptor for the original file that we unwind (Needed)
  6376. Operation ST_SCE_SERVICES : - Sets security on a Service and informs SCE database
  6377. FullName : - Service Name (Needed)
  6378. Index : - Service Style (Needed)
  6379. String1 ; - Security Descriptor string
  6380. Operation ST_SCE_SDS_TO_BIN : - Sets security on a Service and informs SCE database
  6381. FullName : - Service Name (Needed)
  6382. Index : - Service Style (Needed)
  6383. String1 ; - Security Descriptor string
  6384. In each case, return value is error or NO_ERROR
  6385. */
  6386. {
  6387. FARPROC SceFileProc;
  6388. PCWSTR SecurityDescriptor;
  6389. HINSTANCE Dll_Handle;
  6390. DWORD ret, LoadStatus;
  6391. //
  6392. // If we're in "Disable SCE" mode on embedded, don't do security stuff...
  6393. //
  6394. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  6395. return NO_ERROR;
  6396. }
  6397. try {
  6398. switch (Operation) {
  6399. case ST_SCE_SET:
  6400. //Get the Security descriptor from the String table of the node
  6401. if( Index1 != -1 ){
  6402. SecurityDescriptor = pSetupStringTableStringFromId( Queue->StringTable, Index1 );
  6403. if(!SecurityDescriptor) {
  6404. ret= NO_ERROR;
  6405. break;
  6406. }
  6407. }
  6408. else {
  6409. ret = NO_ERROR;
  6410. break;
  6411. }
  6412. ret = SceSetupUpdateSecurityFile((PWSTR)FullName, 0, (PWSTR)SecurityDescriptor );
  6413. break;
  6414. case ST_SCE_RENAME:
  6415. if( Index1 != -1 ) {
  6416. SecurityDescriptor = pSetupStringTableStringFromId( Queue->StringTable, Index1 );
  6417. } else {
  6418. SecurityDescriptor = NULL;
  6419. }
  6420. ret = SceSetupMoveSecurityFile( (PWSTR)FullName, (PWSTR)String1, (PWSTR)SecurityDescriptor );
  6421. break;
  6422. case ST_SCE_DELETE:
  6423. ret = SceSetupMoveSecurityFile( (PWSTR)FullName, NULL, NULL );
  6424. break;
  6425. case ST_SCE_UNWIND:
  6426. ret = SceSetupUnwindSecurityFile( (PWSTR)FullName, SecDesc );
  6427. break;
  6428. case ST_SCE_SERVICES:
  6429. if( String1 == NULL ){
  6430. ret = NO_ERROR;
  6431. } else {
  6432. ret = SceSetupUpdateSecurityService( (PWSTR)FullName, Index1, (PWSTR)String1 );
  6433. }
  6434. break;
  6435. default:
  6436. MYASSERT(0);
  6437. ret = ERROR_INVALID_DATA;
  6438. }
  6439. } except(EXCEPTION_EXECUTE_HANDLER) {
  6440. ret = ERROR_INVALID_DATA;
  6441. }
  6442. return ret;
  6443. }
  6444. VOID
  6445. RestoreBootReplacedFile(
  6446. IN PSP_FILE_QUEUE Queue,
  6447. IN PSP_FILE_QUEUE_NODE QueueNode
  6448. )
  6449. /*++
  6450. Routine Description:
  6451. This routine restores a file that was renamed in preparation for a bootfile
  6452. installation.
  6453. Arguments:
  6454. Queue - queue that contains the bootfile copy operation
  6455. QueueNode - bootfile copy operation being aborted
  6456. Return Value:
  6457. None.
  6458. --*/
  6459. {
  6460. DWORD rc;
  6461. LONG TargetID;
  6462. SP_TARGET_ENT TargetInfo;
  6463. PCTSTR TargetFilename, RenamedFilename;
  6464. BOOL UnPostSucceeded;
  6465. //
  6466. // First, we need to find the corresponding target info node so
  6467. // we can find out what temporary name our file was renamed to.
  6468. //
  6469. rc = pSetupBackupGetTargetByPath((HSPFILEQ)Queue,
  6470. NULL, // use Queue's string table
  6471. NULL,
  6472. QueueNode->TargetDirectory,
  6473. -1,
  6474. QueueNode->TargetFilename,
  6475. &TargetID,
  6476. &TargetInfo
  6477. );
  6478. if(rc == NO_ERROR) {
  6479. //
  6480. // Has the file previously been renamed (and not yet
  6481. // restored)?
  6482. //
  6483. if((TargetInfo.InternalFlags & (SP_TEFLG_MOVED | SP_TEFLG_RESTORED)) == SP_TEFLG_MOVED) {
  6484. TargetFilename = pSetupFormFullPath(
  6485. Queue->StringTable,
  6486. TargetInfo.TargetRoot,
  6487. TargetInfo.TargetSubDir,
  6488. TargetInfo.TargetFilename
  6489. );
  6490. MYASSERT(TargetFilename);
  6491. RenamedFilename = pSetupStringTableStringFromId(
  6492. Queue->StringTable,
  6493. TargetInfo.NewTargetFilename
  6494. );
  6495. MYASSERT(RenamedFilename);
  6496. //
  6497. // Move the renamed file back to its original name.
  6498. //
  6499. RestoreRenamedOrBackedUpFile(TargetFilename,
  6500. RenamedFilename,
  6501. TRUE,
  6502. Queue->LogContext
  6503. );
  6504. //
  6505. // Set the flag indicating that this file has been
  6506. // restored, and save this info.
  6507. //
  6508. TargetInfo.InternalFlags |= SP_TEFLG_RESTORED;
  6509. pSetupBackupSetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo);
  6510. //
  6511. // Finally, get rid of the delayed-move node that was to
  6512. // delete the renamed file upon reboot.
  6513. //
  6514. UnPostSucceeded = UnPostDelayedMove(Queue,
  6515. RenamedFilename,
  6516. NULL
  6517. );
  6518. MYASSERT(UnPostSucceeded);
  6519. }
  6520. }
  6521. }
  6522. VOID
  6523. pSetupExemptFileFromProtection(
  6524. IN PCTSTR FileName,
  6525. IN DWORD FileChangeFlags,
  6526. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  6527. OUT PDWORD QueueNodeFlags OPTIONAL
  6528. )
  6529. /*++
  6530. Routine Description:
  6531. This routine checks to see if the specified file is a protected system
  6532. file, and if so, it tells SFC to make a replacement exception for this file.
  6533. Arguments:
  6534. FileName - Supplies the name of the file for which an exception is being
  6535. requested.
  6536. FileChangeFlags - Supplies the flags to be passed to SfcFileException, if
  6537. this file is determined to be under the protection of SFP.
  6538. LogContext - Optionally, supplies the log context to be used when logging
  6539. information resulting from this request.
  6540. QueueNodeFlags - Optionally, supplies the address of a variable that
  6541. receives one or more of the following queue node flags indicating
  6542. whether the specified file is a protected system file, and whether an
  6543. exception was granted for its replacement:
  6544. IQF_TARGET_PROTECTED - File is a protected system file.
  6545. IQF_ALLOW_UNSIGNED - An exception has been granted so that the file
  6546. may be replaced by an unsigned file.
  6547. Return Value:
  6548. None.
  6549. --*/
  6550. {
  6551. HANDLE hSfp;
  6552. PSETUP_LOG_CONTEXT lc = NULL;
  6553. DWORD Result = NO_ERROR;
  6554. if(QueueNodeFlags) {
  6555. *QueueNodeFlags = 0;
  6556. }
  6557. //
  6558. // If the caller didn't supply us with a LogContext, then create our own.
  6559. // We want to do this so that all log entries generated herein will end up
  6560. // in the same section.
  6561. //
  6562. if(!LogContext) {
  6563. if(CreateLogContext(NULL, TRUE, &lc) == NO_ERROR) {
  6564. //
  6565. // success
  6566. //
  6567. LogContext = lc;
  6568. } else {
  6569. lc = NULL;
  6570. }
  6571. }
  6572. if(IsFileProtected(FileName, LogContext, &hSfp)) {
  6573. if(QueueNodeFlags) {
  6574. *QueueNodeFlags = IQF_TARGET_PROTECTED;
  6575. }
  6576. Result = SfcFileException(hSfp,
  6577. (PWSTR)FileName,
  6578. FileChangeFlags
  6579. );
  6580. if(Result == NO_ERROR) {
  6581. WriteLogEntry(
  6582. LogContext,
  6583. SETUP_LOG_ERROR,
  6584. MSG_LOG_SFC_EXEMPT_SUCCESS,
  6585. NULL,
  6586. FileName);
  6587. if(QueueNodeFlags) {
  6588. *QueueNodeFlags |= IQF_ALLOW_UNSIGNED;
  6589. }
  6590. } else {
  6591. WriteLogEntry(
  6592. LogContext,
  6593. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  6594. MSG_LOG_SFC_EXEMPT_FAIL,
  6595. NULL,
  6596. FileName);
  6597. WriteLogError(
  6598. LogContext,
  6599. SETUP_LOG_ERROR,
  6600. Result);
  6601. }
  6602. SfcClose(hSfp);
  6603. //
  6604. // If we created our own local LogContext, we can free it now.
  6605. //
  6606. if(lc) {
  6607. DeleteLogContext(lc);
  6608. }
  6609. }
  6610. }
  6611. BOOL
  6612. pSetupProtectedRenamesFlag(
  6613. BOOL bSet
  6614. )
  6615. {
  6616. HKEY hKey;
  6617. long rslt = ERROR_SUCCESS;
  6618. if (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  6619. return(TRUE);
  6620. }
  6621. rslt = RegOpenKeyEx(
  6622. HKEY_LOCAL_MACHINE,
  6623. TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
  6624. 0,
  6625. KEY_SET_VALUE,
  6626. &hKey);
  6627. if (rslt == ERROR_SUCCESS) {
  6628. DWORD Value = bSet ? 1 : 0;
  6629. rslt = RegSetValueEx(
  6630. hKey,
  6631. TEXT("AllowProtectedRenames"),
  6632. 0,
  6633. REG_DWORD,
  6634. (LPBYTE)&Value,
  6635. sizeof(DWORD));
  6636. RegCloseKey(hKey);
  6637. if (rslt != ERROR_SUCCESS) {
  6638. DebugPrintEx( DPFLTR_ERROR_LEVEL, TEXT("couldn't RegSetValueEx, ec = %d\n"), rslt );
  6639. }
  6640. } else {
  6641. DebugPrintEx( DPFLTR_ERROR_LEVEL, TEXT("couldn't RegOpenKeyEx, ec = %d\n"), rslt );
  6642. }
  6643. return(rslt == ERROR_SUCCESS);
  6644. }
  6645. VOID
  6646. pSetupUninstallNewCatalogNodes(
  6647. IN PSP_FILE_QUEUE Queue,
  6648. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  6649. )
  6650. /*++
  6651. Routine Description:
  6652. This routine uninstalls any newly-copied INFs/PNFs/CATs contained in the
  6653. specified linked list of catalog nodes.
  6654. Arguments:
  6655. Queue - Supplies a pointer to the file queue (potentially) containing
  6656. newly-copied catalog nodes to be uninstalled.
  6657. Return Value:
  6658. None.
  6659. --*/
  6660. {
  6661. PSPQ_CATALOG_INFO CatalogNode;
  6662. PTSTR InfToUninstall;
  6663. BOOL Locked = FALSE;
  6664. try {
  6665. if(!_pSpUtilsStringTableLock(Queue->StringTable)) {
  6666. leave;
  6667. }
  6668. Locked = TRUE;
  6669. for(CatalogNode = Queue->CatalogList;
  6670. CatalogNode;
  6671. CatalogNode = CatalogNode->Next) {
  6672. if(CatalogNode->Flags & CATINFO_FLAG_NEWLY_COPIED) {
  6673. InfToUninstall = _pSpUtilsStringTableStringFromId(
  6674. Queue->StringTable,
  6675. CatalogNode->InfFinalPath
  6676. );
  6677. MYASSERT(InfToUninstall);
  6678. if(InfToUninstall) {
  6679. pSetupUninstallOEMInf(InfToUninstall, LogContext, SUOI_FORCEDELETE, NULL);
  6680. }
  6681. }
  6682. }
  6683. } except(EXCEPTION_EXECUTE_HANDLER) {
  6684. //
  6685. // Reference the following variable so the compiler will respect
  6686. // statement ordering w.r.t. its assignment.
  6687. //
  6688. Locked = Locked;
  6689. }
  6690. if(Locked) {
  6691. _pSpUtilsStringTableUnlock(Queue->StringTable);
  6692. }
  6693. }
  6694. BOOL
  6695. WINAPI
  6696. SetupUninstallNewlyCopiedInfs(
  6697. IN HSPFILEQ QueueHandle,
  6698. IN DWORD Flags,
  6699. IN PVOID Reserved
  6700. )
  6701. /*++
  6702. Routine Description:
  6703. This API uninstalls any INFs (and their associated PNFs and CATs) that
  6704. were previously installed during committal of the specified file queue.
  6705. Arguments:
  6706. QueueHandle - Supplies a handle to a committed file queue (potentially)
  6707. containing newly-copied INFs to be uninstalled.
  6708. Flags - Supplies flags that alter the behavior of this API. Presently, no
  6709. flags are defined. This parameter must be zero.
  6710. Reserved - Reserved for future use. This parameter must be NULL.
  6711. Return Value:
  6712. If all the parameters were valid, the return value is non-zero (TRUE). Note
  6713. that this does _not_ necessarily mean that any newly-copied INFs were
  6714. uninstalled.
  6715. If there was a problem with the parameters passed in, the return value is
  6716. FALSE, and GetLastError provides more information on the problem.
  6717. --*/
  6718. {
  6719. PSP_FILE_QUEUE Queue;
  6720. BOOL Success;
  6721. PSETUP_LOG_CONTEXT LogContext;
  6722. if(Flags) {
  6723. SetLastError(ERROR_INVALID_FLAGS);
  6724. return FALSE;
  6725. }
  6726. if(Reserved) {
  6727. SetLastError(ERROR_INVALID_PARAMETER);
  6728. return FALSE;
  6729. }
  6730. //
  6731. // Queue handle is actually a pointer to the queue structure.
  6732. //
  6733. Queue = (PSP_FILE_QUEUE)QueueHandle;
  6734. //
  6735. // do a quick handle validation before anything else
  6736. //
  6737. try {
  6738. Success = ((Queue != NULL) && (Queue != INVALID_HANDLE_VALUE) && (Queue->Signature == SP_FILE_QUEUE_SIG));
  6739. if(Success) {
  6740. LogContext = Queue->LogContext;
  6741. }
  6742. } except(EXCEPTION_EXECUTE_HANDLER) {
  6743. Success = FALSE;
  6744. }
  6745. if(!Success) {
  6746. SetLastError(ERROR_INVALID_HANDLE);
  6747. return FALSE;
  6748. }
  6749. pSetupUninstallNewCatalogNodes(Queue, LogContext);
  6750. return TRUE;
  6751. }