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.

7116 lines
256 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. fileutil.c
  5. Abstract:
  6. File-related functions for Windows NT Setup API dll.
  7. Author:
  8. Ted Miller (tedm) 11-Jan-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <ntverp.h>
  14. //
  15. // This guid is used for file signing/verification.
  16. //
  17. GUID DriverVerifyGuid = DRIVER_ACTION_VERIFY;
  18. GUID AuthenticodeVerifyGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  19. //
  20. // Instantiate exception class GUID.
  21. //
  22. #include <initguid.h>
  23. DEFINE_GUID( GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER, 0xF5776D81L, 0xAE53, 0x4935, 0x8E, 0x84, 0xB0, 0xB2, 0x83, 0xD8, 0xBC, 0xEF );
  24. // Bit 0 indicates policy for filters (0 = critical, 1 = non-critical)
  25. #define DDB_DRIVER_POLICY_CRITICAL_BIT (1 << 0)
  26. // Bit 1 indicates policy for user-mode setup blocking (0 = block, 1 = no-block)
  27. #define DDB_DRIVER_POLICY_SETUP_NO_BLOCK_BIT (1 << 1)
  28. #define MIN_HASH_LEN 16
  29. #define MAX_HASH_LEN 20
  30. //
  31. // Global list of device setup classes subject to driver signing policy, along
  32. // with validation platform overrides (where applicable).
  33. //
  34. DRVSIGN_POLICY_LIST GlobalDrvSignPolicyList;
  35. //
  36. // private function prototypes
  37. //
  38. BOOL
  39. ClassGuidInDrvSignPolicyList(
  40. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  41. IN CONST GUID *DeviceSetupClassGuid, OPTIONAL
  42. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform OPTIONAL
  43. );
  44. DWORD
  45. _VerifyCatalogFile(
  46. IN PSETUP_LOG_CONTEXT LogContext,
  47. IN LPCTSTR CatalogFullPath,
  48. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  49. IN BOOL UseAuthenticodePolicy,
  50. IN OUT HCERTSTORE *hStoreTrustedPublisher, OPTIONAL
  51. OUT HANDLE *hWVTStateData OPTIONAL
  52. );
  53. BOOL
  54. pSetupIsAuthenticodePublisherTrusted(
  55. IN PCCERT_CONTEXT pcSignerCertContext,
  56. IN OUT HCERTSTORE *hStoreTrustedPublisher OPTIONAL
  57. );
  58. BOOL
  59. IsAutoCertInstallAllowed(
  60. VOID
  61. );
  62. DWORD
  63. pSetupInstallCertificate(
  64. IN PCCERT_CONTEXT pcSignerCertContext
  65. );
  66. //
  67. // helper to determine log level to use
  68. //
  69. __inline
  70. DWORD
  71. GetCatLogLevel(
  72. IN DWORD Err,
  73. IN BOOL DriverLevel
  74. )
  75. {
  76. switch(Err) {
  77. case ERROR_FILE_NOT_FOUND:
  78. case ERROR_PATH_NOT_FOUND:
  79. case E_NOTIMPL:
  80. return (DriverLevel ? DRIVER_LOG_VVERBOSE : SETUP_LOG_VVERBOSE);
  81. default:
  82. return (DriverLevel ? DRIVER_LOG_INFO : SETUP_LOG_INFO);
  83. }
  84. }
  85. DWORD
  86. ReadAsciiOrUnicodeTextFile(
  87. IN HANDLE FileHandle,
  88. OUT PTEXTFILE_READ_BUFFER Result,
  89. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  90. )
  91. /*++
  92. Routine Description:
  93. Read in a text file that may be in either ascii or unicode format.
  94. If the file is ascii, it is assumed to be ANSI format and is converted
  95. to Unicode.
  96. Arguments:
  97. FileHandle - Supplies the handle of the text file to be read.
  98. Result - supplies the address of a TEXTFILE_READ_BUFFER structure that
  99. receives information about the text file buffer read. The structure
  100. is defined as follows:
  101. typedef struct _TEXTFILE_READ_BUFFER {
  102. PCTSTR TextBuffer;
  103. DWORD TextBufferSize;
  104. HANDLE FileHandle;
  105. HANDLE MappingHandle;
  106. PVOID ViewAddress;
  107. } TEXTFILE_READ_BUFFER, *PTEXTFILE_READ_BUFFER;
  108. TextBuffer - pointer to the read-only character string containing
  109. the entire text of the file.
  110. (NOTE: If the file is a Unicode file with a Byte Order Mark
  111. prefix, this Unicode character is not included in the returned
  112. buffer.)
  113. TextBufferSize - size of the TextBuffer (in characters).
  114. FileHandle - If this is a valid handle (i.e., it's not equal to
  115. INVALID_HANDLE_VALUE), then the file was already the native
  116. character type, so the TextBuffer is simply the mapped-in image
  117. of the file. This field is reserved for use by the
  118. DestroyTextFileReadBuffer routine, and should not be accessed.
  119. MappingHandle - If FileHandle is valid, then this contains the
  120. mapping handle for the file image mapping.
  121. This field is reserved for use by the DestroyTextFileReadBuffer
  122. routine, and should not be accessed.
  123. ViewAddress - If FileHandle is valid, then this contains the
  124. starting memory address where the file image was mapped in.
  125. This field is reserved for use by the DestroyTextFileReadBuffer
  126. routine, and should not be accessed.
  127. LogContext - for logging of errors/tracing
  128. Return Value:
  129. Win32 error value indicating the outcome.
  130. Remarks:
  131. Upon return from this routine, the caller MUST NOT attempt to close
  132. FileHandle. This routine with either close the handle itself (after it's
  133. finished with it, or upon error), or it will store the handle away in the
  134. TEXTFILE_READ_BUFFER struct, to be later closed via
  135. DestroyTextFileReadBuffer().
  136. --*/
  137. {
  138. DWORD rc;
  139. DWORD FileSize;
  140. HANDLE MappingHandle;
  141. PVOID ViewAddress, TextStartAddress;
  142. BOOL IsNativeChar;
  143. UINT SysCodePage = CP_ACP;
  144. //
  145. // Map the file for read access.
  146. //
  147. rc = pSetupMapFileForRead(
  148. FileHandle,
  149. &FileSize,
  150. &MappingHandle,
  151. &ViewAddress
  152. );
  153. if(rc != NO_ERROR) {
  154. //
  155. // We couldn't map the file--close the file handle now.
  156. //
  157. CloseHandle(FileHandle);
  158. } else {
  159. //
  160. // Determine whether the file is unicode. Guard with try/except in
  161. // case we get an inpage error.
  162. //
  163. try {
  164. //
  165. // Check to see if the file starts with a Unicode Byte Order Mark
  166. // (BOM) character (0xFEFF). If so, then we know that the file
  167. // is Unicode, and don't have to go through the slow process of
  168. // trying to figure it out.
  169. //
  170. TextStartAddress = ViewAddress;
  171. if((FileSize >= sizeof(WCHAR)) && (*(PWCHAR)TextStartAddress == 0xFEFF)) {
  172. //
  173. // The file has the BOM prefix. Adjust the pointer to the
  174. // start of the text, so that we don't include the marker
  175. // in the text buffer we return.
  176. //
  177. IsNativeChar = TRUE;
  178. ((PWCHAR)TextStartAddress)++;
  179. FileSize -= sizeof(WCHAR);
  180. } else {
  181. IsNativeChar = IsTextUnicode(TextStartAddress,FileSize,NULL);
  182. }
  183. } except(pSetupExceptionFilter(GetExceptionCode())) {
  184. pSetupExceptionHandler(GetExceptionCode(), ERROR_READ_FAULT, &rc);
  185. }
  186. if(rc == NO_ERROR) {
  187. if(IsNativeChar) {
  188. //
  189. // No conversion is required--we'll just use the mapped-in
  190. // image in memory.
  191. //
  192. Result->TextBuffer = TextStartAddress;
  193. Result->TextBufferSize = FileSize / sizeof(TCHAR);
  194. Result->FileHandle = FileHandle;
  195. Result->MappingHandle = MappingHandle;
  196. Result->ViewAddress = ViewAddress;
  197. } else {
  198. DWORD NativeCharCount;
  199. PTCHAR Buffer;
  200. //
  201. // Need to convert the file to the native character type.
  202. // Allocate a buffer that is maximally sized.
  203. // The maximum size of the unicode text is
  204. // double the size of the oem text, and would occur
  205. // when each oem character is single-byte.
  206. //
  207. if(Buffer = MyMalloc(FileSize * sizeof(TCHAR))) {
  208. try {
  209. //
  210. // FUTURE-1999/09/01-JamieHun -- Implement ANSI Inf Language=xxxx
  211. // Need to come up with a better way of determining
  212. // what code-page to interpret INF file under.
  213. // Currently we use the install-base.
  214. //
  215. SysCodePage = CP_ACP;
  216. rc = GLE_FN_CALL(0,
  217. NativeCharCount = MultiByteToWideChar(
  218. SysCodePage,
  219. MB_PRECOMPOSED,
  220. TextStartAddress,
  221. FileSize,
  222. Buffer,
  223. FileSize)
  224. );
  225. } except(pSetupExceptionFilter(GetExceptionCode())) {
  226. pSetupExceptionHandler(GetExceptionCode(),
  227. ERROR_READ_FAULT,
  228. &rc
  229. );
  230. }
  231. } else {
  232. rc = ERROR_NOT_ENOUGH_MEMORY;
  233. }
  234. if(rc == NO_ERROR) {
  235. //
  236. // If the converted buffer doesn't require the entire block
  237. // we allocated, attempt to reallocate the buffer to its
  238. // correct size. We don't care if this fails, since the
  239. // buffer we have is perfectly fine (just bigger than we
  240. // need).
  241. //
  242. if(!(Result->TextBuffer = MyRealloc(Buffer, NativeCharCount * sizeof(TCHAR)))) {
  243. Result->TextBuffer = Buffer;
  244. }
  245. Result->TextBufferSize = NativeCharCount;
  246. Result->FileHandle = INVALID_HANDLE_VALUE;
  247. } else {
  248. //
  249. // Free the buffer, if it was previously allocated.
  250. //
  251. if(Buffer) {
  252. MyFree(Buffer);
  253. }
  254. }
  255. }
  256. }
  257. //
  258. // If the file was already in native character form and we didn't
  259. // enounter any errors, then we don't want to close it, because we
  260. // use the mapped-in view directly.
  261. //
  262. if((rc != NO_ERROR) || !IsNativeChar) {
  263. pSetupUnmapAndCloseFile(FileHandle, MappingHandle, ViewAddress);
  264. }
  265. }
  266. return rc;
  267. }
  268. BOOL
  269. DestroyTextFileReadBuffer(
  270. IN PTEXTFILE_READ_BUFFER ReadBuffer
  271. )
  272. /*++
  273. Routine Description:
  274. Destroy a textfile read buffer created by ReadAsciiOrUnicodeTextFile.
  275. Arguments:
  276. ReadBuffer - supplies the address of a TEXTFILE_READ_BUFFER structure
  277. for the buffer to be destroyed.
  278. Return Value:
  279. BOOLean value indicating success or failure.
  280. --*/
  281. {
  282. //
  283. // If our ReadBuffer structure has a valid FileHandle, then we must
  284. // unmap and close the file, otherwise, we simply need to free the
  285. // allocated buffer.
  286. //
  287. if(ReadBuffer->FileHandle != INVALID_HANDLE_VALUE) {
  288. return pSetupUnmapAndCloseFile(ReadBuffer->FileHandle,
  289. ReadBuffer->MappingHandle,
  290. ReadBuffer->ViewAddress
  291. );
  292. } else {
  293. MyFree(ReadBuffer->TextBuffer);
  294. return TRUE;
  295. }
  296. }
  297. BOOL
  298. GetVersionInfoFromImage(
  299. IN PCTSTR FileName,
  300. OUT PDWORDLONG Version,
  301. OUT LANGID *Language
  302. )
  303. /*++
  304. Routine Description:
  305. Retrieve file version and language info from a file.
  306. The version is specified in the dwFileVersionMS and dwFileVersionLS fields
  307. of a VS_FIXEDFILEINFO, as filled in by the win32 version APIs. For the
  308. language we look at the translation table in the version resources and
  309. assume that the first langid/codepage pair specifies the language.
  310. If the file is not a coff image or does not have version resources,
  311. the function fails. The function does not fail if we are able to retrieve
  312. the version but not the language.
  313. Arguments:
  314. FileName - supplies the full path of the file whose version data is desired.
  315. Version - receives the version stamp of the file. If the file is not a coff
  316. image or does not contain the appropriate version resource data, the
  317. function fails.
  318. Language - receives the language id of the file. If the file is not a coff
  319. image or does not contain the appropriate version resource data, this
  320. will be 0 and the function succeeds.
  321. Return Value:
  322. TRUE if we were able to retreive at least the version stamp.
  323. FALSE otherwise.
  324. --*/
  325. {
  326. DWORD d;
  327. PVOID VersionBlock = NULL;
  328. VS_FIXEDFILEINFO *FixedVersionInfo;
  329. UINT DataLength;
  330. BOOL b;
  331. PWORD Translation;
  332. DWORD Ignored;
  333. //
  334. // Assume failure
  335. //
  336. b = FALSE;
  337. try {
  338. //
  339. // Get the size of version info block.
  340. //
  341. d = GetFileVersionInfoSize((PTSTR)FileName, &Ignored);
  342. if(!d) {
  343. leave;
  344. }
  345. //
  346. // Allocate memory block of sufficient size to hold version info block
  347. //
  348. VersionBlock = MyMalloc(d);
  349. if(!VersionBlock) {
  350. leave;
  351. }
  352. //
  353. // Get the version block from the file.
  354. //
  355. if(!GetFileVersionInfo((PTSTR)FileName, 0, d, VersionBlock)) {
  356. leave;
  357. }
  358. //
  359. // Get fixed version info.
  360. //
  361. if(VerQueryValue(VersionBlock,
  362. TEXT("\\"),
  363. &FixedVersionInfo,
  364. &DataLength)) {
  365. //
  366. // If we get here, we declare success, even if there is no
  367. // language.
  368. //
  369. b = TRUE;
  370. //
  371. // Return version to caller.
  372. //
  373. *Version = (((DWORDLONG)FixedVersionInfo->dwFileVersionMS) << 32)
  374. + FixedVersionInfo->dwFileVersionLS;
  375. //
  376. // Attempt to get language of file. We'll simply ask for the
  377. // translation table and use the first language id we find in there
  378. // as *the* language of the file.
  379. //
  380. // The translation table consists of LANGID/Codepage pairs.
  381. //
  382. if(VerQueryValue(VersionBlock,
  383. TEXT("\\VarFileInfo\\Translation"),
  384. &Translation,
  385. &DataLength)
  386. && (DataLength >= (2*sizeof(WORD)))) {
  387. *Language = Translation[0];
  388. } else {
  389. //
  390. // No language
  391. //
  392. *Language = 0;
  393. }
  394. }
  395. } except(pSetupExceptionFilter(GetExceptionCode())) {
  396. pSetupExceptionHandler(GetExceptionCode(), ERROR_READ_FAULT, NULL);
  397. b = FALSE;
  398. }
  399. if(VersionBlock) {
  400. MyFree(VersionBlock);
  401. }
  402. return b;
  403. }
  404. BOOL
  405. pSetupGetVersionInfoFromImage(
  406. IN PCTSTR FileName,
  407. OUT PULARGE_INTEGER Version,
  408. OUT LANGID *Language
  409. )
  410. /*++
  411. Routine Description:
  412. See GetVersionInfoFromImage for description
  413. Semi-public version that uses the more friendly ULARGE_INTEGER
  414. Arguments:
  415. FileName - supplies the full path of the file whose version data is
  416. desired.
  417. Version - receives the version stamp of the file. If the file is not a coff
  418. image or does not contain the appropriate version resource data, the
  419. function fails.
  420. Language - receives the language id of the file. If the file is not a coff
  421. image or does not contain the appropriate version resource data, this
  422. will be 0 and the function succeeds.
  423. Return Value:
  424. TRUE if we were able to retreive at least the version stamp.
  425. FALSE otherwise.
  426. --*/
  427. {
  428. DWORDLONG privateVersion=0;
  429. BOOL result;
  430. result = GetVersionInfoFromImage(FileName, &privateVersion, Language);
  431. if(result && Version) {
  432. Version->QuadPart = privateVersion;
  433. }
  434. return result;
  435. }
  436. BOOL
  437. AddFileTimeSeconds(
  438. IN const FILETIME *Base,
  439. OUT FILETIME *Target,
  440. IN INT Seconds
  441. )
  442. /*++
  443. Routine Description:
  444. Bias the filetime by specified number of seconds
  445. Arguments:
  446. Base - original file time
  447. Target - new file time
  448. Seconds - number of seconds to bias it by
  449. Return Value:
  450. If successful, returns TRUE
  451. If out of bounds, returns FALSE and Target set to be same as Base
  452. --*/
  453. {
  454. ULARGE_INTEGER Fuddle;
  455. //
  456. // bias off FileTimeThen as it's the greater time
  457. //
  458. Fuddle.LowPart = Base->dwLowDateTime;
  459. Fuddle.HighPart = Base->dwHighDateTime;
  460. Fuddle.QuadPart += 10000000i64 * Seconds;
  461. if(Fuddle.HighPart < 0x80000000) {
  462. Target->dwHighDateTime = Fuddle.HighPart;
  463. Target->dwLowDateTime = Fuddle.LowPart;
  464. return TRUE;
  465. } else {
  466. *Target = *Base;
  467. return FALSE;
  468. }
  469. }
  470. DWORD
  471. GetSetFileTimestamp(
  472. IN PCTSTR FileName,
  473. IN OUT FILETIME *CreateTime, OPTIONAL
  474. OUT FILETIME *AccessTime, OPTIONAL
  475. OUT FILETIME *WriteTime, OPTIONAL
  476. IN BOOL Set
  477. )
  478. /*++
  479. Routine Description:
  480. Get or set a file's timestamp values.
  481. Arguments:
  482. FileName - supplies full path of file to get or set timestamps
  483. CreateTime - if specified and the underlying filesystem supports it,
  484. receives the creation time of the file.
  485. AccessTime - if specified and the underlying filesystem supports it,
  486. receives the last access time of the file.
  487. WriteTime - if specified, receives the last write time of the file.
  488. Set - if TRUE, set the file's timestamp(s) to the caller-supplied value(s).
  489. Otherwise, simply retrieve the value(s).
  490. Return Value:
  491. If successful, returns NO_ERROR, otherwise returns the Win32 error
  492. indicating the cause of failure.
  493. --*/
  494. {
  495. HANDLE h = INVALID_HANDLE_VALUE;
  496. DWORD d;
  497. try {
  498. d = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  499. h = CreateFile(FileName,
  500. Set ? GENERIC_WRITE : GENERIC_READ,
  501. FILE_SHARE_READ | FILE_SHARE_WRITE,
  502. NULL,
  503. OPEN_EXISTING,
  504. 0,
  505. NULL)
  506. );
  507. if(d != NO_ERROR) {
  508. leave;
  509. }
  510. if(Set) {
  511. d = GLE_FN_CALL(FALSE,
  512. SetFileTime(h, CreateTime, AccessTime, WriteTime)
  513. );
  514. } else {
  515. d = GLE_FN_CALL(FALSE,
  516. GetFileTime(h, CreateTime, AccessTime, WriteTime)
  517. );
  518. }
  519. } except(pSetupExceptionFilter(GetExceptionCode())) {
  520. pSetupExceptionHandler(GetExceptionCode(), ERROR_READ_FAULT, &d);
  521. }
  522. if(h != INVALID_HANDLE_VALUE) {
  523. CloseHandle(h);
  524. }
  525. return d;
  526. }
  527. DWORD
  528. RetreiveFileSecurity(
  529. IN PCTSTR FileName,
  530. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
  531. )
  532. /*++
  533. Routine Description:
  534. Retrieve security information from a file and place it into a buffer.
  535. Arguments:
  536. FileName - supplies name of file whose security information is desired.
  537. SecurityDescriptor - If the function is successful, receives pointer
  538. to buffer containing security information for the file. The pointer
  539. may be NULL, indicating that there is no security information
  540. associated with the file or that the underlying filesystem does not
  541. support file security.
  542. Return Value:
  543. Win32 error code indicating outcome. If NO_ERROR check the value returned
  544. in SecurityDescriptor.
  545. The caller can free the buffer with MyFree() when done with it.
  546. --*/
  547. {
  548. DWORD d;
  549. DWORD BytesRequired;
  550. PSECURITY_DESCRIPTOR p = NULL;
  551. try {
  552. BytesRequired = 1024; // start out with a reasonably-sized buffer
  553. while(NULL != (p = MyMalloc(BytesRequired))) {
  554. //
  555. // Get the security.
  556. //
  557. d = GLE_FN_CALL(FALSE,
  558. GetFileSecurity(
  559. FileName,
  560. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  561. p,
  562. BytesRequired,
  563. &BytesRequired)
  564. );
  565. if(d == NO_ERROR) {
  566. *SecurityDescriptor = p;
  567. p = NULL; // so we won't try to free it later
  568. leave;
  569. }
  570. //
  571. // Return an error code, unless we just need a bigger buffer
  572. //
  573. MyFree(p);
  574. p = NULL;
  575. if(d != ERROR_INSUFFICIENT_BUFFER) {
  576. leave;
  577. }
  578. //
  579. // Otherwise, we'll try again with a bigger buffer
  580. //
  581. }
  582. //
  583. // If we get to here, then we failed due to insufficient memory.
  584. //
  585. d = ERROR_NOT_ENOUGH_MEMORY;
  586. } except(pSetupExceptionFilter(GetExceptionCode())) {
  587. pSetupExceptionHandler(GetExceptionCode(), ERROR_READ_FAULT, &d);
  588. }
  589. if(p) {
  590. MyFree(p);
  591. }
  592. return d;
  593. }
  594. DWORD
  595. StampFileSecurity(
  596. IN PCTSTR FileName,
  597. IN PSECURITY_DESCRIPTOR SecurityInfo
  598. )
  599. /*++
  600. Routine Description:
  601. Set security information on a file.
  602. Arguments:
  603. FileName - supplies name of file whose security information is desired.
  604. SecurityDescriptor - supplies pointer to buffer containing security
  605. information for the file. This buffer should have been returned by a
  606. call to RetreiveFileSecurity. If the underlying filesystem does not
  607. support file security, the function fails.
  608. Return Value:
  609. Win32 error code indicating outcome.
  610. --*/
  611. {
  612. return GLE_FN_CALL(FALSE,
  613. SetFileSecurity(FileName,
  614. (OWNER_SECURITY_INFORMATION
  615. | GROUP_SECURITY_INFORMATION
  616. | DACL_SECURITY_INFORMATION),
  617. SecurityInfo)
  618. );
  619. }
  620. DWORD
  621. TakeOwnershipOfFile(
  622. IN PCTSTR Filename
  623. )
  624. /*++
  625. Routine Description:
  626. Sets the owner of a given file to the default owner specified in
  627. the current process token.
  628. Arguments:
  629. FileName - supplies fully-qualified path of the file of which to take
  630. ownership.
  631. Return Value:
  632. Win32 error code indicating outcome.
  633. --*/
  634. {
  635. SECURITY_DESCRIPTOR SecurityDescriptor;
  636. DWORD Err;
  637. HANDLE Token;
  638. DWORD BytesRequired;
  639. PTOKEN_OWNER OwnerInfo = NULL;
  640. //
  641. // Open the process token.
  642. //
  643. Err = GLE_FN_CALL(FALSE,
  644. OpenProcessToken(GetCurrentProcess(),
  645. TOKEN_QUERY,
  646. &Token)
  647. );
  648. if(Err != NO_ERROR) {
  649. return Err;
  650. }
  651. try {
  652. //
  653. // Get the current process's default owner sid.
  654. //
  655. Err = GLE_FN_CALL(FALSE,
  656. GetTokenInformation(Token,
  657. TokenOwner,
  658. NULL,
  659. 0,
  660. &BytesRequired)
  661. );
  662. MYASSERT(Err != NO_ERROR);
  663. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  664. leave;
  665. }
  666. OwnerInfo = MyMalloc(BytesRequired);
  667. if(!OwnerInfo) {
  668. Err = ERROR_NOT_ENOUGH_MEMORY;
  669. leave;
  670. }
  671. Err = GLE_FN_CALL(FALSE,
  672. GetTokenInformation(Token,
  673. TokenOwner,
  674. OwnerInfo,
  675. BytesRequired,
  676. &BytesRequired)
  677. );
  678. if(Err != NO_ERROR) {
  679. leave;
  680. }
  681. //
  682. // Initialize the security descriptor.
  683. //
  684. Err = GLE_FN_CALL(FALSE,
  685. InitializeSecurityDescriptor(
  686. &SecurityDescriptor,
  687. SECURITY_DESCRIPTOR_REVISION)
  688. );
  689. if(Err != NO_ERROR) {
  690. leave;
  691. }
  692. Err = GLE_FN_CALL(FALSE,
  693. SetSecurityDescriptorOwner(&SecurityDescriptor,
  694. OwnerInfo->Owner,
  695. FALSE)
  696. );
  697. if(Err != NO_ERROR) {
  698. leave;
  699. }
  700. //
  701. // Set file security.
  702. //
  703. Err = GLE_FN_CALL(FALSE,
  704. SetFileSecurity(Filename,
  705. OWNER_SECURITY_INFORMATION,
  706. &SecurityDescriptor)
  707. );
  708. //
  709. // Not all filesystems support this operation.
  710. //
  711. if(Err == ERROR_NOT_SUPPORTED) {
  712. Err = NO_ERROR;
  713. }
  714. } except(pSetupExceptionFilter(GetExceptionCode())) {
  715. pSetupExceptionHandler(GetExceptionCode(), ERROR_READ_FAULT, &Err);
  716. }
  717. if(OwnerInfo) {
  718. MyFree(OwnerInfo);
  719. }
  720. CloseHandle(Token);
  721. return Err;
  722. }
  723. DWORD
  724. SearchForInfFile(
  725. IN PCTSTR InfName,
  726. OUT LPWIN32_FIND_DATA FindData,
  727. IN DWORD SearchControl,
  728. OUT PTSTR FullInfPath,
  729. IN UINT FullInfPathSize,
  730. OUT PUINT RequiredSize OPTIONAL
  731. )
  732. /*++
  733. Routine Description:
  734. This routine searches for an INF file in the manner specified
  735. by the SearchControl parameter. If the file is found, its
  736. full path is returned.
  737. Arguments:
  738. InfName - Supplies name of INF to search for. This name is simply
  739. appended to the two search directory paths, so if the name
  740. contains directories, the file will searched for in the
  741. subdirectory under the search directory. I.e.:
  742. \foo\bar.inf
  743. will be searched for as %windir%\inf\foo\bar.inf and
  744. %windir%\system32\foo\bar.inf.
  745. FindData - Supplies the address of a Win32 Find Data structure that
  746. receives information about the file specified (if it is found).
  747. SearchControl - Specifies the order in which directories should
  748. be searched:
  749. INFINFO_DEFAULT_SEARCH : search %windir%\inf, then %windir%\system32
  750. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  751. INFINFO_INF_PATH_LIST_SEARCH : search for the INF in each of the
  752. directories listed in the DevicePath value entry under:
  753. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  754. FullInfPath - If the file is found, receives the full path of the INF.
  755. FullInfPathSize - Supplies the size of the FullInfPath buffer (in
  756. characters).
  757. RequiredSize - Optionally, receives the number of characters (including
  758. terminating NULL) required to store the FullInfPath.
  759. Return Value:
  760. Win32 error code indicating whether the function was successful. Common
  761. return values are:
  762. NO_ERROR if the file was found, and the INF file path returned
  763. successfully.
  764. ERROR_INSUFFICIENT_BUFFER if the supplied buffer was not large enough
  765. to hold the full INF path (RequiredSize will indicated how large
  766. the buffer needs to be)
  767. ERROR_FILE_NOT_FOUND if the file was not found.
  768. ERROR_INVALID_PARAMETER if the SearchControl parameter is invalid.
  769. --*/
  770. {
  771. PCTSTR PathList;
  772. TCHAR CurInfPath[MAX_PATH];
  773. PCTSTR PathPtr, InfPathLocation;
  774. DWORD PathLength;
  775. BOOL b, FreePathList;
  776. DWORD d;
  777. //
  778. // Retrieve the path list.
  779. //
  780. if(SearchControl == INFINFO_INF_PATH_LIST_SEARCH) {
  781. //
  782. // Just use our global list of INF search paths.
  783. //
  784. PathList = InfSearchPaths;
  785. FreePathList = FALSE;
  786. } else {
  787. if(!(PathList = AllocAndReturnDriverSearchList(SearchControl))) {
  788. return ERROR_NOT_ENOUGH_MEMORY;
  789. }
  790. FreePathList = TRUE;
  791. }
  792. d = NO_ERROR;
  793. InfPathLocation = NULL;
  794. try {
  795. //
  796. // Now look for the INF in each path in our MultiSz list.
  797. //
  798. for(PathPtr = PathList; *PathPtr; PathPtr += (lstrlen(PathPtr) + 1)) {
  799. //
  800. // Concatenate the INF file name with the current search path.
  801. //
  802. if(FAILED(StringCchCopy(CurInfPath, SIZECHARS(CurInfPath), PathPtr))) {
  803. //
  804. // not a valid path, don't bother trying to do FileExists
  805. //
  806. continue;
  807. }
  808. if(!pSetupConcatenatePaths(CurInfPath,
  809. InfName,
  810. SIZECHARS(CurInfPath),
  811. &PathLength)) {
  812. //
  813. // not a valid path, don't bother trying to do FileExists
  814. //
  815. continue;
  816. }
  817. d = GLE_FN_CALL(FALSE, FileExists(CurInfPath, FindData));
  818. if(d == NO_ERROR) {
  819. if(!(FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  820. InfPathLocation = CurInfPath;
  821. break;
  822. }
  823. } else {
  824. //
  825. // See if we got a 'real' error
  826. //
  827. if((d != ERROR_NO_MORE_FILES) &&
  828. (d != ERROR_FILE_NOT_FOUND) &&
  829. (d != ERROR_PATH_NOT_FOUND)) {
  830. //
  831. // This is a 'real' error, abort the search.
  832. //
  833. break;
  834. }
  835. //
  836. // reset error to NO_ERROR and continue search
  837. //
  838. d = NO_ERROR;
  839. }
  840. }
  841. } except(pSetupExceptionFilter(GetExceptionCode())) {
  842. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &d);
  843. }
  844. //
  845. // Whatever the outcome, we're through with the PathList buffer.
  846. //
  847. if(FreePathList) {
  848. MyFree(PathList);
  849. }
  850. if(d != NO_ERROR) {
  851. return d;
  852. } else if(!InfPathLocation) {
  853. return ERROR_FILE_NOT_FOUND;
  854. }
  855. if(RequiredSize) {
  856. *RequiredSize = PathLength;
  857. }
  858. if(PathLength > FullInfPathSize) {
  859. return ERROR_INSUFFICIENT_BUFFER;
  860. }
  861. CopyMemory(FullInfPath,
  862. InfPathLocation,
  863. PathLength * sizeof(TCHAR)
  864. );
  865. return NO_ERROR;
  866. }
  867. DWORD
  868. MultiSzFromSearchControl(
  869. IN DWORD SearchControl,
  870. OUT PTCHAR PathList,
  871. IN DWORD PathListSize,
  872. OUT PDWORD RequiredSize OPTIONAL
  873. )
  874. /*++
  875. Routine Description:
  876. This routine takes a search control ordinal and builds a MultiSz list
  877. based on the search list it specifies.
  878. Arguments:
  879. SearchControl - Specifies the directory list to be built. May be one
  880. of the following values:
  881. INFINFO_DEFAULT_SEARCH : %windir%\inf, then %windir%\system32
  882. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  883. INFINFO_INF_PATH_LIST_SEARCH : Each of the directories listed in
  884. the DevicePath value entry under:
  885. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  886. PathList - Supplies the address of a character buffer that will receive
  887. the MultiSz list.
  888. PathListSize - Supplies the size, in characters, of the PathList buffer.
  889. RequiredSize - Optionally, receives the number of characters required
  890. to store the MultiSz PathList.
  891. (NOTE: The user-supplied buffer is used to retrieve the value entry
  892. from the registry. Therefore, if the value is a REG_EXPAND_SZ entry,
  893. the RequiredSize parameter may be set too small on an
  894. ERROR_INSUFFICIENT_BUFFER error. This will happen if the buffer was
  895. too small to retrieve the value entry, before expansion. In this case,
  896. calling the API again with a buffer sized according to the RequiredSize
  897. output may fail with an ERROR_INSUFFICIENT_BUFFER yet again, since
  898. expansion may require an even larger buffer.)
  899. Return Value:
  900. If successful, returns NO_ERROR.
  901. If failure, returns a Win32 error code indicating the cause of the failure.
  902. --*/
  903. {
  904. HKEY hk;
  905. PCTSTR Path1, Path2;
  906. PTSTR PathBuffer;
  907. DWORD RegDataType, PathLength, PathLength1, PathLength2;
  908. DWORD NumPaths, Err;
  909. BOOL UseDefaultDevicePath;
  910. if(PathList) {
  911. Err = NO_ERROR; // assume success.
  912. } else {
  913. return ERROR_INVALID_PARAMETER;
  914. }
  915. UseDefaultDevicePath = FALSE;
  916. if(SearchControl == INFINFO_INF_PATH_LIST_SEARCH) {
  917. //
  918. // Retrieve the INF search path list from the registry.
  919. //
  920. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  921. pszPathSetup,
  922. 0,
  923. KEY_READ,
  924. &hk) != ERROR_SUCCESS) {
  925. //
  926. // Fall back to default (just the Inf directory).
  927. //
  928. UseDefaultDevicePath = TRUE;
  929. } else {
  930. PathBuffer = NULL;
  931. try {
  932. //
  933. // Get the DevicePath value entry. Support REG_SZ or
  934. // REG_EXPAND_SZ data.
  935. //
  936. PathLength = PathListSize * sizeof(TCHAR);
  937. Err = RegQueryValueEx(hk,
  938. pszDevicePath,
  939. NULL,
  940. &RegDataType,
  941. (LPBYTE)PathList,
  942. &PathLength
  943. );
  944. //
  945. // Need path length in characters from now on.
  946. //
  947. PathLength /= sizeof(TCHAR);
  948. if(Err == ERROR_SUCCESS) {
  949. //
  950. // Check if the caller's buffer has room for extra NULL
  951. // terminator.
  952. //
  953. if(PathLength >= PathListSize) {
  954. PathLength++;
  955. Err = ERROR_INSUFFICIENT_BUFFER;
  956. } else if((RegDataType == REG_SZ) || (RegDataType == REG_EXPAND_SZ)) {
  957. //
  958. // Convert this semicolon-delimited list to a
  959. // REG_MULTI_SZ.
  960. //
  961. NumPaths = DelimStringToMultiSz(PathList,
  962. PathLength,
  963. TEXT(';')
  964. );
  965. //
  966. // Allocate a temporary buffer large enough to hold the
  967. // number of paths in the MULTI_SZ list, each having
  968. // maximum length (plus an extra terminating NULL at
  969. // the end).
  970. //
  971. if(!(PathBuffer = MyMalloc((NumPaths * MAX_PATH * sizeof(TCHAR))
  972. + sizeof(TCHAR)))) {
  973. Err = ERROR_NOT_ENOUGH_MEMORY;
  974. leave;
  975. }
  976. PathLength = 0;
  977. for(Path1 = PathList;
  978. *Path1;
  979. Path1 += lstrlen(Path1) + 1) {
  980. if(RegDataType == REG_EXPAND_SZ) {
  981. DWORD SubPathLength;
  982. SubPathLength = ExpandEnvironmentStrings(
  983. Path1,
  984. PathBuffer + PathLength,
  985. MAX_PATH
  986. );
  987. if(SubPathLength <= MAX_PATH) {
  988. PathLength += lstrlen(PathBuffer+PathLength) + 1;
  989. }
  990. } else {
  991. if(SUCCEEDED(StringCchCopy(PathBuffer + PathLength,
  992. MAX_PATH,
  993. Path1))) {
  994. PathLength += lstrlen(PathBuffer+PathLength) + 1;
  995. }
  996. }
  997. //
  998. // If the last character in this path is a
  999. // backslash, then strip it off.
  1000. // PathLength at this point includes terminating
  1001. // NULL char at PathBuffer[PathLength-1] is (or
  1002. // should be) NULL char at PathBuffer[PathLength-2]
  1003. // may be '\'
  1004. //
  1005. if(*CharPrev(PathBuffer, PathBuffer + PathLength - 1) == TEXT('\\')) {
  1006. *(PathBuffer + PathLength - 2) = TEXT('\0');
  1007. PathLength--;
  1008. }
  1009. }
  1010. //
  1011. // Add additional terminating NULL at the end.
  1012. //
  1013. *(PathBuffer + PathLength) = TEXT('\0');
  1014. if(++PathLength > PathListSize) {
  1015. Err = ERROR_INSUFFICIENT_BUFFER;
  1016. } else {
  1017. CopyMemory(PathList,
  1018. PathBuffer,
  1019. PathLength * sizeof(TCHAR)
  1020. );
  1021. }
  1022. MyFree(PathBuffer);
  1023. PathBuffer = NULL;
  1024. } else {
  1025. //
  1026. // Bad data type--just use the Inf directory.
  1027. //
  1028. UseDefaultDevicePath = TRUE;
  1029. }
  1030. } else if(Err == ERROR_MORE_DATA){
  1031. Err = ERROR_INSUFFICIENT_BUFFER;
  1032. } else {
  1033. //
  1034. // Fall back to default (just the Inf directory).
  1035. //
  1036. UseDefaultDevicePath = TRUE;
  1037. }
  1038. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1039. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  1040. //
  1041. // Fall back to default (just the Inf directory).
  1042. //
  1043. UseDefaultDevicePath = TRUE;
  1044. if(PathBuffer) {
  1045. MyFree(PathBuffer);
  1046. }
  1047. }
  1048. RegCloseKey(hk);
  1049. }
  1050. }
  1051. if(UseDefaultDevicePath) {
  1052. PathLength = lstrlen(InfDirectory) + 2;
  1053. if(PathLength > PathListSize) {
  1054. Err = ERROR_INSUFFICIENT_BUFFER;
  1055. } else {
  1056. Err = NO_ERROR;
  1057. CopyMemory(PathList, InfDirectory, (PathLength - 1) * sizeof(TCHAR));
  1058. //
  1059. // Add extra NULL to terminate the list.
  1060. //
  1061. PathList[PathLength - 1] = TEXT('\0');
  1062. }
  1063. } else if((Err == NO_ERROR) && (SearchControl != INFINFO_INF_PATH_LIST_SEARCH)) {
  1064. switch(SearchControl) {
  1065. case INFINFO_DEFAULT_SEARCH :
  1066. Path1 = InfDirectory;
  1067. Path2 = SystemDirectory;
  1068. break;
  1069. case INFINFO_REVERSE_DEFAULT_SEARCH :
  1070. Path1 = SystemDirectory;
  1071. Path2 = InfDirectory;
  1072. break;
  1073. default :
  1074. return ERROR_INVALID_PARAMETER;
  1075. }
  1076. PathLength1 = lstrlen(Path1) + 1;
  1077. PathLength2 = lstrlen(Path2) + 1;
  1078. PathLength = PathLength1 + PathLength2 + 1;
  1079. if(PathLength > PathListSize) {
  1080. Err = ERROR_INSUFFICIENT_BUFFER;
  1081. } else {
  1082. CopyMemory(PathList, Path1, PathLength1 * sizeof(TCHAR));
  1083. CopyMemory(&(PathList[PathLength1]), Path2, PathLength2 * sizeof(TCHAR));
  1084. //
  1085. // Add additional terminating NULL at the end.
  1086. //
  1087. PathList[PathLength - 1] = TEXT('\0');
  1088. }
  1089. }
  1090. if(((Err == NO_ERROR) || (Err == ERROR_INSUFFICIENT_BUFFER)) && RequiredSize) {
  1091. *RequiredSize = PathLength;
  1092. }
  1093. return Err;
  1094. }
  1095. PTSTR
  1096. AllocAndReturnDriverSearchList(
  1097. IN DWORD SearchControl
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. This routine returns a buffer contains a multi-sz list of all directory
  1102. paths in our driver search path list.
  1103. The buffer returned must be freed with MyFree().
  1104. Arguments:
  1105. SearchControl - Specifies the directory list to be retrieved. May be one
  1106. of the following values:
  1107. INFINFO_DEFAULT_SEARCH : %windir%\inf, then %windir%\system32
  1108. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  1109. INFINFO_INF_PATH_LIST_SEARCH : Each of the directories listed in
  1110. the DevicePath value entry under:
  1111. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  1112. Returns:
  1113. Pointer to the allocated buffer containing the list, or NULL if a failure
  1114. was encountered (typically, due to out-of-memory).
  1115. --*/
  1116. {
  1117. PTSTR PathListBuffer = NULL, TrimBuffer = NULL;
  1118. DWORD BufferSize;
  1119. DWORD Err;
  1120. try {
  1121. //
  1122. // Start out with a buffer of MAX_PATH length, which should cover most cases.
  1123. //
  1124. BufferSize = MAX_PATH;
  1125. //
  1126. // Loop on a call to MultiSzFromSearchControl until we succeed or hit
  1127. // some error other than buffer-too-small. There are two reasons for
  1128. // this. First, it is possible that someone could have added a new
  1129. // path to the registry list between calls, and second, since that
  1130. // routine uses our buffer to retrieve the original (non-expanded)
  1131. // list, it can only report the size it needs to retrieve the
  1132. // unexpanded list. After it is given enough space to retrieve it,
  1133. // _then_ it can tell us how much space we really need.
  1134. //
  1135. // With all that said, we'll almost never see this call made more than
  1136. // once.
  1137. //
  1138. while(NULL != (PathListBuffer = MyMalloc((BufferSize+2) * sizeof(TCHAR)))) {
  1139. if((Err = MultiSzFromSearchControl(SearchControl,
  1140. PathListBuffer,
  1141. BufferSize,
  1142. &BufferSize)) == NO_ERROR) {
  1143. //
  1144. // We've successfully retrieved the path list. If the list is
  1145. // larger than necessary (the normal case), then trim it down
  1146. // before returning. (If this fails it's no big deal--we'll
  1147. // just keep on using the original buffer.)
  1148. //
  1149. TrimBuffer = MyRealloc(PathListBuffer,
  1150. (BufferSize+2) * sizeof(TCHAR)
  1151. );
  1152. if(TrimBuffer) {
  1153. PathListBuffer = TrimBuffer;
  1154. }
  1155. //
  1156. // We succeeded--break out of the loop.
  1157. //
  1158. break;
  1159. } else {
  1160. //
  1161. // Free our current buffer before we find out what went wrong.
  1162. //
  1163. MyFree(PathListBuffer);
  1164. PathListBuffer = NULL;
  1165. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  1166. //
  1167. // We failed.
  1168. //
  1169. leave;
  1170. }
  1171. }
  1172. }
  1173. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1174. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  1175. if(TrimBuffer) {
  1176. MyFree(TrimBuffer);
  1177. } else if(PathListBuffer) {
  1178. MyFree(PathListBuffer);
  1179. }
  1180. PathListBuffer = NULL;
  1181. }
  1182. return PathListBuffer;
  1183. }
  1184. BOOL
  1185. DoMove(
  1186. IN PCTSTR CurrentName,
  1187. IN PCTSTR NewName
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. Wrapper for MoveFileEx on NT
  1192. Arguments:
  1193. CurrentName - supplies the name of the file as it exists currently.
  1194. NewName - supplies the new name
  1195. Returns:
  1196. Boolean value indicating outcome. If failure, last error is set.
  1197. --*/
  1198. {
  1199. return MoveFileEx(CurrentName, NewName, MOVEFILE_REPLACE_EXISTING);
  1200. }
  1201. BOOL
  1202. DelayedMove(
  1203. IN PCTSTR CurrentName,
  1204. IN PCTSTR NewName OPTIONAL
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. Queue a file for copy or delete on next reboot.
  1209. On Windows NT this means using MoveFileEx().
  1210. Arguments:
  1211. CurrentName - supplies the name of the file as it exists currently.
  1212. NewName - if specified supplies the new name. If not specified
  1213. then the file named by CurrentName is deleted on next reboot.
  1214. Returns:
  1215. Boolean value indicating outcome. If failure, last error is set.
  1216. --*/
  1217. {
  1218. return MoveFileEx(CurrentName,
  1219. NewName,
  1220. MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT
  1221. );
  1222. }
  1223. typedef enum _OEM_FILE_TYPE {
  1224. OemFiletypeInf,
  1225. OemFiletypeCat
  1226. } OEM_FILE_TYPE, *POEM_FILE_TYPE;
  1227. BOOL
  1228. IsInstalledFileFromOem(
  1229. IN PCTSTR Filename,
  1230. IN OEM_FILE_TYPE Filetype
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. Determine whether a file has the proper format for an (installed) OEM INF
  1235. or catalog.
  1236. Arguments:
  1237. Filename - supplies filename (sans path) to be checked.
  1238. Filetype - specifies the type of file indicating how validation should be
  1239. performed for the caller-supplied Filename. May be one of the
  1240. following values:
  1241. OemFiletypeInf - file must be OEM INF filename format (i.e., OEM<n>.INF)
  1242. OemFiletypeCat - file must be OEM CAT filename format (i.e., OEM<n>.CAT)
  1243. Return Value:
  1244. If the file conforms to the format for an installed OEM file of the
  1245. specified type, the return is non-zero. Otherwise, it is FALSE.
  1246. --*/
  1247. {
  1248. PTSTR p;
  1249. BOOL b;
  1250. //
  1251. // Catalog filename must not contain path...
  1252. //
  1253. MYASSERT(pSetupGetFileTitle(Filename) == Filename);
  1254. //
  1255. // First check that the first 3 characters are OEM
  1256. //
  1257. if(_tcsnicmp(Filename, TEXT("oem"), 3)) {
  1258. return FALSE;
  1259. }
  1260. //
  1261. // Next verify that any characters after "oem" and before ".cat"
  1262. // are digits.
  1263. //
  1264. p = (PTSTR)Filename;
  1265. p = CharNext(p);
  1266. p = CharNext(p);
  1267. p = CharNext(p);
  1268. while((*p != TEXT('\0')) && (*p != TEXT('.'))) {
  1269. if((*p < TEXT('0')) || (*p > TEXT('9'))) {
  1270. return FALSE;
  1271. }
  1272. p = CharNext(p);
  1273. }
  1274. //
  1275. // Finally, verify that the last 4 characters are either ".inf" or ".cat",
  1276. // depending on what type of file the caller specified.
  1277. //
  1278. switch(Filetype) {
  1279. case OemFiletypeInf :
  1280. b = !_tcsicmp(p, TEXT(".INF"));
  1281. break;
  1282. case OemFiletypeCat :
  1283. b = !_tcsicmp(p, TEXT(".CAT"));
  1284. break;
  1285. default :
  1286. MYASSERT(FALSE);
  1287. return FALSE;
  1288. }
  1289. return b;
  1290. }
  1291. DWORD
  1292. pSetupInstallCatalog(
  1293. IN LPCTSTR CatalogFullPath,
  1294. IN LPCTSTR NewBaseName,
  1295. OUT LPTSTR NewCatalogFullPath OPTIONAL
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. This routine installs a catalog file. The file is copied by the system
  1300. into a special directory, and is optionally renamed.
  1301. Arguments:
  1302. CatalogFullPath - supplies the fully-qualified win32 path of the catalog
  1303. to be installed on the system.
  1304. NewBaseName - specifies the new base name to use when the catalog file is
  1305. copied into the catalog store.
  1306. NewCatalogFullPath - optionally receives the fully-qualified path of the
  1307. catalog file within the catalog store. This buffer should be at least
  1308. MAX_PATH bytes (ANSI version) or chars (Unicode version).
  1309. ** NOTE: If we're running in "minimal embedded" mode, then we don't **
  1310. ** actually call any of the Crypto APIs, and instead always simply **
  1311. ** report success. In this case, the caller had better not have **
  1312. ** specified an OUT buffer for NewCatalogFullPath, because we won't **
  1313. ** have a path to report. If we run into this case, we'll instead **
  1314. ** report failure. What this really says is that nobody other than **
  1315. ** setupapi should ever be passing a non-NULL value for this arg. **
  1316. Return Value:
  1317. If successful, the return value is NO_ERROR.
  1318. If failure, the return value is a Win32 error code indicating the cause of
  1319. the failure.
  1320. --*/
  1321. {
  1322. DWORD Err;
  1323. HCATADMIN hCatAdmin;
  1324. HCATINFO hCatInfo;
  1325. CATALOG_INFO CatalogInfo;
  1326. LPWSTR LocalCatalogFullPath;
  1327. LPWSTR LocalNewBaseName;
  1328. MYASSERT(NewBaseName);
  1329. if(!NewBaseName) {
  1330. return ERROR_INVALID_PARAMETER;
  1331. }
  1332. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1333. //
  1334. // If someone called us expecting the new catalog's full path to be
  1335. // returned, they're outta luck...
  1336. //
  1337. MYASSERT(!NewCatalogFullPath);
  1338. if(NewCatalogFullPath) {
  1339. //
  1340. // In minimal embedded mode, a non-NULL NewCatalogFullPath arg is
  1341. // an invalid parameter...
  1342. //
  1343. return ERROR_INVALID_PARAMETER;
  1344. } else {
  1345. //
  1346. // Simply report success.
  1347. //
  1348. return NO_ERROR;
  1349. }
  1350. }
  1351. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  1352. return TRUST_E_FAIL;
  1353. }
  1354. Err = NO_ERROR;
  1355. LocalCatalogFullPath = NULL;
  1356. LocalNewBaseName = NULL;
  1357. hCatInfo = NULL;
  1358. Err = GLE_FN_CALL(FALSE, CryptCATAdminAcquireContext(&hCatAdmin,
  1359. &DriverVerifyGuid,
  1360. 0)
  1361. );
  1362. if(Err != NO_ERROR) {
  1363. return Err;
  1364. }
  1365. try {
  1366. //
  1367. // Duplicate our catalog pathname and basename since the
  1368. // CryptCATAdminAddCatalog prototype doesn't specify these arguments as
  1369. // being const strings.
  1370. //
  1371. LocalCatalogFullPath = DuplicateString(CatalogFullPath);
  1372. LocalNewBaseName = DuplicateString(NewBaseName);
  1373. if(!LocalCatalogFullPath || !LocalNewBaseName) {
  1374. Err = ERROR_NOT_ENOUGH_MEMORY;
  1375. leave;
  1376. }
  1377. Err = GLE_FN_CALL(NULL,
  1378. hCatInfo = CryptCATAdminAddCatalog(
  1379. hCatAdmin,
  1380. LocalCatalogFullPath,
  1381. LocalNewBaseName,
  1382. 0)
  1383. );
  1384. if(Err != NO_ERROR) {
  1385. //
  1386. // If the error we received is ERROR_ALREADY_EXISTS, then that
  1387. // indicates that the exact same catalog was already present
  1388. // (and installed under the same name). Treat this as a
  1389. // success (assuming we can get the full pathname of the
  1390. // existing catalog).
  1391. //
  1392. if(Err == ERROR_ALREADY_EXISTS) {
  1393. if(NewCatalogFullPath) {
  1394. //
  1395. // Resolve the catalog base filename to a fully-
  1396. // qualified path.
  1397. //
  1398. CatalogInfo.cbStruct = sizeof(CATALOG_INFO);
  1399. Err = GLE_FN_CALL(FALSE,
  1400. CryptCATAdminResolveCatalogPath(
  1401. hCatAdmin,
  1402. LocalNewBaseName,
  1403. &CatalogInfo,
  1404. 0)
  1405. );
  1406. } else {
  1407. //
  1408. // Caller isn't interested in finding out what pathname
  1409. // the catalog was installed under...
  1410. //
  1411. Err = NO_ERROR;
  1412. }
  1413. }
  1414. } else if(NewCatalogFullPath) {
  1415. //
  1416. // The caller wants to know the full path under which the catalog
  1417. // got installed.
  1418. //
  1419. CatalogInfo.cbStruct = sizeof(CATALOG_INFO);
  1420. Err = GLE_FN_CALL(FALSE,
  1421. CryptCATCatalogInfoFromContext(hCatInfo,
  1422. &CatalogInfo,
  1423. 0)
  1424. );
  1425. }
  1426. //
  1427. // If we succeeded in retrieving the installed catalog's full path
  1428. // (and the caller requested it), fill in the caller's buffer now.
  1429. //
  1430. if((Err == NO_ERROR) && NewCatalogFullPath) {
  1431. MYVERIFY(SUCCEEDED(StringCchCopy(NewCatalogFullPath,
  1432. MAX_PATH,
  1433. CatalogInfo.wszCatalogFile)));
  1434. }
  1435. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1436. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1437. }
  1438. if(hCatInfo) {
  1439. CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0);
  1440. }
  1441. CryptCATAdminReleaseContext(hCatAdmin, 0);
  1442. if(LocalCatalogFullPath) {
  1443. MyFree(LocalCatalogFullPath);
  1444. }
  1445. if(LocalNewBaseName) {
  1446. MyFree(LocalNewBaseName);
  1447. }
  1448. return Err;
  1449. }
  1450. DWORD
  1451. pSetupVerifyCatalogFile(
  1452. IN LPCTSTR CatalogFullPath
  1453. )
  1454. /*++
  1455. Routine Description:
  1456. This routine verifies a single catalog file using standard OS codesigning
  1457. (i.e., driver signing) policy.
  1458. Arguments:
  1459. CatalogFullPath - supplies the fully-qualified Win32 path of
  1460. the catalog file to be verified.
  1461. Return Value:
  1462. If successful, the return value is ERROR_SUCCESS.
  1463. If failure, the return value is the error returned from WinVerifyTrust.
  1464. --*/
  1465. {
  1466. return _VerifyCatalogFile(NULL, CatalogFullPath, NULL, FALSE, NULL, NULL);
  1467. }
  1468. DWORD
  1469. _VerifyCatalogFile(
  1470. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1471. IN LPCTSTR CatalogFullPath,
  1472. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  1473. IN BOOL UseAuthenticodePolicy,
  1474. IN OUT HCERTSTORE *hStoreTrustedPublisher, OPTIONAL
  1475. OUT HANDLE *hWVTStateData OPTIONAL
  1476. )
  1477. /*++
  1478. Routine Description:
  1479. This routine verifies a single catalog file using the specified policy.
  1480. Arguments:
  1481. LogContext - optionally, supplies the context to be used when logging
  1482. information about the routine's activities.
  1483. CatalogFullPath - supplies the fully-qualified Win32 path of the catalog
  1484. file to be verified.
  1485. AltPlatformInfo - optionally, supplies alternate platform information used
  1486. to fill in a DRIVER_VER_INFO structure (defined in sdk\inc\softpub.h)
  1487. that is passed to WinVerifyTrust.
  1488. ** NOTE: This structure _must_ have its cbSize field set to **
  1489. ** sizeof(SP_ALTPLATFORM_INFO_V2) -- validation on client-supplied **
  1490. ** buffer is the responsibility of the caller. **
  1491. UseAuthenticodePolicy - if TRUE, verification is to be done using
  1492. Authenticode policy instead of standard driver signing policy.
  1493. hStoreTrustedPublisher - optionally, supplies the address of a certificate
  1494. store handle. If the handle pointed to is NULL, a handle will be
  1495. acquired (if possible) via CertOpenStore and returned to the caller.
  1496. If the handle pointed to is non-NULL, then that handle will be used by
  1497. this routine. If the pointer itself is NULL, then an HCERTSTORE will
  1498. be acquired for the duration of this call, and released before
  1499. returning.
  1500. NOTE: it is the caller's responsibility to free the certificate store
  1501. handle returned by this routine by calling CertCloseStore. This handle
  1502. may be opened in either success or failure cases, so the caller must
  1503. check for non-NULL returned handle in both cases.
  1504. hWVTStateData - if supplied, this parameter points to a buffer that
  1505. receives a handle to WinVerifyTrust state data. This handle will be
  1506. returned only when validation was successfully performed using
  1507. Authenticode policy. This handle may be used, for example, to retrieve
  1508. signer info when prompting the user about whether they trust the
  1509. publisher. (The status code returned will indicate whether or not this
  1510. is necessary, see "Return Value" section below.)
  1511. This parameter should only be supplied if UseAuthenticodePolicy is
  1512. TRUE. If the routine fails, then this handle will be set to NULL.
  1513. It is the caller's responsibility to close this handle when they're
  1514. finished with it by calling pSetupCloseWVTStateData().
  1515. Return Value:
  1516. If the catalog was successfully validated via driver signing policy, then
  1517. the return value is NO_ERROR.
  1518. If the catalog was successfully validated via Authenticode policy, and the
  1519. publisher was in the TrustedPublisher store, then the return value is
  1520. ERROR_AUTHENTICODE_TRUSTED_PUBLISHER.
  1521. If the catalog was successfully validated via Authenticode policy, and the
  1522. publisher was not in the TrustedPublisher store (hence we must prompt the
  1523. user to establish their trust of the publisher), then the return value is
  1524. ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED
  1525. If a failure occurred, the return value is a Win32 error code indicating
  1526. the cause of the failure.
  1527. Remarks:
  1528. If we're in initial system setup (i.e., GUI-mode setup or mini-setup), we
  1529. automatically install the certificates for any Authenticode-signed packages
  1530. we encounter. This is done to make OEM and corporate deployment as
  1531. painless as possible. In order to avoid being spoofed into thinking we're
  1532. in system setup when we're not, we check to see if we're in LocalSystem
  1533. security context (which both GUI setup and mini-setup are), and that we're
  1534. on an interactive windowstation (which umpnpmgr is not).
  1535. --*/
  1536. {
  1537. WINTRUST_DATA WintrustData;
  1538. WINTRUST_FILE_INFO WintrustFileInfo;
  1539. DRIVER_VER_INFO VersionInfo;
  1540. DWORD Err, CertAutoInstallErr;
  1541. PCRYPT_PROVIDER_DATA ProviderData;
  1542. PCRYPT_PROVIDER_SGNR ProviderSigner;
  1543. PCRYPT_PROVIDER_CERT ProviderCert;
  1544. TCHAR PublisherName[MAX_PATH];
  1545. //
  1546. // If the caller requested that we return WinVerifyTrust state data upon
  1547. // successful Authenticode validation, then they'd better have actually
  1548. // requested Authenticode validation!
  1549. //
  1550. MYASSERT(!hWVTStateData || UseAuthenticodePolicy);
  1551. if(hWVTStateData) {
  1552. *hWVTStateData = NULL;
  1553. }
  1554. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1555. //
  1556. // Not valid to call us requesting Authenticode validation!
  1557. //
  1558. MYASSERT(!UseAuthenticodePolicy);
  1559. return ERROR_SUCCESS;
  1560. }
  1561. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  1562. return TRUST_E_FAIL;
  1563. }
  1564. if (!FileExists(CatalogFullPath, NULL)) {
  1565. return ERROR_NO_CATALOG_FOR_OEM_INF;
  1566. }
  1567. ZeroMemory(&WintrustData, sizeof(WINTRUST_DATA));
  1568. WintrustData.cbStruct = sizeof(WINTRUST_DATA);
  1569. WintrustData.dwUIChoice = WTD_UI_NONE;
  1570. WintrustData.dwUnionChoice = WTD_CHOICE_FILE;
  1571. WintrustData.pFile = &WintrustFileInfo;
  1572. WintrustData.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
  1573. WTD_CACHE_ONLY_URL_RETRIEVAL;
  1574. ZeroMemory(&WintrustFileInfo, sizeof(WINTRUST_FILE_INFO));
  1575. WintrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
  1576. WintrustFileInfo.pcwszFilePath = CatalogFullPath;
  1577. if(UseAuthenticodePolicy) {
  1578. //
  1579. // We want WinVerifyTrust to return a handle to its state data, so we
  1580. // can retrieve the publisher's cert...
  1581. //
  1582. WintrustData.dwStateAction = WTD_STATEACTION_VERIFY;
  1583. } else {
  1584. //
  1585. // Specify driver version info structure so that we can control the
  1586. // range of OS versions against which this catalog should validate.
  1587. //
  1588. ZeroMemory(&VersionInfo, sizeof(DRIVER_VER_INFO));
  1589. VersionInfo.cbStruct = sizeof(DRIVER_VER_INFO);
  1590. if(AltPlatformInfo) {
  1591. MYASSERT(AltPlatformInfo->cbSize == sizeof(SP_ALTPLATFORM_INFO_V2));
  1592. //
  1593. // Caller wants the file validated for an alternate platform, so we
  1594. // must fill in a DRIVER_VER_INFO structure to be passed to the policy
  1595. // module.
  1596. //
  1597. VersionInfo.dwPlatform = AltPlatformInfo->Platform;
  1598. VersionInfo.dwVersion = AltPlatformInfo->MajorVersion;
  1599. VersionInfo.sOSVersionLow.dwMajor = AltPlatformInfo->FirstValidatedMajorVersion;
  1600. VersionInfo.sOSVersionLow.dwMinor = AltPlatformInfo->FirstValidatedMinorVersion;
  1601. VersionInfo.sOSVersionHigh.dwMajor = AltPlatformInfo->MajorVersion;
  1602. VersionInfo.sOSVersionHigh.dwMinor = AltPlatformInfo->MinorVersion;
  1603. } else {
  1604. //
  1605. // If an AltPlatformInfo was not passed in then set the
  1606. // WTD_USE_DEFAULT_OSVER_CHECK flag. This flag tells WinVerifyTrust to
  1607. // use its default osversion checking, even though a DRIVER_VER_INFO
  1608. // structure was passed in.
  1609. //
  1610. WintrustData.dwProvFlags |= WTD_USE_DEFAULT_OSVER_CHECK;
  1611. }
  1612. //
  1613. // Specify a DRIVER_VER_INFO structure so we can get back signer
  1614. // information about the catalog.
  1615. //
  1616. WintrustData.pPolicyCallbackData = (PVOID)&VersionInfo;
  1617. }
  1618. //
  1619. // Our call to WinVerifyTrust may allocate a resource we need to free
  1620. // (namely, the signer cert context). Wrap the following in try/except
  1621. // so we won't leak resources in case of exception.
  1622. //
  1623. try {
  1624. Err = (DWORD)WinVerifyTrust(NULL,
  1625. (UseAuthenticodePolicy
  1626. ? &AuthenticodeVerifyGuid
  1627. : &DriverVerifyGuid),
  1628. &WintrustData
  1629. );
  1630. if((Err != NO_ERROR) || !UseAuthenticodePolicy) {
  1631. //
  1632. // If we're using driver signing policy, and we failed because of
  1633. // an osattribute mismatch, then convert this error to a specific
  1634. // error (with more sensible text).
  1635. //
  1636. if(!UseAuthenticodePolicy && (Err == ERROR_APP_WRONG_OS)) {
  1637. Err = ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH;
  1638. }
  1639. leave;
  1640. }
  1641. //
  1642. // If we get to this point, we successfully validated the catalog via
  1643. // Authenticode policy, and we have a handle to the WinVerifyTrust
  1644. // state data we need in order to: (a) return the handle to the caller
  1645. // (if requested), and (b) get at the certificate we need to search for
  1646. // in the TrustedPublisher certificate store.
  1647. //
  1648. MYASSERT(WintrustData.hWVTStateData);
  1649. if(!WintrustData.hWVTStateData) {
  1650. Err = ERROR_UNIDENTIFIED_ERROR;
  1651. leave;
  1652. }
  1653. //
  1654. // Now we need to ascertain whether the publisher is already trusted,
  1655. // or whether we must prompt the user.
  1656. //
  1657. ProviderData = WTHelperProvDataFromStateData(WintrustData.hWVTStateData);
  1658. MYASSERT(ProviderData);
  1659. if(!ProviderData) {
  1660. Err = ERROR_UNIDENTIFIED_ERROR;
  1661. leave;
  1662. }
  1663. ProviderSigner = WTHelperGetProvSignerFromChain(ProviderData,
  1664. 0,
  1665. FALSE,
  1666. 0
  1667. );
  1668. MYASSERT(ProviderSigner);
  1669. if(!ProviderSigner) {
  1670. Err = ERROR_UNIDENTIFIED_ERROR;
  1671. leave;
  1672. }
  1673. ProviderCert = WTHelperGetProvCertFromChain(ProviderSigner, 0);
  1674. MYASSERT(ProviderCert);
  1675. if(!ProviderCert) {
  1676. Err = ERROR_UNIDENTIFIED_ERROR;
  1677. leave;
  1678. }
  1679. if(pSetupIsAuthenticodePublisherTrusted(ProviderCert->pCert,
  1680. hStoreTrustedPublisher)) {
  1681. Err = ERROR_AUTHENTICODE_TRUSTED_PUBLISHER;
  1682. } else {
  1683. //
  1684. // If we're running in a context where it's acceptable to auto-
  1685. // install the cert, then do that now. Otherwise, we report a
  1686. // status code that informs the caller they must prompt the user
  1687. // about whether this publisher is to be trusted.
  1688. //
  1689. if(IsAutoCertInstallAllowed()) {
  1690. //
  1691. // Retrieve the publisher's name, so we can include it when
  1692. // logging either success or failure of the certificate
  1693. // installation.
  1694. //
  1695. MYVERIFY(1 <= CertGetNameString(
  1696. ProviderCert->pCert,
  1697. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  1698. 0,
  1699. NULL,
  1700. PublisherName,
  1701. SIZECHARS(PublisherName))
  1702. );
  1703. CertAutoInstallErr = pSetupInstallCertificate(ProviderCert->pCert);
  1704. if(CertAutoInstallErr == NO_ERROR) {
  1705. //
  1706. // Log the fact that we auto-installed a certificate.
  1707. //
  1708. WriteLogEntry(LogContext,
  1709. DRIVER_LOG_INFO,
  1710. MSG_LOG_AUTHENTICODE_CERT_AUTOINSTALLED,
  1711. NULL,
  1712. PublisherName
  1713. );
  1714. //
  1715. // Now publisher is trusted, so return status indicating
  1716. // that.
  1717. //
  1718. Err = ERROR_AUTHENTICODE_TRUSTED_PUBLISHER;
  1719. } else {
  1720. //
  1721. // Log the fact that we couldn't install the certificate.
  1722. // Don't treat this as a fatal error, however.
  1723. //
  1724. WriteLogEntry(LogContext,
  1725. DRIVER_LOG_WARNING | SETUP_LOG_BUFFER,
  1726. MSG_LOG_AUTHENTICODE_CERT_AUTOINSTALL_FAILED,
  1727. NULL,
  1728. PublisherName
  1729. );
  1730. WriteLogError(LogContext,
  1731. DRIVER_LOG_WARNING,
  1732. CertAutoInstallErr
  1733. );
  1734. //
  1735. // Report status indicating that the user must be prompted
  1736. // to establish trust of this publisher.
  1737. //
  1738. Err = ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED;
  1739. }
  1740. } else {
  1741. Err = ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED;
  1742. }
  1743. }
  1744. //
  1745. // If we get to here, then we've successfully verified the catalog, and
  1746. // ascertained whether the certificate should be implicitly trusted.
  1747. // If the caller requested that we return the WinVerifyTrust state data
  1748. // to them, then we can store that in their output buffer now.
  1749. //
  1750. if(hWVTStateData) {
  1751. *hWVTStateData = WintrustData.hWVTStateData;
  1752. //
  1753. // WinVerifyTrust state data handle successfully transferred to
  1754. // caller's output buffer. Clear it out of the WintrustData
  1755. // structure so we won't end up trying to free it twice in case of
  1756. // error.
  1757. //
  1758. WintrustData.hWVTStateData = NULL;
  1759. }
  1760. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1761. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1762. }
  1763. if(!UseAuthenticodePolicy && VersionInfo.pcSignerCertContext) {
  1764. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  1765. }
  1766. if((Err != ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) &&
  1767. (Err != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  1768. //
  1769. // If our error is NO_ERROR, then we shouldn't have WinVerifyTrust
  1770. // state data, because that indicates we validated using standard
  1771. // driver signing policy, not Authenticode policy.
  1772. //
  1773. MYASSERT((Err != NO_ERROR) || !hWVTStateData || !*hWVTStateData);
  1774. if(hWVTStateData && *hWVTStateData) {
  1775. pSetupCloseWVTStateData(*hWVTStateData);
  1776. *hWVTStateData = NULL;
  1777. //
  1778. // We'd better not also have a WinVerifyTrust state data handle in
  1779. // the WintrustData structure...
  1780. //
  1781. MYASSERT(!WintrustData.hWVTStateData);
  1782. }
  1783. }
  1784. if(WintrustData.hWVTStateData) {
  1785. pSetupCloseWVTStateData(WintrustData.hWVTStateData);
  1786. }
  1787. return Err;
  1788. }
  1789. VOID
  1790. pSetupCloseWVTStateData(
  1791. IN HANDLE hWVTStateData
  1792. )
  1793. /*++
  1794. Routine Description:
  1795. This routine closes the WinVerifyTrust state data handle returned from
  1796. certain routines (e.g., _VerifyCatalogFile) for prompting the user to
  1797. establish trust of an Authenticode publisher.
  1798. Arguments:
  1799. hWVTStateData - supplies the WinVerifyTrust state data handle to be closed.
  1800. Return Value:
  1801. None.
  1802. --*/
  1803. {
  1804. WINTRUST_DATA WintrustData;
  1805. ZeroMemory(&WintrustData, sizeof(WINTRUST_DATA));
  1806. WintrustData.cbStruct = sizeof(WINTRUST_DATA);
  1807. WintrustData.dwStateAction = WTD_STATEACTION_CLOSE;
  1808. WintrustData.hWVTStateData = hWVTStateData;
  1809. MYVERIFY(NO_ERROR == WinVerifyTrust(NULL,
  1810. &AuthenticodeVerifyGuid,
  1811. &WintrustData));
  1812. }
  1813. DWORD
  1814. pSetupUninstallCatalog(
  1815. IN LPCTSTR CatalogFilename
  1816. )
  1817. /*++
  1818. Routine Description:
  1819. This routine uninstalls a catalog, so it can no longer be used to validate
  1820. digital signatures.
  1821. Arguments:
  1822. CatalogFilename - supplies the simple filename of the catalog to be
  1823. uninstalled.
  1824. Return Value:
  1825. If successful, the return value is NO_ERROR.
  1826. If failure, the return value is a Win32 error code indicating the cause of
  1827. the failure.
  1828. --*/
  1829. {
  1830. DWORD Err;
  1831. HCATADMIN hCatAdmin;
  1832. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1833. return NO_ERROR;
  1834. }
  1835. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  1836. return TRUST_E_FAIL;
  1837. }
  1838. Err = GLE_FN_CALL(FALSE,
  1839. CryptCATAdminAcquireContext(&hCatAdmin,
  1840. &DriverVerifyGuid,
  1841. 0)
  1842. );
  1843. if(Err != NO_ERROR) {
  1844. return Err;
  1845. }
  1846. try {
  1847. Err = GLE_FN_CALL(FALSE,
  1848. CryptCATAdminRemoveCatalog(hCatAdmin,
  1849. CatalogFilename,
  1850. 0)
  1851. );
  1852. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1853. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1854. }
  1855. CryptCATAdminReleaseContext(hCatAdmin, 0);
  1856. return Err;
  1857. }
  1858. BOOL
  1859. pAnyDeviceUsingInf(
  1860. IN LPCTSTR InfFullPath,
  1861. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  1862. )
  1863. /*++
  1864. Routine Description:
  1865. This routine checks if any device, live or phantom, is using this INF file,
  1866. and logs if they are.
  1867. Arguments:
  1868. InfFullPath - supplies the full path of the INF.
  1869. LogContext - optionally, supplies the log context to be used if a device
  1870. using this INF is encountered.
  1871. Return Value:
  1872. TRUE if this INF is being used by any device, or if an error occurred (if
  1873. an error was encountered, we don't want to end up deleting the INF
  1874. erroneously.
  1875. FALSE if no devices are using this INF (and no errors were encountered).
  1876. --*/
  1877. {
  1878. DWORD Err;
  1879. HDEVINFO DeviceInfoSet;
  1880. SP_DEVINFO_DATA DeviceInfoData;
  1881. DWORD MemberIndex = 0;
  1882. HKEY hkey = INVALID_HANDLE_VALUE;
  1883. TCHAR CurrentDeviceInfFile[MAX_PATH];
  1884. DWORD cbSize, dwType;
  1885. PTSTR pInfFile;
  1886. //
  1887. // If we are passed a NULL InfFullPath or an enpty string then just return
  1888. // FALSE since nobody is using this.
  1889. //
  1890. if(!InfFullPath || (InfFullPath[0] == TEXT('\0'))) {
  1891. return FALSE;
  1892. }
  1893. pInfFile = (PTSTR)pSetupGetFileTitle(InfFullPath);
  1894. DeviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES);
  1895. if(DeviceInfoSet == INVALID_HANDLE_VALUE) {
  1896. //
  1897. // We can't retrieve a list of devices, hence we cannot make a
  1898. // determination of whether this inf is in-use. Safe thing to do is
  1899. // assume it is in-use...
  1900. //
  1901. return TRUE;
  1902. }
  1903. Err = NO_ERROR; // assume we won't find any devices using this INF.
  1904. try {
  1905. DeviceInfoData.cbSize = sizeof(DeviceInfoData);
  1906. while(SetupDiEnumDeviceInfo(DeviceInfoSet,
  1907. MemberIndex++,
  1908. &DeviceInfoData)) {
  1909. //
  1910. // Open the 'driver' key for this device.
  1911. //
  1912. hkey = SetupDiOpenDevRegKey(DeviceInfoSet,
  1913. &DeviceInfoData,
  1914. DICS_FLAG_GLOBAL,
  1915. 0,
  1916. DIREG_DRV,
  1917. KEY_READ);
  1918. if(hkey != INVALID_HANDLE_VALUE) {
  1919. cbSize = sizeof(CurrentDeviceInfFile);
  1920. dwType = REG_SZ;
  1921. if ((RegQueryValueEx(hkey,
  1922. pszInfPath,
  1923. NULL,
  1924. &dwType,
  1925. (LPBYTE)CurrentDeviceInfFile,
  1926. &cbSize) == ERROR_SUCCESS) &&
  1927. !lstrcmpi(CurrentDeviceInfFile, pInfFile)) {
  1928. //
  1929. // This key is using this INF file so the INF can't be
  1930. // deleted.
  1931. //
  1932. Err = ERROR_SHARING_VIOLATION; // any error will do
  1933. if(LogContext) {
  1934. TCHAR DeviceId[MAX_DEVICE_ID_LEN];
  1935. if(CM_Get_Device_ID(DeviceInfoData.DevInst,
  1936. DeviceId,
  1937. SIZECHARS(DeviceId),
  1938. 0
  1939. ) != CR_SUCCESS) {
  1940. DeviceId[0] = TEXT('\0');
  1941. }
  1942. WriteLogEntry(LogContext,
  1943. SETUP_LOG_WARNING,
  1944. MSG_LOG_INF_IN_USE,
  1945. NULL,
  1946. pInfFile,
  1947. DeviceId
  1948. );
  1949. }
  1950. }
  1951. RegCloseKey(hkey);
  1952. hkey = INVALID_HANDLE_VALUE;
  1953. }
  1954. }
  1955. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1956. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1957. }
  1958. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  1959. if(hkey != INVALID_HANDLE_VALUE) {
  1960. RegCloseKey(hkey);
  1961. }
  1962. return (Err != NO_ERROR);
  1963. }
  1964. VOID
  1965. pSetupUninstallOEMInf(
  1966. IN LPCTSTR InfFullPath,
  1967. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1968. IN DWORD Flags,
  1969. OUT PDWORD InfDeleteErr OPTIONAL
  1970. )
  1971. /*++
  1972. Routine Description:
  1973. This routine uninstalls a 3rd-party INF, PNF, and CAT (if one exists). It
  1974. can also be used to uninstall an exception package INF, PNF, and CAT.
  1975. By default this routine will first verify that there aren't any other
  1976. device's, live and phantom, that are pointing their InfPath to this
  1977. INF. This behavior can be overridden by the SUOI_FORCEDELETE flag.
  1978. Arguments:
  1979. InfFullPath - supplies the full path of the INF to be uninstalled.
  1980. LogContext - optionally, supplies the log context to be used if we
  1981. encounter an error when attempting to delete the catalog.
  1982. Flags - the following flags are supported:
  1983. SUOI_FORCEDELETE - delete the INF even if other driver keys are
  1984. have their InfPath pointing to it.
  1985. InfDeleteErr - optionally, supplies the address of a variable that receives
  1986. the error (if any) encountered when attempting to delete the INF.
  1987. Note that we delete the INF last (to avoid race conditions), so the
  1988. corresponding CAT and PNF may have already been deleted at this point.
  1989. Return Value:
  1990. None.
  1991. --*/
  1992. {
  1993. DWORD Err;
  1994. TCHAR FileNameBuffer[MAX_PATH+4]; // +4 in case filename is blahblah. not blahblah.inf
  1995. BOOL FreeLogContext = FALSE;
  1996. LPTSTR ExtPtr= NULL;
  1997. HINF hInf = INVALID_HANDLE_VALUE;
  1998. if(!LogContext) {
  1999. if(NO_ERROR == CreateLogContext(NULL, TRUE, &LogContext)) {
  2000. //
  2001. // Remember that we created this log context locally, so we can
  2002. // free it when we're done with this routine.
  2003. //
  2004. FreeLogContext = TRUE;
  2005. } else {
  2006. //
  2007. // Ensure LogContext is still NULL so we won't try to use it.
  2008. //
  2009. LogContext = NULL;
  2010. }
  2011. }
  2012. try {
  2013. //
  2014. // Make sure the specified INF is in %windir%\Inf, and that it's an OEM
  2015. // INF (i.e, filename is OEM<n>.INF).
  2016. //
  2017. if(pSetupInfIsFromOemLocation(InfFullPath, TRUE)) {
  2018. Err = ERROR_NOT_AN_INSTALLED_OEM_INF;
  2019. goto LogAnyUninstallErrors;
  2020. } else if(!IsInstalledFileFromOem(pSetupGetFileTitle(InfFullPath), OemFiletypeInf)) {
  2021. BOOL IsExceptionInf = FALSE;
  2022. GUID ClassGuid;
  2023. //
  2024. // The INF is in %windir%\Inf, but is not of the form oem<n>.inf.
  2025. // It may still be OK to uninstall it, if it's an exception INF...
  2026. //
  2027. hInf = SetupOpenInfFile(InfFullPath, NULL, INF_STYLE_WIN4, NULL);
  2028. if(hInf != INVALID_HANDLE_VALUE) {
  2029. //
  2030. // We don't need to lock the INF because it'll never be
  2031. // accessible outside of this routine.
  2032. //
  2033. if(ClassGuidFromInfVersionNode(&(((PLOADED_INF)hInf)->VersionBlock), &ClassGuid)
  2034. && IsEqualGUID(&ClassGuid, &GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER)) {
  2035. IsExceptionInf = TRUE;
  2036. }
  2037. //
  2038. // Close the INF handle now so we won't still have it open if
  2039. // we end up deleting the INF.
  2040. //
  2041. SetupCloseInfFile(hInf);
  2042. hInf = INVALID_HANDLE_VALUE; // no need to close if we hit an exception
  2043. }
  2044. if(!IsExceptionInf) {
  2045. Err = ERROR_NOT_AN_INSTALLED_OEM_INF;
  2046. goto LogAnyUninstallErrors;
  2047. }
  2048. }
  2049. //
  2050. // Unless the caller passed in the SUOI_FORCEDELETE flag first check
  2051. // that no devices are using this INF file.
  2052. //
  2053. if(!(Flags & SUOI_FORCEDELETE) &&
  2054. pAnyDeviceUsingInf(InfFullPath, LogContext)) {
  2055. //
  2056. // Some device is still using this INF so we can't delete it.
  2057. //
  2058. Err = ERROR_INF_IN_USE_BY_DEVICES;
  2059. goto LogAnyUninstallErrors;
  2060. }
  2061. //
  2062. // Copy the caller-supplied INF name into a local buffer, so we can
  2063. // modify it when deleting the various files (INF, PNF, and CAT).
  2064. //
  2065. if(FAILED(StringCchCopy(FileNameBuffer, SIZECHARS(FileNameBuffer), InfFullPath))) {
  2066. //
  2067. // This error would be returned by DeleteFile if we let it go
  2068. // through.
  2069. //
  2070. Err = ERROR_PATH_NOT_FOUND;
  2071. goto LogAnyUninstallErrors;
  2072. }
  2073. //
  2074. // Uninstall the catalog (if any) first, because as soon as we delete
  2075. // the INF, that slot is "open" for use by another INF, and we wouldn't
  2076. // want to inadvertently delete someone else's catalog due to a race
  2077. // condition.
  2078. //
  2079. ExtPtr = _tcsrchr(FileNameBuffer, TEXT('.'));
  2080. MYASSERT(ExtPtr); // we already validated the filename's format
  2081. if(FAILED(StringCchCopy(ExtPtr,
  2082. SIZECHARS(FileNameBuffer)-(ExtPtr-FileNameBuffer),
  2083. pszCatSuffix))) {
  2084. Err = ERROR_BUFFER_OVERFLOW;
  2085. } else {
  2086. Err = pSetupUninstallCatalog(pSetupGetFileTitle(FileNameBuffer));
  2087. }
  2088. if((Err != NO_ERROR) && LogContext) {
  2089. //
  2090. // It's kinda important that we were unable to delete the catalog,
  2091. // but not important enough to fail the routine. Log this fact to
  2092. // setupapi.log...
  2093. //
  2094. WriteLogEntry(LogContext,
  2095. DEL_ERR_LOG_LEVEL(Err) | SETUP_LOG_BUFFER,
  2096. MSG_LOG_OEM_CAT_UNINSTALL_FAILED,
  2097. NULL,
  2098. pSetupGetFileTitle(FileNameBuffer)
  2099. );
  2100. WriteLogError(LogContext,
  2101. DEL_ERR_LOG_LEVEL(Err),
  2102. Err
  2103. );
  2104. }
  2105. //
  2106. // Now delete the PNF (we don't care so much if this succeeds or
  2107. // fails)...
  2108. //
  2109. if(SUCCEEDED(StringCchCopy(ExtPtr,
  2110. SIZECHARS(FileNameBuffer)-(ExtPtr-FileNameBuffer),
  2111. pszPnfSuffix))) {
  2112. SetFileAttributes(FileNameBuffer, FILE_ATTRIBUTE_NORMAL);
  2113. DeleteFile(FileNameBuffer);
  2114. }
  2115. //
  2116. // and finally the INF itself...
  2117. //
  2118. SetFileAttributes(InfFullPath, FILE_ATTRIBUTE_NORMAL);
  2119. Err = GLE_FN_CALL(FALSE, DeleteFile(InfFullPath));
  2120. LogAnyUninstallErrors:
  2121. if((Err != NO_ERROR) && LogContext) {
  2122. WriteLogEntry(LogContext,
  2123. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  2124. MSG_LOG_OEM_INF_UNINSTALL_FAILED,
  2125. NULL,
  2126. InfFullPath
  2127. );
  2128. WriteLogError(LogContext,
  2129. SETUP_LOG_ERROR,
  2130. Err
  2131. );
  2132. }
  2133. if(InfDeleteErr) {
  2134. *InfDeleteErr = Err;
  2135. }
  2136. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2137. pSetupExceptionHandler(GetExceptionCode(),
  2138. ERROR_INVALID_PARAMETER,
  2139. InfDeleteErr
  2140. );
  2141. if(hInf != INVALID_HANDLE_VALUE) {
  2142. SetupCloseInfFile(hInf);
  2143. }
  2144. }
  2145. if(FreeLogContext) {
  2146. DeleteLogContext(LogContext);
  2147. }
  2148. }
  2149. DWORD
  2150. _VerifyFile(
  2151. IN PSETUP_LOG_CONTEXT LogContext,
  2152. IN OUT PVERIFY_CONTEXT VerifyContext, OPTIONAL
  2153. IN LPCTSTR Catalog, OPTIONAL
  2154. IN PVOID CatalogBaseAddress, OPTIONAL
  2155. IN DWORD CatalogImageSize,
  2156. IN LPCTSTR Key,
  2157. IN LPCTSTR FileFullPath,
  2158. OUT SetupapiVerifyProblem *Problem, OPTIONAL
  2159. OUT LPTSTR ProblemFile, OPTIONAL
  2160. IN BOOL CatalogAlreadyVerified,
  2161. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  2162. IN DWORD Flags, OPTIONAL
  2163. OUT LPTSTR CatalogFileUsed, OPTIONAL
  2164. OUT PDWORD NumCatalogsConsidered, OPTIONAL
  2165. OUT LPTSTR DigitalSigner, OPTIONAL
  2166. OUT LPTSTR SignerVersion, OPTIONAL
  2167. OUT HANDLE *hWVTStateData OPTIONAL
  2168. )
  2169. /*++
  2170. Routine Description:
  2171. This routine verifies a single file against a particular catalog file, or
  2172. against any installed catalog file.
  2173. Arguments:
  2174. LogContext - supplies the context to be used when logging information about
  2175. the routine's activities.
  2176. VerifyContext - optionally, supplies the address of a structure that caches
  2177. various verification context handles. These handles may be NULL (if
  2178. not previously acquired, and they may be filled in upon return (in
  2179. either success or failure) if they were acquired during the processing
  2180. of this verification request. It is the caller's responsibility to
  2181. free these various context handles when they are no longer needed by
  2182. calling pSetupFreeVerifyContextMembers.
  2183. Catalog - optionally, supplies the path of the catalog file to be used for
  2184. the verification. If this argument is not specified, then this routine
  2185. will attempt to find a catalog that can verify it from among all
  2186. catalogs installed in the system.
  2187. If this path is a simple filename (no path components), then we'll look
  2188. up that catalog file in the CatAdmin's list of installed catalogs, else
  2189. we'll use the name as-is.
  2190. CatalogBaseAddress - optionally, supplies the address of a buffer
  2191. containing the entire catalog image with which our enumerated catalog
  2192. must match before being considered a correct validation. This is used
  2193. when copying OEM INFs, for example, when there may be multiple
  2194. installed catalogs that can validate an INF, but we want to make sure
  2195. that we pick _the_ catalog that matches the one we're contemplating
  2196. installing before we'll consider our INF/CAT files to be duplicates of
  2197. the previously-existing files.
  2198. This parameter (and its partner, CatalogImageSize) are only used when
  2199. Catalog doesn't specify a file path.
  2200. CatalogImageSize - if CatalogBaseAddress is specified, this parameter give
  2201. the size, in bytes, of that buffer.
  2202. Key - supplies a value that "indexes" the catalog, telling the verify APIs
  2203. which signature datum within the catalog it should use. Typically
  2204. the key is the (original) filename of a file.
  2205. FileFullPath - supplies the full path of the file to be verified.
  2206. Problem - if supplied, this parameter points to a variable that will be
  2207. filled in upon unsuccessful return with the cause of failure. If this
  2208. parameter is not supplied, then the ProblemFile parameter is ignored.
  2209. ProblemFile - if supplied, this parameter points to a character buffer of
  2210. at least MAX_PATH characters that receives the name of the file for
  2211. which a verification error occurred (the contents of this buffer are
  2212. undefined if verification succeeds.
  2213. If the Problem parameter is supplied, then the ProblemFile parameter
  2214. must also be specified.
  2215. CatalogAlreadyVerified - if TRUE, then verification won't be done on the
  2216. catalog--we'll just use that catalog to validate the file of interest.
  2217. If this is TRUE, then Catalog must be specified, must contain the path
  2218. to the catalog file (i.e., it can't be a simple filename).
  2219. ** This flag is ignored when validating via Authenticode policy--the **
  2220. ** catalog is always verified. **
  2221. AltPlatformInfo - optionally, supplies alternate platform information used
  2222. to fill in a DRIVER_VER_INFO structure (defined in sdk\inc\softpub.h)
  2223. that is passed to WinVerifyTrust.
  2224. ** NOTE: This structure _must_ have its cbSize field set to **
  2225. ** sizeof(SP_ALTPLATFORM_INFO_V2) -- validation on client-supplied **
  2226. ** buffer is the responsibility of the caller. **
  2227. Flags - supplies flags that alter that behavior of this routine. May be a
  2228. combination of the following values:
  2229. VERIFY_FILE_IGNORE_SELFSIGNED - if this bit is set, then this routine
  2230. will fail validation for self-signed
  2231. binaries.
  2232. VERIFY_FILE_USE_OEM_CATALOGS - if this bit is set, then all catalogs
  2233. installed in the system will be scanned
  2234. to verify the given file. Otherwise,
  2235. OEM (3rd party) catalogs will NOT be
  2236. scanned to verify the given file. This
  2237. is only applicable if a catalog is not
  2238. specified.
  2239. VERIFY_FILE_USE_AUTHENTICODE_CATALOG - Validate the file using a
  2240. catalog signed with Authenticode
  2241. policy. If this flag is set,
  2242. we'll _only_ check for
  2243. Authenticode signatures, so if
  2244. the caller wants to first try
  2245. validating a file for OS code-
  2246. signing usage, then falling back
  2247. to Authenticode, they'll have to
  2248. call this routine twice.
  2249. If this flag is set, then the
  2250. caller may also supply the
  2251. hWVTStateData output parameter,
  2252. which can be used to prompt user
  2253. in order to establish that the
  2254. publisher should be trusted.
  2255. _VerifyFile will return one of
  2256. two error codes upon successful
  2257. validation via Authenticode
  2258. policy. Refer to the "Return
  2259. Value" section for details.
  2260. VERIFY_FILE_DRIVERBLOCKED_ONLY - Only check if the file is in the bad
  2261. driver database, don't do any digital
  2262. sigature validation.
  2263. VERIFY_FILE_NO_DRIVERBLOCKED_CHECK - Don't check if the file is blocked
  2264. via the Bad Driver Database.
  2265. CatalogFileUsed - if supplied, this parameter points to a character buffer
  2266. at least MAX_PATH characters big that receives the name of the catalog
  2267. file used to verify the specified file. This is only filled in upon
  2268. successful return, or when the Problem is SetupapiVerifyFileProblem
  2269. (i.e., the catalog verified, but the file did not). If this buffer is
  2270. set to the empty string upon a SetupapiVerifyFileProblem failure, then
  2271. we didn't find any applicable catalogs to use for validation.
  2272. Also, this buffer will contain an empty string upon successful return
  2273. if the file was validated without using a catalog (i.e., the file
  2274. contains its own signature).
  2275. NumCatalogsConsidered - if supplied, this parameter receives a count of the
  2276. number of catalogs against which verification was attempted. Of course,
  2277. if Catalog is specified, this number will always be either zero or one.
  2278. DigitalSigner - if supplied, this parameter points to a character buffer of
  2279. at least MAX_PATH characters that receives the name of who digitally
  2280. signed the specified file. This value is only set if the Key is
  2281. correctly signed (i.e. the function returns NO_ERROR).
  2282. ** This parameter should not be supplied when validating using **
  2283. ** Authenticode policy. Information about signer, date, etc., may **
  2284. ** be acquired from the hWVTStateData in that case. **
  2285. SignerVersion - if supplied, this parameter points to a character buffer of
  2286. at least MAX_PATH characters that receives the signer version as
  2287. returned in the szwVerion field of the DRIVER_VER_INFO structure in our
  2288. call to WinVerifyTrust.
  2289. ** This parameter should not be supplied when validating using **
  2290. ** Authenticode policy. Information about signer, date, etc., may **
  2291. ** be acquired from the hWVTStateData in that case. **
  2292. hWVTStateData - if supplied, this parameter points to a buffer that
  2293. receives a handle to WinVerifyTrust state data. This handle will be
  2294. returned only when validation was successfully performed using
  2295. Authenticode policy. This handle may be used, for example, to retrieve
  2296. signer info when prompting the user about whether they trust the
  2297. publisher. (The status code returned will indicate whether or not this
  2298. is necessary, see "Return Value" section below.)
  2299. This parameter should only be supplied if the
  2300. VERIFY_FILE_USE_AUTHENTICODE_CATALOG bit is set in the supplied Flags.
  2301. If the routine fails, then this handle will be set to NULL.
  2302. It is the caller's responsibility to close this handle when they're
  2303. finished with it by calling pSetupCloseWVTStateData().
  2304. Return Value:
  2305. If the file was successfully validated via driver signing policy (or we
  2306. didn't perform digital signature verification and everything else
  2307. succeeded), then the return value is NO_ERROR.
  2308. If the file was successfully validated via Authenticode policy, and the
  2309. publisher was in the TrustedPublisher store, then the return value is
  2310. ERROR_AUTHENTICODE_TRUSTED_PUBLISHER.
  2311. If the file was successfully validated via Authenticode policy, and the
  2312. publisher was not in the TrustedPublisher store (hence we must prompt the
  2313. user to establish their trust of the publisher), then the return value is
  2314. ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED
  2315. If a failure occurred, the return value is a Win32 error code indicating
  2316. the cause of the failure.
  2317. --*/
  2318. {
  2319. LPBYTE Hash;
  2320. DWORD HashSize;
  2321. CATALOG_INFO CatInfo;
  2322. HANDLE hFile;
  2323. HCATINFO hCatInfo;
  2324. HCATINFO PrevCat;
  2325. DWORD Err, AuthenticodeErr;
  2326. WINTRUST_DATA WintrustData;
  2327. WINTRUST_CATALOG_INFO WintrustCatalogInfo;
  2328. WINTRUST_FILE_INFO WintrustFileInfo;
  2329. DRIVER_VER_INFO VersionInfo;
  2330. LPTSTR CatalogFullPath;
  2331. WCHAR UnicodeKey[MAX_PATH];
  2332. WIN32_FILE_ATTRIBUTE_DATA FileAttribData;
  2333. BOOL FoundMatchingImage;
  2334. DWORD CurCatFileSize;
  2335. HANDLE CurCatFileHandle, CurCatMappingHandle;
  2336. PVOID CurCatBaseAddress;
  2337. BOOL LoggedWarning;
  2338. BOOL TrySelfSign;
  2339. DWORD AltPlatSlot;
  2340. TAGREF tagref;
  2341. HCATADMIN LocalhCatAdmin;
  2342. HSDB LocalhSDBDrvMain;
  2343. BOOL UseAuthenticodePolicy = Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG;
  2344. //
  2345. // Initialize the CatalogFileUsed parameter to an empty string (i.e., no
  2346. // applicable catalog at this point).
  2347. //
  2348. if(CatalogFileUsed) {
  2349. *CatalogFileUsed = TEXT('\0');
  2350. }
  2351. //
  2352. // Initialize the output counter indicating the number of catalog files we
  2353. // processed during the attempted verification.
  2354. //
  2355. if(NumCatalogsConsidered) {
  2356. *NumCatalogsConsidered = 0;
  2357. }
  2358. //
  2359. // Initialize the output handle for WinVerifyTrust state data.
  2360. //
  2361. if(hWVTStateData) {
  2362. *hWVTStateData = NULL;
  2363. }
  2364. //
  2365. // If Authenticode validation is requested, then the caller shouldn't have
  2366. // passed in the DigitalSigner and SignerVersion output parameters.
  2367. //
  2368. MYASSERT(!UseAuthenticodePolicy || (!DigitalSigner && !SignerVersion));
  2369. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  2370. //
  2371. // The old behavior of this API in the ANSI case where the crypto
  2372. // APIs weren't available was to set the CatalogFileUsed OUT param to
  2373. // an empty string and report NO_ERROR. We'll do the same thing here
  2374. // (but we'll also assert, because no external callers should care, and
  2375. // if they do, an empty string probably isn't going to make them very
  2376. // happy).
  2377. //
  2378. MYASSERT(!CatalogFileUsed);
  2379. MYASSERT(!NumCatalogsConsidered);
  2380. //
  2381. // We'd better not be called in minimal embedded scenarios where we're
  2382. // asked to provide signer info...
  2383. //
  2384. MYASSERT(!DigitalSigner);
  2385. MYASSERT(!SignerVersion);
  2386. //
  2387. // Likewise, we'd better not be called asking to validate using
  2388. // Authenticode policy (and hence, to return WinVerifyTrust state data
  2389. // regarding the signing certificate).
  2390. //
  2391. MYASSERT(!UseAuthenticodePolicy);
  2392. return NO_ERROR;
  2393. }
  2394. //
  2395. // If the caller requested that we return WinVerifyTrust state data upon
  2396. // successful Authenticode validation, then they'd better have actually
  2397. // requested Authenticode validation!
  2398. //
  2399. MYASSERT(!hWVTStateData || UseAuthenticodePolicy);
  2400. //
  2401. // Doesn't make sense to have both these flags set!
  2402. //
  2403. MYASSERT((Flags & (VERIFY_FILE_DRIVERBLOCKED_ONLY | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK))
  2404. != (VERIFY_FILE_DRIVERBLOCKED_ONLY | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK)
  2405. );
  2406. //
  2407. // If Problem is supplied, then ProblemFile must also be supplied.
  2408. //
  2409. MYASSERT(!Problem || ProblemFile);
  2410. //
  2411. // If the caller claims to have already verified the catalog file, make
  2412. // sure they passed us the full path to one.
  2413. //
  2414. MYASSERT(!CatalogAlreadyVerified || (Catalog && (Catalog != pSetupGetFileTitle(Catalog))));
  2415. //
  2416. // If a catalog image is specified, we'd better have been given a size.
  2417. //
  2418. MYASSERT((CatalogBaseAddress && CatalogImageSize) ||
  2419. !(CatalogBaseAddress || CatalogImageSize));
  2420. //
  2421. // If a catalog image was supplied for comparison, there shouldn't be a
  2422. // file path specified in the Catalog parameter.
  2423. //
  2424. MYASSERT(!CatalogBaseAddress || !(Catalog && (Catalog != pSetupGetFileTitle(Catalog))));
  2425. //
  2426. // OK, preliminary checking is over--prepare to enter try/except block...
  2427. //
  2428. hFile = INVALID_HANDLE_VALUE;
  2429. Hash = NULL;
  2430. LoggedWarning = FALSE;
  2431. TrySelfSign = FALSE;
  2432. AltPlatSlot = 0;
  2433. tagref = TAGREF_NULL;
  2434. LocalhCatAdmin = NULL;
  2435. LocalhSDBDrvMain = NULL;
  2436. hCatInfo = NULL;
  2437. AuthenticodeErr = NO_ERROR;
  2438. //
  2439. // Go ahead and initialize the VersionInfo structure as well.
  2440. // WinVerifyTrust will sometimes fill in the pcSignerCertContext field with
  2441. // a cert context that must be freed, and we don't want to introduce the
  2442. // possibility of leaking this if we hit an exception at an inopportune
  2443. // moment. (We don't need to do this for Authenticode verification,
  2444. // because Authenticode pays no attention to the driver version info.)
  2445. //
  2446. if(!UseAuthenticodePolicy) {
  2447. ZeroMemory(&VersionInfo, sizeof(DRIVER_VER_INFO));
  2448. VersionInfo.cbStruct = sizeof(DRIVER_VER_INFO);
  2449. }
  2450. try {
  2451. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  2452. if(Problem) {
  2453. *Problem = SetupapiVerifyAutoFailProblem;
  2454. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  2455. }
  2456. Err = TRUST_E_FAIL;
  2457. leave;
  2458. }
  2459. if(AltPlatformInfo) {
  2460. AltPlatSlot = AllocLogInfoSlotOrLevel(LogContext,SETUP_LOG_VERBOSE,FALSE);
  2461. WriteLogEntry(LogContext,
  2462. AltPlatSlot,
  2463. MSG_LOG_VERIFYFILE_ALTPLATFORM,
  2464. NULL, // text message
  2465. AltPlatformInfo->Platform,
  2466. AltPlatformInfo->MajorVersion,
  2467. AltPlatformInfo->MinorVersion,
  2468. AltPlatformInfo->FirstValidatedMajorVersion,
  2469. AltPlatformInfo->FirstValidatedMinorVersion
  2470. );
  2471. }
  2472. if(VerifyContext && VerifyContext->hCatAdmin) {
  2473. LocalhCatAdmin = VerifyContext->hCatAdmin;
  2474. } else {
  2475. Err = GLE_FN_CALL(FALSE,
  2476. CryptCATAdminAcquireContext(&LocalhCatAdmin,
  2477. &DriverVerifyGuid,
  2478. 0)
  2479. );
  2480. if(Err != NO_ERROR) {
  2481. //
  2482. // Failure encountered--ensure local handle is still NULL.
  2483. //
  2484. LocalhCatAdmin = NULL;
  2485. if(Problem) {
  2486. //
  2487. // We failed too early to blame the file as the problem,
  2488. // but it's the only filename we currently have to return
  2489. // as the problematic file.
  2490. //
  2491. *Problem = SetupapiVerifyFileProblem;
  2492. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  2493. }
  2494. leave;
  2495. }
  2496. //
  2497. // If requested, store the handle to be returned to the caller.
  2498. //
  2499. if(VerifyContext) {
  2500. VerifyContext->hCatAdmin = LocalhCatAdmin;
  2501. }
  2502. }
  2503. //
  2504. // Calculate the hash value for the inf.
  2505. //
  2506. Err = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  2507. hFile = CreateFile(FileFullPath,
  2508. GENERIC_READ,
  2509. FILE_SHARE_READ,
  2510. NULL,
  2511. OPEN_EXISTING,
  2512. 0,
  2513. NULL)
  2514. );
  2515. if(Err != NO_ERROR) {
  2516. if(Problem) {
  2517. *Problem = SetupapiVerifyFileProblem;
  2518. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  2519. }
  2520. leave;
  2521. }
  2522. //
  2523. // Only check if the driver is in the defective driver database if we
  2524. // are NOT in GUI setup, and the caller has NOT passed in the
  2525. // VERIFY_FILE_NO_DRIVERBLOCKED_CHECK flag.
  2526. //
  2527. if(!GuiSetupInProgress &&
  2528. !(Flags & VERIFY_FILE_NO_DRIVERBLOCKED_CHECK)) {
  2529. //
  2530. // Shim database APIs have been known to crash from time to time,
  2531. // so guard ourselves against that because failure to do a lookup
  2532. // in the bad driver database should not result in a verification
  2533. // failure.
  2534. //
  2535. try {
  2536. if(VerifyContext && VerifyContext->hSDBDrvMain) {
  2537. LocalhSDBDrvMain = VerifyContext->hSDBDrvMain;
  2538. } else {
  2539. LocalhSDBDrvMain = SdbInitDatabaseEx(SDB_DATABASE_MAIN_DRIVERS,
  2540. NULL,
  2541. DEFAULT_IMAGE
  2542. );
  2543. if(LocalhSDBDrvMain) {
  2544. //
  2545. // If requested, store the handle to be returned to the
  2546. // caller.
  2547. //
  2548. if(VerifyContext) {
  2549. VerifyContext->hSDBDrvMain = LocalhSDBDrvMain;
  2550. }
  2551. } else {
  2552. //
  2553. // Log a warning that we couldn't access the bad driver
  2554. // database to check if this is a blocked driver.
  2555. // (SdbInitDatabase doesn't set last error, so we don't
  2556. // know why this failed--only that it did.)
  2557. //
  2558. WriteLogEntry(LogContext,
  2559. SETUP_LOG_WARNING,
  2560. MSG_LOG_CANT_ACCESS_BDD,
  2561. NULL,
  2562. FileFullPath
  2563. );
  2564. }
  2565. }
  2566. //
  2567. // Check the bad driver database to see if this file is blocked.
  2568. //
  2569. if(LocalhSDBDrvMain) {
  2570. tagref = SdbGetDatabaseMatch(LocalhSDBDrvMain,
  2571. Key,
  2572. hFile,
  2573. NULL,
  2574. 0);
  2575. if(tagref != TAGREF_NULL) {
  2576. //
  2577. // Read the driver policy to see if this should be
  2578. // blocked by usermode or not.
  2579. // If the 1st bit is set then this should NOT be blocked
  2580. // by usermode.
  2581. //
  2582. ULONG type, size, policy;
  2583. size = sizeof(policy);
  2584. policy = 0;
  2585. type = REG_DWORD;
  2586. if(SdbQueryDriverInformation(LocalhSDBDrvMain,
  2587. tagref,
  2588. TEXT("Policy"),
  2589. &type,
  2590. &policy,
  2591. &size) != ERROR_SUCCESS) {
  2592. //
  2593. // If we can't read the policy then default to 0.
  2594. // This means we will block in usermode!
  2595. //
  2596. policy = 0;
  2597. }
  2598. if(!(policy & DDB_DRIVER_POLICY_SETUP_NO_BLOCK_BIT)) {
  2599. //
  2600. // This driver is in the database and needs to be
  2601. // blocked!
  2602. //
  2603. WriteLogEntry(LogContext,
  2604. SETUP_LOG_VERBOSE,
  2605. MSG_LOG_DRIVER_BLOCKED_ERROR,
  2606. NULL,
  2607. FileFullPath
  2608. );
  2609. LoggedWarning = TRUE;
  2610. if(Problem) {
  2611. *Problem = SetupapiVerifyDriverBlocked;
  2612. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  2613. }
  2614. Err = ERROR_DRIVER_BLOCKED;
  2615. leave;
  2616. }
  2617. }
  2618. }
  2619. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2620. pSetupExceptionHandler(GetExceptionCode(),
  2621. ERROR_INVALID_PARAMETER,
  2622. &Err
  2623. );
  2624. WriteLogEntry(LogContext,
  2625. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  2626. MSG_LOG_CANT_ACCESS_BDD_EXCEPTION,
  2627. NULL,
  2628. FileFullPath
  2629. );
  2630. WriteLogError(LogContext, SETUP_LOG_WARNING, Err);
  2631. }
  2632. }
  2633. //
  2634. // If the caller only wanted to check if the file was in the bad driver
  2635. // database then we are done.
  2636. //
  2637. if(Flags & VERIFY_FILE_DRIVERBLOCKED_ONLY) {
  2638. Err = NO_ERROR;
  2639. leave;
  2640. }
  2641. //
  2642. // Initialize some of the structures that will be used later on
  2643. // in calls to WinVerifyTrust. We don't know if we're verifying
  2644. // against a catalog or against a file yet.
  2645. //
  2646. ZeroMemory(&WintrustData, sizeof(WINTRUST_DATA));
  2647. WintrustData.cbStruct = sizeof(WINTRUST_DATA);
  2648. WintrustData.dwUIChoice = WTD_UI_NONE;
  2649. WintrustData.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
  2650. WTD_CACHE_ONLY_URL_RETRIEVAL;
  2651. if(!UseAuthenticodePolicy) {
  2652. //
  2653. // We only supply a driver version info structure if we're doing
  2654. // validation via driver signing policy. Authenticode completely
  2655. // ignores this...
  2656. //
  2657. if(AltPlatformInfo) {
  2658. MYASSERT(AltPlatformInfo->cbSize == sizeof(SP_ALTPLATFORM_INFO_V2));
  2659. //
  2660. // Caller wants the file validated for an alternate
  2661. // platform, so we must fill in a DRIVER_VER_INFO structure
  2662. // to be passed to the policy module.
  2663. //
  2664. VersionInfo.dwPlatform = AltPlatformInfo->Platform;
  2665. VersionInfo.dwVersion = AltPlatformInfo->MajorVersion;
  2666. VersionInfo.sOSVersionLow.dwMajor = AltPlatformInfo->FirstValidatedMajorVersion;
  2667. VersionInfo.sOSVersionLow.dwMinor = AltPlatformInfo->FirstValidatedMinorVersion;
  2668. VersionInfo.sOSVersionHigh.dwMajor = AltPlatformInfo->MajorVersion;
  2669. VersionInfo.sOSVersionHigh.dwMinor = AltPlatformInfo->MinorVersion;
  2670. } else {
  2671. //
  2672. // If an AltPlatformInfo was not passed in then set the
  2673. // WTD_USE_DEFAULT_OSVER_CHECK flag. This flag tells
  2674. // WinVerifyTrust to use its default osversion checking, even
  2675. // though a DRIVER_VER_INFO structure was passed in.
  2676. //
  2677. WintrustData.dwProvFlags |= WTD_USE_DEFAULT_OSVER_CHECK;
  2678. }
  2679. //
  2680. // Specify a DRIVER_VER_INFO structure so we can get back
  2681. // who signed the file and the signer version information.
  2682. // If we don't have an AltPlatformInfo then set the
  2683. // WTD_USE_DEFAULT_OSVER_CHECK flag so that WinVerifyTrust will do
  2684. // its default checking, just as if a DRIVER_VER_INFO structure
  2685. // was not passed in.
  2686. //
  2687. WintrustData.pPolicyCallbackData = (PVOID)&VersionInfo;
  2688. //
  2689. // "auto-cache" feature only works for driver signing policy...
  2690. //
  2691. WintrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE;
  2692. }
  2693. //
  2694. // Compute the cryptographic hash for the file. If we fail to compute
  2695. // this hash, we want to bail immediately. We don't want to attempt to
  2696. // fallback to self-signed binaries, because in the future the hash may
  2697. // be used to revoke a signature, and we wouldn't want to automatically
  2698. // trust a self-signed binary in that case.
  2699. //
  2700. HashSize = 100; // start out with a reasonable size for most requests.
  2701. do {
  2702. Hash = MyMalloc(HashSize);
  2703. if(!Hash) {
  2704. Err = ERROR_NOT_ENOUGH_MEMORY;
  2705. } else {
  2706. Err = GLE_FN_CALL(FALSE,
  2707. CryptCATAdminCalcHashFromFileHandle(hFile,
  2708. &HashSize,
  2709. Hash,
  2710. 0)
  2711. );
  2712. }
  2713. if(Err != NO_ERROR) {
  2714. if(Hash) {
  2715. MyFree(Hash);
  2716. Hash = NULL;
  2717. }
  2718. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  2719. //
  2720. // We failed for some reason other than buffer-too-small.
  2721. //
  2722. WriteLogEntry(LogContext,
  2723. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  2724. MSG_LOG_HASH_ERROR,
  2725. NULL,
  2726. FileFullPath,
  2727. Catalog ? Catalog : TEXT(""),
  2728. Key
  2729. );
  2730. WriteLogError(LogContext, SETUP_LOG_WARNING, Err);
  2731. LoggedWarning = TRUE;
  2732. if(Problem) {
  2733. *Problem = SetupapiVerifyFileProblem;
  2734. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  2735. }
  2736. leave;
  2737. }
  2738. }
  2739. } while(Err != NO_ERROR);
  2740. //
  2741. // Now we have the file's hash. Initialize the structures that will be
  2742. // used later on in calls to WinVerifyTrust.
  2743. //
  2744. WintrustData.dwUnionChoice = WTD_CHOICE_CATALOG;
  2745. WintrustData.pCatalog = &WintrustCatalogInfo;
  2746. ZeroMemory(&WintrustCatalogInfo, sizeof(WINTRUST_CATALOG_INFO));
  2747. WintrustCatalogInfo.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
  2748. WintrustCatalogInfo.pbCalculatedFileHash = Hash;
  2749. WintrustCatalogInfo.cbCalculatedFileHash = HashSize;
  2750. //
  2751. // WinVerifyTrust is case-sensitive, so ensure that the key being used
  2752. // is all lower-case. (We copy the key to a writable Unicode character
  2753. // buffer so we can lower-case it.)
  2754. //
  2755. StringCchCopy(UnicodeKey, SIZECHARS(UnicodeKey), Key);
  2756. CharLower(UnicodeKey);
  2757. WintrustCatalogInfo.pcwszMemberTag = UnicodeKey;
  2758. if(Catalog && (Catalog != pSetupGetFileTitle(Catalog))) {
  2759. //
  2760. // We know in this case we're always going to examine exactly one
  2761. // catalog.
  2762. //
  2763. if(NumCatalogsConsidered) {
  2764. *NumCatalogsConsidered = 1;
  2765. }
  2766. //
  2767. // Fill in the catalog information since we know which catalog
  2768. // we're going to be using...
  2769. //
  2770. WintrustCatalogInfo.pcwszCatalogFilePath = Catalog;
  2771. //
  2772. // The caller supplied the path to the catalog file to be used for
  2773. // verification--we're ready to go! First, verify the catalog
  2774. // (unless the caller already did it), and if that succeeds, then
  2775. // verify the file.
  2776. //
  2777. if(!CatalogAlreadyVerified || UseAuthenticodePolicy) {
  2778. //
  2779. // Before validating the catalog, we'll flush the crypto cache.
  2780. // Otherwise, it can get fooled when validating against a
  2781. // catalog at a specific location, because that catalog can
  2782. // change "behind its back".
  2783. //
  2784. if(WintrustData.dwStateAction == WTD_STATEACTION_AUTO_CACHE) {
  2785. WintrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE_FLUSH;
  2786. Err = (DWORD)WinVerifyTrust(NULL,
  2787. &DriverVerifyGuid,
  2788. &WintrustData
  2789. );
  2790. if(Err != NO_ERROR) {
  2791. //
  2792. // This shouldn't fail, but log a warning if it does...
  2793. //
  2794. WriteLogEntry(LogContext,
  2795. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  2796. MSG_LOG_CRYPTO_CACHE_FLUSH_FAILURE,
  2797. NULL,
  2798. Catalog
  2799. );
  2800. WriteLogError(LogContext,
  2801. SETUP_LOG_WARNING,
  2802. Err
  2803. );
  2804. //
  2805. // treat this error as non-fatal
  2806. //
  2807. }
  2808. //
  2809. // When flushing the cache, crypto isn't supposed to be
  2810. // allocating a pcSignerCertContext...
  2811. //
  2812. MYASSERT(!VersionInfo.pcSignerCertContext);
  2813. if(VersionInfo.pcSignerCertContext) {
  2814. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  2815. VersionInfo.pcSignerCertContext = NULL;
  2816. }
  2817. //
  2818. // Now back to our regularly-scheduled programming...
  2819. //
  2820. WintrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE;
  2821. }
  2822. //
  2823. // NTRAID#NTBUG9-705286-2002/09/17-LonnyM superfluous validation of catalog
  2824. // Apparently, WinVerifyTrust validates both the catalog, and
  2825. // the file vouched thereby. We should clean this up, although
  2826. // the performance delta is probably insignificant.
  2827. //
  2828. Err = _VerifyCatalogFile(LogContext,
  2829. Catalog,
  2830. AltPlatformInfo,
  2831. UseAuthenticodePolicy,
  2832. (VerifyContext
  2833. ? &(VerifyContext->hStoreTrustedPublisher)
  2834. : NULL),
  2835. hWVTStateData
  2836. );
  2837. //
  2838. // If we got one of the two "successful" errors when validating
  2839. // via Authenticode policy, then reset our error, and save the
  2840. // Authenticode error for use later, if we don't subsequently
  2841. // encounter some other failure.
  2842. //
  2843. if((Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  2844. (Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  2845. MYASSERT(UseAuthenticodePolicy);
  2846. MYASSERT(!hWVTStateData || *hWVTStateData);
  2847. AuthenticodeErr = Err;
  2848. Err = NO_ERROR;
  2849. }
  2850. }
  2851. if(Err != NO_ERROR) {
  2852. MYASSERT(!hWVTStateData || !*hWVTStateData);
  2853. WriteLogEntry(LogContext,
  2854. GetCatLogLevel(Err, UseAuthenticodePolicy) | SETUP_LOG_BUFFER,
  2855. (UseAuthenticodePolicy
  2856. ? MSG_LOG_VERIFYCAT_VIA_AUTHENTICODE_ERROR
  2857. : MSG_LOG_VERIFYCAT_ERROR),
  2858. NULL,
  2859. Catalog
  2860. );
  2861. WriteLogError(LogContext,
  2862. GetCatLogLevel(Err, UseAuthenticodePolicy),
  2863. Err
  2864. );
  2865. LoggedWarning = TRUE;
  2866. if(Problem) {
  2867. *Problem = SetupapiVerifyCatalogProblem;
  2868. StringCchCopy(ProblemFile, MAX_PATH, Catalog);
  2869. }
  2870. leave;
  2871. }
  2872. //
  2873. // Catalog was verified, now verify the file using that catalog.
  2874. //
  2875. if(CatalogFileUsed) {
  2876. StringCchCopy(CatalogFileUsed, MAX_PATH, Catalog);
  2877. }
  2878. Err = (DWORD)WinVerifyTrust(NULL,
  2879. (UseAuthenticodePolicy
  2880. ? &AuthenticodeVerifyGuid
  2881. : &DriverVerifyGuid),
  2882. &WintrustData
  2883. );
  2884. //
  2885. // Fill in the DigitalSigner and SignerVersion if they were passed
  2886. // in.
  2887. //
  2888. if(Err == NO_ERROR) {
  2889. if(DigitalSigner) {
  2890. StringCchCopy(DigitalSigner, MAX_PATH, VersionInfo.wszSignedBy);
  2891. }
  2892. if(SignerVersion) {
  2893. StringCchCopy(SignerVersion, MAX_PATH, VersionInfo.wszVersion);
  2894. }
  2895. } else if(!UseAuthenticodePolicy && (Err == ERROR_APP_WRONG_OS)) {
  2896. //
  2897. // We failed validation via driver signing policy because of an
  2898. // osattribute mismatch. Translate this error into something
  2899. // with more understandable text.
  2900. //
  2901. Err = ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH;
  2902. }
  2903. if(Err != NO_ERROR) {
  2904. WriteLogEntry(LogContext,
  2905. GetCatLogLevel(Err, UseAuthenticodePolicy) | SETUP_LOG_BUFFER,
  2906. (UseAuthenticodePolicy
  2907. ? MSG_LOG_VERIFYFILE_AUTHENTICODE_AGAINST_FULLCATPATH_ERROR
  2908. : MSG_LOG_VERIFYFILE_AGAINST_FULLCATPATH_ERROR),
  2909. NULL,
  2910. FileFullPath,
  2911. Catalog,
  2912. Key
  2913. );
  2914. WriteLogError(LogContext,
  2915. GetCatLogLevel(Err, UseAuthenticodePolicy),
  2916. Err
  2917. );
  2918. LoggedWarning = TRUE;
  2919. if(Problem) {
  2920. *Problem = SetupapiVerifyFileProblem;
  2921. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  2922. }
  2923. } else {
  2924. //
  2925. // Log the successful validation against the caller-specified
  2926. // catalog.
  2927. //
  2928. if(UseAuthenticodePolicy) {
  2929. WriteLogEntry(LogContext,
  2930. DRIVER_LOG_INFO | SETUP_LOG_BUFFER,
  2931. MSG_LOG_VERIFYFILE_AUTHENTICODE_AGAINST_FULLCATPATH_OK,
  2932. NULL,
  2933. FileFullPath,
  2934. Catalog,
  2935. Key
  2936. );
  2937. WriteLogError(LogContext, DRIVER_LOG_INFO, AuthenticodeErr);
  2938. } else {
  2939. WriteLogEntry(LogContext,
  2940. SETUP_LOG_VERBOSE,
  2941. MSG_LOG_VERIFYFILE_AGAINST_FULLCATPATH_OK,
  2942. NULL,
  2943. FileFullPath,
  2944. Catalog,
  2945. Key
  2946. );
  2947. }
  2948. }
  2949. //
  2950. // We don't attempt to fallback to self-contained signatures in
  2951. // cases where the catalog is specifically specified. Thus, we're
  2952. // done, regardless of whether or not we were successful.
  2953. //
  2954. leave;
  2955. }
  2956. //
  2957. // We'd better have a catalog name (i.e., not be doing global
  2958. // validation) if we're supposed to be verifying via Authenticode
  2959. // policy!
  2960. //
  2961. MYASSERT(!UseAuthenticodePolicy || Catalog);
  2962. //
  2963. // Search through installed catalogs looking for those that contain
  2964. // data for a file with the hash we just calculated (aka, "global
  2965. // validation").
  2966. //
  2967. PrevCat = NULL;
  2968. Err = GLE_FN_CALL(NULL,
  2969. hCatInfo = CryptCATAdminEnumCatalogFromHash(
  2970. LocalhCatAdmin,
  2971. Hash,
  2972. HashSize,
  2973. 0,
  2974. &PrevCat)
  2975. );
  2976. while(hCatInfo) {
  2977. CatInfo.cbStruct = sizeof(CATALOG_INFO);
  2978. if(CryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, 0)) {
  2979. CatalogFullPath = CatInfo.wszCatalogFile;
  2980. //
  2981. // If we have a catalog name we're looking for, see if the
  2982. // current catalog matches. If the caller didn't specify a
  2983. // catalog, then just attempt to validate against each
  2984. // catalog we enumerate. Note that the catalog file info
  2985. // we get back gives us a fully qualified path.
  2986. //
  2987. if(Catalog) {
  2988. FoundMatchingImage = !lstrcmpi(
  2989. pSetupGetFileTitle(CatalogFullPath),
  2990. Catalog
  2991. );
  2992. } else {
  2993. if((Flags & VERIFY_FILE_USE_OEM_CATALOGS) ||
  2994. !IsInstalledFileFromOem(pSetupGetFileTitle(CatalogFullPath),
  2995. OemFiletypeCat)) {
  2996. FoundMatchingImage = TRUE;
  2997. } else {
  2998. FoundMatchingImage = FALSE;
  2999. }
  3000. }
  3001. if(FoundMatchingImage) {
  3002. //
  3003. // Increment our counter of how many catalogs we've
  3004. // considered.
  3005. //
  3006. if(NumCatalogsConsidered) {
  3007. (*NumCatalogsConsidered)++;
  3008. }
  3009. //
  3010. // If the caller supplied a mapped-in image of the
  3011. // catalog we're looking for, then check to see if this
  3012. // catalog matches by doing a binary compare.
  3013. //
  3014. if(CatalogBaseAddress) {
  3015. FoundMatchingImage = GetFileAttributesEx(
  3016. CatalogFullPath,
  3017. GetFileExInfoStandard,
  3018. &FileAttribData
  3019. );
  3020. //
  3021. // Check to see if the catalog we're looking
  3022. // at is the same size as the one we're
  3023. // verifying.
  3024. //
  3025. if(FoundMatchingImage &&
  3026. (FileAttribData.nFileSizeLow != CatalogImageSize)) {
  3027. FoundMatchingImage = FALSE;
  3028. }
  3029. if(FoundMatchingImage) {
  3030. if(NO_ERROR == pSetupOpenAndMapFileForRead(
  3031. CatalogFullPath,
  3032. &CurCatFileSize,
  3033. &CurCatFileHandle,
  3034. &CurCatMappingHandle,
  3035. &CurCatBaseAddress)) {
  3036. MYASSERT(CurCatFileSize == CatalogImageSize);
  3037. //
  3038. // Wrap this binary compare in its own try/
  3039. // except block, because if we run across a
  3040. // catalog we can't read for some reason,
  3041. // we don't want this to abort our search.
  3042. //
  3043. try {
  3044. FoundMatchingImage =
  3045. !memcmp(CatalogBaseAddress,
  3046. CurCatBaseAddress,
  3047. CatalogImageSize
  3048. );
  3049. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3050. pSetupExceptionHandler(GetExceptionCode(),
  3051. ERROR_READ_FAULT,
  3052. NULL);
  3053. FoundMatchingImage = FALSE;
  3054. }
  3055. pSetupUnmapAndCloseFile(CurCatFileHandle,
  3056. CurCatMappingHandle,
  3057. CurCatBaseAddress
  3058. );
  3059. } else {
  3060. FoundMatchingImage = FALSE;
  3061. }
  3062. }
  3063. } else {
  3064. //
  3065. // Since there was no catalog image supplied to
  3066. // match against, the catalog we're currently
  3067. // looking at is considered a valid match
  3068. // candidate.
  3069. //
  3070. FoundMatchingImage = TRUE;
  3071. }
  3072. if(FoundMatchingImage) {
  3073. //
  3074. // We found an applicable catalog, now validate the
  3075. // file against that catalog (this also validates the
  3076. // catalog itself).
  3077. //
  3078. WintrustCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
  3079. Err = (DWORD)WinVerifyTrust(NULL,
  3080. (UseAuthenticodePolicy
  3081. ? &AuthenticodeVerifyGuid
  3082. : &DriverVerifyGuid),
  3083. &WintrustData
  3084. );
  3085. //
  3086. // Fill in the DigitalSigner and SignerVersion if
  3087. // they were passed in.
  3088. //
  3089. if(Err == NO_ERROR) {
  3090. if(DigitalSigner) {
  3091. StringCchCopy(DigitalSigner, MAX_PATH, VersionInfo.wszSignedBy);
  3092. }
  3093. if(SignerVersion) {
  3094. StringCchCopy(SignerVersion, MAX_PATH, VersionInfo.wszVersion);
  3095. }
  3096. } else if(!UseAuthenticodePolicy && (Err == ERROR_APP_WRONG_OS)) {
  3097. //
  3098. // We failed validation via driver signing policy
  3099. // because of an osattribute mismatch. Translate
  3100. // this error into something with more
  3101. // understandable text.
  3102. //
  3103. // NOTE: Unfortunately, the crypto APIs report
  3104. // ERROR_APP_WRONG_OS in two quite different cases:
  3105. //
  3106. // 1. Valid driver signing catalog has an
  3107. // osattribute mismatch.
  3108. // 2. Authenticode catalog is being validated
  3109. // using driver signing policy.
  3110. //
  3111. // We want to translate the error in the first case
  3112. // but not in the second. The only way to
  3113. // distinguish these two cases is to re-attempt
  3114. // verification against _all_ os versions. Thus,
  3115. // any failure encountered must be due to #2.
  3116. //
  3117. //
  3118. // The DRIVER_VER_INFO structure was filled in
  3119. // during our previous call to WinVerifyTrust with
  3120. // a pointer that we must free!
  3121. //
  3122. if(VersionInfo.pcSignerCertContext) {
  3123. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  3124. }
  3125. //
  3126. // Now reset the structure and clear the flag so
  3127. // that we'll validate against _any_ OS version
  3128. // (irrespective of the catalog's osattributes).
  3129. //
  3130. ZeroMemory(&VersionInfo, sizeof(DRIVER_VER_INFO));
  3131. VersionInfo.cbStruct = sizeof(DRIVER_VER_INFO);
  3132. WintrustData.dwProvFlags &= ~WTD_USE_DEFAULT_OSVER_CHECK;
  3133. if(NO_ERROR == WinVerifyTrust(NULL,
  3134. &DriverVerifyGuid,
  3135. &WintrustData)) {
  3136. //
  3137. // The catalog is a valid driver signing
  3138. // catalog (i.e., case #1 discussed above).
  3139. // Translate this into more specific/meaningful
  3140. // error.
  3141. //
  3142. Err = ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH;
  3143. }
  3144. }
  3145. //
  3146. // If we successfully validated via Authenticode
  3147. // policy, then we need to determine whether the
  3148. // catalog's publisher is in the TrustedPublisher cert
  3149. // store.
  3150. //
  3151. if((Err == NO_ERROR) && UseAuthenticodePolicy) {
  3152. AuthenticodeErr = _VerifyCatalogFile(
  3153. LogContext,
  3154. WintrustCatalogInfo.pcwszCatalogFilePath,
  3155. NULL,
  3156. TRUE,
  3157. (VerifyContext
  3158. ? &(VerifyContext->hStoreTrustedPublisher)
  3159. : NULL),
  3160. hWVTStateData
  3161. );
  3162. MYASSERT((AuthenticodeErr == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  3163. (AuthenticodeErr == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED));
  3164. if((AuthenticodeErr != ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) &&
  3165. (AuthenticodeErr != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  3166. //
  3167. // This shouldn't have failed, but since it
  3168. // did, we'll propagate this over to our error
  3169. // status so we treat it appropriately.
  3170. //
  3171. Err = AuthenticodeErr;
  3172. }
  3173. }
  3174. if(!UseAuthenticodePolicy) {
  3175. //
  3176. // The DRIVER_VER_INFO structure was filled in with
  3177. // a pointer that we must free!
  3178. //
  3179. if(VersionInfo.pcSignerCertContext) {
  3180. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  3181. VersionInfo.pcSignerCertContext = NULL;
  3182. }
  3183. }
  3184. if(Err != NO_ERROR) {
  3185. WriteLogEntry(LogContext,
  3186. GetCatLogLevel(Err, UseAuthenticodePolicy) | SETUP_LOG_BUFFER,
  3187. (UseAuthenticodePolicy
  3188. ? MSG_LOG_VERIFYFILE_AUTHENTICODE_GLOBAL_VALIDATION_ERROR
  3189. : MSG_LOG_VERIFYFILE_GLOBAL_VALIDATION_ERROR),
  3190. NULL,
  3191. FileFullPath,
  3192. CatInfo.wszCatalogFile,
  3193. Key
  3194. );
  3195. WriteLogError(LogContext,
  3196. GetCatLogLevel(Err, UseAuthenticodePolicy),
  3197. Err
  3198. );
  3199. LoggedWarning = TRUE;
  3200. } else {
  3201. if(UseAuthenticodePolicy) {
  3202. WriteLogEntry(LogContext,
  3203. DRIVER_LOG_INFO | SETUP_LOG_BUFFER,
  3204. MSG_LOG_VERIFYFILE_AUTHENTICODE_GLOBAL_VALIDATION_OK,
  3205. NULL,
  3206. FileFullPath,
  3207. CatInfo.wszCatalogFile,
  3208. Key
  3209. );
  3210. WriteLogError(LogContext,
  3211. DRIVER_LOG_INFO,
  3212. AuthenticodeErr
  3213. );
  3214. } else {
  3215. WriteLogEntry(LogContext,
  3216. SETUP_LOG_VERBOSE,
  3217. MSG_LOG_VERIFYFILE_GLOBAL_VALIDATION_OK,
  3218. NULL,
  3219. FileFullPath,
  3220. CatInfo.wszCatalogFile,
  3221. Key
  3222. );
  3223. }
  3224. }
  3225. if(Err == NO_ERROR) {
  3226. //
  3227. // We successfully verified the file--store the
  3228. // name of the catalog used, if the caller
  3229. // requested it.
  3230. //
  3231. if(CatalogFileUsed) {
  3232. StringCchCopy(CatalogFileUsed, MAX_PATH, CatalogFullPath);
  3233. }
  3234. } else {
  3235. if(Catalog || CatalogBaseAddress) {
  3236. //
  3237. // We only want to return the catalog file used
  3238. // in cases where we believe the catalog to be
  3239. // valid. In this situation, the only case we
  3240. // can tell for certain is when we encounter an
  3241. // osattribute mismatch.
  3242. //
  3243. if(CatalogFileUsed && (Err == ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH)) {
  3244. StringCchCopy(CatalogFileUsed, MAX_PATH, CatalogFullPath);
  3245. }
  3246. if(Problem) {
  3247. *Problem = SetupapiVerifyFileProblem;
  3248. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  3249. }
  3250. }
  3251. }
  3252. //
  3253. // If the result of the above validations is success,
  3254. // then we're done. If not, and we're looking for a
  3255. // relevant catalog file (i.e., the INF didn't specify
  3256. // one), then we move on to the next catalog.
  3257. // Otherwise, we've failed.
  3258. //
  3259. if((Err == NO_ERROR) || Catalog || CatalogBaseAddress) {
  3260. CryptCATAdminReleaseCatalogContext(LocalhCatAdmin, hCatInfo, 0);
  3261. hCatInfo = NULL;
  3262. break;
  3263. }
  3264. }
  3265. }
  3266. }
  3267. PrevCat = hCatInfo;
  3268. Err = GLE_FN_CALL(NULL,
  3269. hCatInfo = CryptCATAdminEnumCatalogFromHash(
  3270. LocalhCatAdmin,
  3271. Hash,
  3272. HashSize,
  3273. 0,
  3274. &PrevCat)
  3275. );
  3276. }
  3277. if(Err == NO_ERROR) {
  3278. //
  3279. // We successfully validated the file--we're done!
  3280. //
  3281. leave;
  3282. }
  3283. //
  3284. // report failure if we haven't already done so
  3285. //
  3286. if(!LoggedWarning) {
  3287. WriteLogEntry(LogContext,
  3288. GetCatLogLevel(Err, UseAuthenticodePolicy) | SETUP_LOG_BUFFER,
  3289. (UseAuthenticodePolicy
  3290. ? MSG_LOG_VERIFYFILE_AUTHENTICODE_GLOBAL_VALIDATION_NO_CATS_FOUND
  3291. : MSG_LOG_VERIFYFILE_GLOBAL_VALIDATION_NO_CATS_FOUND),
  3292. NULL,
  3293. FileFullPath,
  3294. Catalog ? Catalog : TEXT(""),
  3295. Key
  3296. );
  3297. WriteLogError(LogContext,
  3298. GetCatLogLevel(Err, UseAuthenticodePolicy),
  3299. Err
  3300. );
  3301. LoggedWarning = TRUE;
  3302. }
  3303. if(!(Flags & (VERIFY_FILE_IGNORE_SELFSIGNED | VERIFY_FILE_USE_AUTHENTICODE_CATALOG))) {
  3304. //
  3305. // We've been instructed to allow self-signed files to be
  3306. // considered valid, so check for self-contained signature now.
  3307. //
  3308. WintrustData.dwUnionChoice = WTD_CHOICE_FILE;
  3309. WintrustData.pFile = &WintrustFileInfo;
  3310. ZeroMemory(&WintrustFileInfo, sizeof(WINTRUST_FILE_INFO));
  3311. WintrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
  3312. WintrustFileInfo.pcwszFilePath = FileFullPath;
  3313. Err = (DWORD)WinVerifyTrust(NULL,
  3314. &DriverVerifyGuid,
  3315. &WintrustData
  3316. );
  3317. //
  3318. // Fill in the DigitalSigner and SignerVersion if
  3319. // they were passed in.
  3320. //
  3321. if(Err == NO_ERROR) {
  3322. if(DigitalSigner) {
  3323. StringCchCopy(DigitalSigner, MAX_PATH, VersionInfo.wszSignedBy);
  3324. }
  3325. if(SignerVersion) {
  3326. StringCchCopy(SignerVersion, MAX_PATH, VersionInfo.wszVersion);
  3327. }
  3328. }
  3329. //
  3330. // The DRIVER_VER_INFO structure was filled in with a pointer that
  3331. // we must free!
  3332. //
  3333. if(VersionInfo.pcSignerCertContext) {
  3334. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  3335. VersionInfo.pcSignerCertContext = NULL;
  3336. }
  3337. if(Err != NO_ERROR) {
  3338. WriteLogEntry(LogContext,
  3339. SETUP_LOG_VERBOSE | SETUP_LOG_BUFFER,
  3340. MSG_LOG_SELFSIGN_ERROR,
  3341. NULL,
  3342. FileFullPath,
  3343. Key
  3344. );
  3345. WriteLogError(LogContext, SETUP_LOG_VERBOSE, Err);
  3346. LoggedWarning = TRUE;
  3347. } else {
  3348. WriteLogEntry(LogContext,
  3349. SETUP_LOG_VERBOSE,
  3350. MSG_LOG_SELFSIGN_OK,
  3351. NULL,
  3352. FileFullPath,
  3353. Key
  3354. );
  3355. }
  3356. }
  3357. if(Err == NO_ERROR) {
  3358. //
  3359. // The file validated without a catalog. Store an empty string
  3360. // in the CatalogFileUsed buffer (if supplied).
  3361. //
  3362. if(CatalogFileUsed) {
  3363. *CatalogFileUsed = TEXT('\0');
  3364. }
  3365. } else {
  3366. //
  3367. // report error prior to Self-Sign check
  3368. //
  3369. if(Problem) {
  3370. *Problem = SetupapiVerifyFileProblem;
  3371. StringCchCopy(ProblemFile, MAX_PATH, FileFullPath);
  3372. }
  3373. }
  3374. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3375. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  3376. }
  3377. if(Err == NO_ERROR) {
  3378. //
  3379. // If we successfully validated via Authenticode policy, then we should
  3380. // have squirrelled away one of two "special" errors to be returned to
  3381. // the caller...
  3382. //
  3383. MYASSERT((AuthenticodeErr == NO_ERROR) || UseAuthenticodePolicy);
  3384. Err = AuthenticodeErr;
  3385. } else {
  3386. //
  3387. // If we failed, and we haven't already logged a message indicating the
  3388. // cause of the failure, log a generic message now.
  3389. //
  3390. if(!LoggedWarning) {
  3391. WriteLogEntry(LogContext,
  3392. GetCatLogLevel(Err, UseAuthenticodePolicy) | SETUP_LOG_BUFFER,
  3393. (UseAuthenticodePolicy
  3394. ? MSG_LOG_VERIFYFILE_AUTHENTICODE_ERROR
  3395. : MSG_LOG_VERIFYFILE_ERROR),
  3396. NULL,
  3397. FileFullPath,
  3398. Catalog ? Catalog : TEXT(""),
  3399. Key
  3400. );
  3401. WriteLogError(LogContext,
  3402. GetCatLogLevel(Err, UseAuthenticodePolicy),
  3403. Err
  3404. );
  3405. }
  3406. if(hWVTStateData && *hWVTStateData) {
  3407. //
  3408. // We must've hit an exception after retrieving the WinVerifyTrust
  3409. // state data. This is extremely unlikely, but if this happens,
  3410. // we need to free this here and now.
  3411. //
  3412. pSetupCloseWVTStateData(*hWVTStateData);
  3413. *hWVTStateData = NULL;
  3414. }
  3415. }
  3416. if(!VerifyContext && LocalhSDBDrvMain) {
  3417. //
  3418. // Don't need to return our HSDB to the caller, so free it now.
  3419. //
  3420. SdbReleaseDatabase(LocalhSDBDrvMain);
  3421. }
  3422. if(hFile != INVALID_HANDLE_VALUE) {
  3423. CloseHandle(hFile);
  3424. }
  3425. if(AltPlatSlot) {
  3426. ReleaseLogInfoSlot(LogContext, AltPlatSlot);
  3427. }
  3428. if(Hash) {
  3429. MyFree(Hash);
  3430. }
  3431. if(!UseAuthenticodePolicy && VersionInfo.pcSignerCertContext) {
  3432. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  3433. }
  3434. if(hCatInfo) {
  3435. MYASSERT(LocalhCatAdmin);
  3436. CryptCATAdminReleaseCatalogContext(LocalhCatAdmin, hCatInfo, 0);
  3437. }
  3438. if(!VerifyContext && LocalhCatAdmin) {
  3439. CryptCATAdminReleaseContext(LocalhCatAdmin, 0);
  3440. }
  3441. return Err;
  3442. }
  3443. DWORD
  3444. pSetupVerifyFile(
  3445. IN PSETUP_LOG_CONTEXT LogContext,
  3446. IN LPCTSTR Catalog, OPTIONAL
  3447. IN PVOID CatalogBaseAddress, OPTIONAL
  3448. IN DWORD CatalogImageSize,
  3449. IN LPCTSTR Key,
  3450. IN LPCTSTR FileFullPath,
  3451. OUT SetupapiVerifyProblem *Problem, OPTIONAL
  3452. OUT LPTSTR ProblemFile, OPTIONAL
  3453. IN BOOL CatalogAlreadyVerified,
  3454. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  3455. OUT LPTSTR CatalogFileUsed, OPTIONAL
  3456. OUT PDWORD NumCatalogsConsidered OPTIONAL
  3457. )
  3458. /*++
  3459. Routine Description:
  3460. See _VerifyFile
  3461. Since this private API is exported for use by other system components
  3462. (e.g., syssetup), we make a check to ensure that the AltPlatformInfo, if
  3463. specified, is of the correct version.
  3464. --*/
  3465. {
  3466. if(AltPlatformInfo) {
  3467. if(AltPlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V2)) {
  3468. return ERROR_INVALID_PARAMETER;
  3469. }
  3470. if(!(AltPlatformInfo->Flags & SP_ALTPLATFORM_FLAGS_VERSION_RANGE)) {
  3471. //
  3472. // this flag must be set to indicate the version range fields are
  3473. // valid
  3474. //
  3475. return ERROR_INVALID_PARAMETER;
  3476. }
  3477. }
  3478. return _VerifyFile(LogContext,
  3479. NULL,
  3480. Catalog,
  3481. CatalogBaseAddress,
  3482. CatalogImageSize,
  3483. Key,
  3484. FileFullPath,
  3485. Problem,
  3486. ProblemFile,
  3487. CatalogAlreadyVerified,
  3488. AltPlatformInfo,
  3489. 0,
  3490. CatalogFileUsed,
  3491. NumCatalogsConsidered,
  3492. NULL,
  3493. NULL,
  3494. NULL
  3495. );
  3496. }
  3497. BOOL
  3498. IsInfForDeviceInstall(
  3499. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  3500. IN CONST GUID *DeviceSetupClassGuid, OPTIONAL
  3501. IN PLOADED_INF LoadedInf, OPTIONAL
  3502. OUT PTSTR *DeviceDesc, OPTIONAL
  3503. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform, OPTIONAL
  3504. OUT PDWORD PolicyToUse, OPTIONAL
  3505. OUT PBOOL UseOriginalInfName, OPTIONAL
  3506. IN BOOL ForceNonDrvSignPolicy
  3507. )
  3508. /*++
  3509. Routine Description:
  3510. This routine determines whether the specified INF is a device INF. If so,
  3511. it returns a generic string to use in identifying the device installation
  3512. when there is no device description available (e.g., installing a printer).
  3513. It can also return the appropriate platform parameters to be used in
  3514. digital signature verification for this INF, as well as the codesigning
  3515. policy to employ should a digital signature validation failure occur.
  3516. Finally, this routine can indicate whether the INF should be installed
  3517. under its original name (i.e., because it's an exception package INF).
  3518. Arguments:
  3519. LogContext - Optionally, supplies the log context for any log entries that
  3520. might be generated by this routine.
  3521. DeviceSetupClassGuid - Optionally, supplies the address of a GUID that
  3522. indicates which device setup class is to be used in determining
  3523. information such as description, validation platform, and policy to
  3524. use. If this parameter is NULL, then the GUID is retrieved from the
  3525. INF list supplied via the LoadedInf parameter.
  3526. LoadedInf - Optionally, supplies the address of a loaded INF list we need
  3527. to examine to see if any of the members therein are device INFs. An
  3528. INF is a device INF if it specifies a class association (via either
  3529. Class= or ClassGUID= entries) in its [Version] section. If the
  3530. DeviceSetupClassGuid parameter is supplied (i.e., non-NULL), then this
  3531. parameter is ignored. If this parameter is also NULL, then it is
  3532. assumed the installation is not device-related.
  3533. The presence of a device INF anywhere in this list will cause us to
  3534. consider this a device installation. However, the _first_ INF we
  3535. encounter having a class association is what will be used in
  3536. determining the device description (see below).
  3537. ** NOTE: The caller is responsible for locking the loaded INF **
  3538. ** list prior to calling this routine! **
  3539. DeviceDesc - Optionally, supplies the address of a string pointer that will
  3540. be filled in upon return with a (newly-allocated) descriptive string to
  3541. be used when referring to this installation (e.g., for doing driver
  3542. signing failure popups). We will first try to retrieve the friendly
  3543. name for this INF's class (whose determination is described above). If
  3544. that's not possible (e.g., the class isn't yet installed), then we'll
  3545. return the class name. If that's not possible, then we'll return a
  3546. (localized) generic string such as "Unknown driver software package".
  3547. This output parameter (if supplied) will only ever be set to a non-NULL
  3548. value when the routine returns TRUE. The caller is responsible for
  3549. freeing this character buffer. If an out-of-memory failure is
  3550. encountered when trying to allocate memory for this buffer, the
  3551. DeviceDesc pointer will simply be set to NULL. It will also be set to
  3552. NULL if we're dealing with an exception package (since we don't want
  3553. to treat this like a "hardware install" for purposes of codesigning
  3554. blocking UI).
  3555. ValidationPlatform - Optionally, supplies the address of a (version 2)
  3556. altplatform info pointer that is filled in upon return with a newly-
  3557. allocated structure specifying the appropriate parameters to be passed
  3558. to WinVerifyTrust when validating this INF. These parameters are
  3559. retrieved from certclas.inf for the relevant device setup class GUID.
  3560. If no special parameters are specified for this class (or if the INF
  3561. has no class at all), then this pointer is returned as NULL, which
  3562. causes us to use WinVerifyTrust's default validation. Note that if
  3563. we fail to allocate this structure due to low-memory, the pointer will
  3564. be returned as NULL in that case as well. This is OK, because this
  3565. simply means we'll do default validation in that case.
  3566. By this mechanism, we can easily deal with the different validation
  3567. policies in effect for the various device classes we have in the
  3568. system.
  3569. The caller is responsible for freeing the memory allocated for this
  3570. structure.
  3571. PolicyToUse - Optionally, supplies the address of a dword variable that is
  3572. set upon return to indicate what codesigning policy (i.e., Ignore,
  3573. Warn, or Block) should be used for this INF. This determination is
  3574. made based on whether any INF in the list is of a class that WHQL has a
  3575. certification program for (as specified in %windir%\Inf\certclas.inf).
  3576. Additionally, if any INF in the list is of the exception class, then
  3577. the policy is automatically set to Block (i.e., it's not configurable
  3578. via driver signing or non-driver-signing policy/preference settings).
  3579. If it's appropriate to allow for a fallback to an Authenticode
  3580. signature, then the high bit of the policy value will be set (i.e.,
  3581. DRIVERSIGN_ALLOW_AUTHENTICODE).
  3582. UseOriginalInfName - Optionally, supplies the address of a boolean variable
  3583. that is set upon return to indicate whether the INF should be installed
  3584. into %windir%\Inf under its original name. This will only be true if
  3585. the INF is an exception INF.
  3586. ForceNonDrvSignPolicy - if TRUE, then we'll use non-driver signing policy,
  3587. regardless of whether the INF has an associated device setup class
  3588. GUID. (Note: this override won't work if that class GUID is in the
  3589. WHQL logo-able list contained in certclas.inf--in that case, we always
  3590. want to use driver signing policy.)
  3591. This override will also cause us to report that the INF is _not_ a
  3592. device INF (assuming it's not a WHQL class, as described above).
  3593. Return Value:
  3594. If the INF is a device INF, the return value is TRUE. Otherwise, it is
  3595. FALSE.
  3596. --*/
  3597. {
  3598. PLOADED_INF CurInf, NextInf;
  3599. GUID ClassGuid;
  3600. BOOL DeviceInfFound, ClassInDrvSignList;
  3601. TCHAR ClassDescBuffer[LINE_LEN];
  3602. PCTSTR ClassDesc;
  3603. DWORD Err;
  3604. BOOL IsExceptionInf = FALSE;
  3605. if(DeviceDesc) {
  3606. *DeviceDesc = NULL;
  3607. }
  3608. if(ValidationPlatform) {
  3609. *ValidationPlatform = NULL;
  3610. }
  3611. if(UseOriginalInfName) {
  3612. *UseOriginalInfName = FALSE;
  3613. }
  3614. if(!DeviceSetupClassGuid && !LoadedInf) {
  3615. //
  3616. // Not a whole lot to do here. Assume non-driver-signing policy and
  3617. // return.
  3618. //
  3619. if(PolicyToUse) {
  3620. *PolicyToUse = pSetupGetCurrentDriverSigningPolicy(FALSE);
  3621. //
  3622. // Non-device installs are always candidates for Authenticode
  3623. // signatures.
  3624. //
  3625. *PolicyToUse |= DRIVERSIGN_ALLOW_AUTHENTICODE;
  3626. }
  3627. return FALSE;
  3628. }
  3629. if(PolicyToUse) {
  3630. *PolicyToUse = DRIVERSIGN_NONE;
  3631. }
  3632. //
  3633. // If DeviceSetupClassGuid was specified, then retrieve information
  3634. // pertaining to that class. Otherwise, traverse the individual INFs in
  3635. // the LOADED_INF list, examining each one to see if it's a device INF.
  3636. //
  3637. DeviceInfFound = FALSE;
  3638. ClassInDrvSignList = FALSE;
  3639. try {
  3640. for(CurInf = LoadedInf; CurInf || DeviceSetupClassGuid; CurInf = NextInf) {
  3641. //
  3642. // Setup a "NextInf" pointer so we won't dereference NULL when we
  3643. // go back through the loop in the case where we have a
  3644. // DeviceSetupClassGuid instead of a LoadedInf list.
  3645. //
  3646. NextInf = CurInf ? CurInf->Next : NULL;
  3647. if(!DeviceSetupClassGuid) {
  3648. if(ClassGuidFromInfVersionNode(&(CurInf->VersionBlock), &ClassGuid)) {
  3649. DeviceSetupClassGuid = &ClassGuid;
  3650. } else {
  3651. //
  3652. // This INF doesn't have an associated device setup class
  3653. // GUID, so skip it and continue on with our search for a
  3654. // device INF.
  3655. //
  3656. continue;
  3657. }
  3658. }
  3659. //
  3660. // NOTE: From this point forward, you must reset the
  3661. // DeviceSetupClasGuid pointer to NULL before making another pass
  3662. // through the loop. Otherwise, we'll enter an infinite loop,
  3663. // since we can enter the loop if that pointer is non-NULL.
  3664. //
  3665. if(IsEqualGUID(DeviceSetupClassGuid, &GUID_NULL)) {
  3666. //
  3667. // The INF specified a ClassGUID of GUID_NULL (e.g., like some
  3668. // of our non-device system INFs such as layout.inf do). Skip
  3669. // it, and continue on with our search for a device INF.
  3670. //
  3671. DeviceSetupClassGuid = NULL;
  3672. continue;
  3673. }
  3674. //
  3675. // If we get to this point, we have a device setup class GUID. If
  3676. // this is the first device INF we've encountered (or our first and
  3677. // only time through the loop when the caller passed us in a
  3678. // DeviceSetupClassGuid), then do our best to retrieve a
  3679. // description for it (if we've been asked to do so). We do not do
  3680. // this for exception packages, because we don't want them to be
  3681. // referred to as "hardware installs" in the Block dialog if a
  3682. // signature verification failure occurs.
  3683. //
  3684. if(!DeviceInfFound) {
  3685. DeviceInfFound = TRUE;
  3686. if(DeviceDesc) {
  3687. if(!IsEqualGUID(DeviceSetupClassGuid, &GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER)) {
  3688. //
  3689. // First, try to retrieve the class's friendly name.
  3690. //
  3691. if(SetupDiGetClassDescription(DeviceSetupClassGuid,
  3692. ClassDescBuffer,
  3693. SIZECHARS(ClassDescBuffer),
  3694. NULL)) {
  3695. ClassDesc = ClassDescBuffer;
  3696. } else if(CurInf) {
  3697. //
  3698. // OK, so the class isn't installed yet. Retrieve
  3699. // the class name from the INF itself.
  3700. //
  3701. ClassDesc = pSetupGetVersionDatum(&(CurInf->VersionBlock),
  3702. pszClass
  3703. );
  3704. } else {
  3705. //
  3706. // The caller passed us in a device setup class
  3707. // GUID instead of an INF. The class hasn't been
  3708. // installed yet, so we have no idea what to call
  3709. // it.
  3710. //
  3711. ClassDesc = NULL;
  3712. }
  3713. if(!ClassDesc) {
  3714. //
  3715. // We have a non-installed class, either with no
  3716. // INF, or with an INF that specifies a ClassGUID=
  3717. // entry, but no Class= entry in its [Version]
  3718. // section. If we tried to actually install a
  3719. // device from such an INF, we'd get a failure in
  3720. // SetupDiInstallClass because the class name is
  3721. // required when installing the class. However,
  3722. // this INF might never be used in a device
  3723. // installation, but it definitely is a device INF.
  3724. // Therefore, we just give it a generic
  3725. // description.
  3726. //
  3727. if(LoadString(MyDllModuleHandle,
  3728. IDS_UNKNOWN_DRIVER,
  3729. ClassDescBuffer,
  3730. SIZECHARS(ClassDescBuffer))) {
  3731. ClassDesc = ClassDescBuffer;
  3732. } else {
  3733. ClassDesc = NULL;
  3734. }
  3735. }
  3736. //
  3737. // OK, we have a description for this device (unless we
  3738. // hit some weird error).
  3739. //
  3740. if(ClassDesc) {
  3741. *DeviceDesc = DuplicateString(ClassDesc);
  3742. }
  3743. }
  3744. }
  3745. }
  3746. //
  3747. // If we get to this point, we know that: (a) we have a device
  3748. // setup class GUID and (b) we've retrieved a device description,
  3749. // if necessary/possible.
  3750. //
  3751. // Now, check to see if this is an exception class--if it is, then
  3752. // policy is Block, and we want to install the INF and CAT files
  3753. // using their original names.
  3754. //
  3755. if(IsEqualGUID(DeviceSetupClassGuid, &GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER)) {
  3756. if(PolicyToUse) {
  3757. *PolicyToUse = DRIVERSIGN_BLOCKING;
  3758. }
  3759. if(UseOriginalInfName) {
  3760. *UseOriginalInfName = TRUE;
  3761. }
  3762. IsExceptionInf = TRUE;
  3763. }
  3764. if(PolicyToUse || ValidationPlatform || ForceNonDrvSignPolicy) {
  3765. //
  3766. // Now check to see if this class is in our list of classes
  3767. // that WHQL has certification programs for (hence should be
  3768. // subject to driver signing policy).
  3769. //
  3770. // NOTE: We may also find the exception class GUID in this
  3771. // list. This may be used as an override mechanism, in case we
  3772. // decide to allow 5.0-signed exception packages install on
  3773. // 5.1, for example. This should never be the case, since an
  3774. // exception package destined for multiple OS versions should
  3775. // have an OS attribute explicitly calling out each OS version
  3776. // for which it is applicable. The fact that we check for the
  3777. // exception package override in certclas.inf is simply an
  3778. // "escape hatch" for such an unfortunate eventuality.
  3779. //
  3780. ClassInDrvSignList = ClassGuidInDrvSignPolicyList(
  3781. LogContext,
  3782. DeviceSetupClassGuid,
  3783. ValidationPlatform
  3784. );
  3785. if(ClassInDrvSignList) {
  3786. //
  3787. // Once we encounter a device INF whose class is in our
  3788. // driver signing policy list, we can stop looking...
  3789. //
  3790. break;
  3791. }
  3792. } else {
  3793. //
  3794. // The caller doesn't care about whether this class is subject
  3795. // to driver signing policy. Since we've already retrieved the
  3796. // info they care about, we can get out of this loop.
  3797. //
  3798. break;
  3799. }
  3800. DeviceSetupClassGuid = NULL; // break out in no-INF case
  3801. }
  3802. //
  3803. // Unless we've already established that the policy to use is "Block"
  3804. // (i.e., because we found an exception INF), we should retrieve the
  3805. // applicable policy now...
  3806. //
  3807. if(PolicyToUse && (*PolicyToUse != DRIVERSIGN_BLOCKING)) {
  3808. if(ForceNonDrvSignPolicy) {
  3809. //
  3810. // We want to use non-driver signing policy unless the INF's
  3811. // class is in our WHQL-approved list.
  3812. //
  3813. if(ClassInDrvSignList) {
  3814. *PolicyToUse = pSetupGetCurrentDriverSigningPolicy(TRUE);
  3815. } else {
  3816. *PolicyToUse = pSetupGetCurrentDriverSigningPolicy(FALSE)
  3817. | DRIVERSIGN_ALLOW_AUTHENTICODE;
  3818. }
  3819. } else {
  3820. //
  3821. // If we have a device INF, we want to use driver signing
  3822. // policy. Otherwise, we want "non-driver signing" policy.
  3823. //
  3824. *PolicyToUse = pSetupGetCurrentDriverSigningPolicy(DeviceInfFound);
  3825. //
  3826. // If we have a device setup class, and that class is in our
  3827. // WHQL-approved list, then we should not accept Authenticode
  3828. // signatures.
  3829. //
  3830. if(!ClassInDrvSignList) {
  3831. *PolicyToUse |= DRIVERSIGN_ALLOW_AUTHENTICODE;
  3832. }
  3833. }
  3834. }
  3835. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3836. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  3837. }
  3838. if(ForceNonDrvSignPolicy) {
  3839. return (ClassInDrvSignList || IsExceptionInf);
  3840. } else {
  3841. return DeviceInfFound;
  3842. }
  3843. }
  3844. DWORD
  3845. GetCodeSigningPolicyForInf(
  3846. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  3847. IN HINF InfHandle,
  3848. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform, OPTIONAL
  3849. OUT PBOOL UseOriginalInfName OPTIONAL
  3850. )
  3851. /*++
  3852. Routine Description:
  3853. This routine returns a value indicating the appropriate policy to be
  3854. employed should a digital signature verification failure arise from some
  3855. operation initiated by that INF. It figures out whether the INF is subject
  3856. to driver signing or non-driver signing policy (based on the INF's class
  3857. affiliation), as well as whether or not Authenticode signatures should be
  3858. allowed (based on the presence of an applicable WHQL program). It also can
  3859. return an altplatform info structure indicating how validation should be
  3860. done (i.e., if certclas.inf indicates that a range of OSATTR versions
  3861. should be considered valid).
  3862. Arguments:
  3863. LogContext - Optionally, supplies the log context for any log entries that
  3864. might be generated by this routine.
  3865. InfHandle - Supplies the handle of the INF for which policy is to be
  3866. retrieved.
  3867. ValidationPlatform - See preamble of IsInfForDeviceInstall routine for
  3868. details.
  3869. UseOriginalInfName - Optionally, supplies the address of a boolean variable
  3870. that is set upon return to indicate whether the INF should be installed
  3871. into %windir%\Inf under its original name. This will only be true if
  3872. the INF is an exception INF.
  3873. Return Value:
  3874. DWORD indicating the policy to be used...
  3875. DRIVERSIGN_NONE
  3876. DRIVERSIGN_WARNING
  3877. DRIVERSIGN_BLOCKING
  3878. ...potentially OR'ed with the DRIVERSIGN_ALLOW_AUTHENTICODE flag, if it's
  3879. acceptable to check for Authenticode signatures.
  3880. --*/
  3881. {
  3882. DWORD Policy;
  3883. if(UseOriginalInfName) {
  3884. *UseOriginalInfName = FALSE;
  3885. }
  3886. if(ValidationPlatform) {
  3887. *ValidationPlatform = NULL;
  3888. }
  3889. if(!LockInf((PLOADED_INF)InfHandle)) {
  3890. //
  3891. // This is an internal-only routine, and all callers should be passing
  3892. // in valid INF handles.
  3893. //
  3894. MYASSERT(FALSE);
  3895. //
  3896. // If this does happen, just assume this isn't a device INF (but don't
  3897. // allow Authenticode signatures).
  3898. //
  3899. return pSetupGetCurrentDriverSigningPolicy(FALSE);
  3900. }
  3901. try {
  3902. IsInfForDeviceInstall(LogContext,
  3903. NULL,
  3904. (PLOADED_INF)InfHandle,
  3905. NULL,
  3906. ValidationPlatform,
  3907. &Policy,
  3908. UseOriginalInfName,
  3909. TRUE // use non-driver signing policy unless it's a WHQL class
  3910. );
  3911. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3912. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  3913. //
  3914. // We have to return a policy so we'll default to warn (w/o allowing
  3915. // use of Authenticode signatures).
  3916. //
  3917. Policy = DRIVERSIGN_WARNING;
  3918. }
  3919. UnlockInf((PLOADED_INF)InfHandle);
  3920. return Policy;
  3921. }
  3922. VOID
  3923. pSetupGetRealSystemTime(
  3924. OUT LPSYSTEMTIME RealSystemTime
  3925. );
  3926. DWORD
  3927. pSetupGetCurrentDriverSigningPolicy(
  3928. IN BOOL IsDeviceInstallation
  3929. )
  3930. /*++
  3931. Routine Description:
  3932. (The following description describes the strategy behind the selection of
  3933. policy. The implementation, however, follows a few twists and turns in
  3934. order to thwart unscupulous individuals who would subvert digital signature
  3935. UI in order to avoid having to get their packages signed...)
  3936. This routine returns a value indicating what action should be taken when a
  3937. digital signature verification failure is encountered. Separate "policies"
  3938. are maintained for "DriverSigning" (i.e., device installer activities) and
  3939. "NonDriverSigning" (i.e., everything else).
  3940. ** NOTE: presently, an INF that doesn't identify itself as a device INF **
  3941. ** (i.e., because it doesn't include a non-NULL ClassGuid entry in its **
  3942. ** [Version] section) will always fall under "non-driver signing" **
  3943. ** policy, even though it's possible the INF may be making driver- **
  3944. ** related changes (e.g., copying new driver files to **
  3945. ** %windir%\system32\drivers, adding services via either AddReg or **
  3946. ** AddService, etc.). **
  3947. For driver signing, there are actually 3 sources of policy:
  3948. 1. HKLM\Software\Microsoft\Driver Signing : Policy : REG_BINARY (REG_DWORD also supported)
  3949. This is a Windows 98-compatible value that specifies the default
  3950. behavior which applies to all users of the machine.
  3951. 2. HKCU\Software\Microsoft\Driver Signing : Policy : REG_DWORD
  3952. This specifies the user's preference for what behavior to employ
  3953. upon verification failure.
  3954. 3. HKCU\Software\Policies\Microsoft\Windows NT\Driver Signing : BehaviorOnFailedVerify : REG_DWORD
  3955. This specifies the administrator-mandated policy on what behavior
  3956. to employ upon verification failure. This policy, if specified,
  3957. overrides the user's preference.
  3958. The algorithm for deciding on the behavior to employ is as follows:
  3959. if (3) is specified {
  3960. policy = (3)
  3961. } else {
  3962. policy = (2)
  3963. }
  3964. policy = MAX(policy, (1))
  3965. For non-driver signing, the algorithm is the same, except that values (1),
  3966. (2), and (3) come from the following registry locations:
  3967. 1. HKLM\Software\Microsoft\Non-Driver Signing : Policy : REG_BINARY (REG_DWORD also supported)
  3968. 2. HKCU\Software\Microsoft\Non-Driver Signing : Policy : REG_DWORD
  3969. 3. HKCU\Software\Policies\Microsoft\Windows NT\Non-Driver Signing : BehaviorOnFailedVerify : REG_DWORD
  3970. NOTE: If we're in non-interactive mode, policy is always Block, so we
  3971. don't even bother trying to retrieve any of these registry settings.
  3972. Another reason to avoid doing so is to keep from jumping to the
  3973. wrong conclusion that someone has tampered with policy when in
  3974. reality, we're in a service that loaded in GUI setup prior to the
  3975. time when the policy values were fully initialized.
  3976. Arguments:
  3977. IsDeviceInstallation - If non-zero, then driver signing policy should be
  3978. retrieved. Otherwise, non-driver signing policy should be used.
  3979. Return Value:
  3980. Value indicating the policy in effect. May be one of the following three
  3981. values:
  3982. DRIVERSIGN_NONE - silently succeed installation of unsigned/
  3983. incorrectly-signed files. A PSS log entry will
  3984. be generated, however (as it will for all 3
  3985. types)
  3986. DRIVERSIGN_WARNING - warn the user, but let them choose whether or not
  3987. they still want to install the problematic file
  3988. DRIVERSIGN_BLOCKING - do not allow the file to be installed
  3989. (If policy can't be retrieved from any of the sources described above, the
  3990. default is DRIVERSIGN_NONE.)
  3991. --*/
  3992. {
  3993. SYSTEMTIME RealSystemTime;
  3994. DWORD PolicyFromReg, PolicyFromDS, RegDataType, RegDataSize;
  3995. HKEY hKey;
  3996. BOOL UserPolicyRetrieved = FALSE;
  3997. WORD w;
  3998. if(GlobalSetupFlags & PSPGF_NONINTERACTIVE) {
  3999. return DRIVERSIGN_BLOCKING;
  4000. }
  4001. w = IsDeviceInstallation?1:0;
  4002. RealSystemTime.wDayOfWeek = (LOWORD(&hKey)&~4)|(w<<2);
  4003. pSetupGetRealSystemTime(&RealSystemTime);
  4004. PolicyFromReg = (((RealSystemTime.wMilliseconds+2)&15)^8)/4;
  4005. MYASSERT(PolicyFromReg <= DRIVERSIGN_BLOCKING);
  4006. //
  4007. // Retrieve the user policy. If policy isn't set for this user, then
  4008. // retrieve the user's preference, instead.
  4009. //
  4010. PolicyFromDS = DRIVERSIGN_NONE;
  4011. hKey = INVALID_HANDLE_VALUE;
  4012. try {
  4013. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  4014. (IsDeviceInstallation ? pszDrvSignPolicyPath
  4015. : pszNonDrvSignPolicyPath),
  4016. 0,
  4017. KEY_READ,
  4018. &hKey)) {
  4019. //
  4020. // Ensure hKey is still invalid so we won't try to free it.
  4021. //
  4022. hKey = INVALID_HANDLE_VALUE;
  4023. } else {
  4024. RegDataSize = sizeof(PolicyFromDS);
  4025. if(ERROR_SUCCESS == RegQueryValueEx(
  4026. hKey,
  4027. pszDrvSignBehaviorOnFailedVerifyDS,
  4028. NULL,
  4029. &RegDataType,
  4030. (PBYTE)&PolicyFromDS,
  4031. &RegDataSize)) {
  4032. if((RegDataType == REG_DWORD) &&
  4033. (RegDataSize == sizeof(DWORD)) &&
  4034. ((PolicyFromDS == DRIVERSIGN_NONE) || (PolicyFromDS == DRIVERSIGN_WARNING) || (PolicyFromDS == DRIVERSIGN_BLOCKING)))
  4035. {
  4036. //
  4037. // We successfully retrieved user policy, so we won't need
  4038. // to retrieve user preference.
  4039. //
  4040. UserPolicyRetrieved = TRUE;
  4041. }
  4042. }
  4043. RegCloseKey(hKey);
  4044. hKey = INVALID_HANDLE_VALUE;
  4045. }
  4046. //
  4047. // If we didn't find a user policy, then retrieve the user preference.
  4048. //
  4049. if(!UserPolicyRetrieved) {
  4050. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  4051. (IsDeviceInstallation ? pszDrvSignPath
  4052. : pszNonDrvSignPath),
  4053. 0,
  4054. KEY_READ,
  4055. &hKey)) {
  4056. //
  4057. // Ensure hKey is still invalid so we won't try to free it.
  4058. //
  4059. hKey = INVALID_HANDLE_VALUE;
  4060. } else {
  4061. RegDataSize = sizeof(PolicyFromDS);
  4062. if(ERROR_SUCCESS == RegQueryValueEx(hKey,
  4063. pszDrvSignPolicyValue,
  4064. NULL,
  4065. &RegDataType,
  4066. (PBYTE)&PolicyFromDS,
  4067. &RegDataSize))
  4068. {
  4069. if((RegDataType != REG_DWORD) ||
  4070. (RegDataSize != sizeof(DWORD)) ||
  4071. !((PolicyFromDS == DRIVERSIGN_NONE) || (PolicyFromDS == DRIVERSIGN_WARNING) || (PolicyFromDS == DRIVERSIGN_BLOCKING)))
  4072. {
  4073. //
  4074. // Bogus entry for user preference--ignore it.
  4075. //
  4076. PolicyFromDS = DRIVERSIGN_NONE;
  4077. }
  4078. }
  4079. //
  4080. // No need to close the registry key handle--it'll get closed
  4081. // after we exit the try/except block.
  4082. //
  4083. }
  4084. }
  4085. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4086. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4087. }
  4088. if(hKey != INVALID_HANDLE_VALUE) {
  4089. RegCloseKey(hKey);
  4090. }
  4091. //
  4092. // Now return the more restrictive of the two policies.
  4093. //
  4094. if(PolicyFromDS > PolicyFromReg) {
  4095. return PolicyFromDS;
  4096. } else {
  4097. return PolicyFromReg;
  4098. }
  4099. }
  4100. DWORD
  4101. VerifySourceFile(
  4102. IN PSETUP_LOG_CONTEXT LogContext,
  4103. IN PSP_FILE_QUEUE Queue, OPTIONAL
  4104. IN PSP_FILE_QUEUE_NODE QueueNode, OPTIONAL
  4105. IN PCTSTR Key,
  4106. IN PCTSTR FileToVerifyFullPath,
  4107. IN PCTSTR OriginalSourceFileFullPath, OPTIONAL
  4108. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  4109. IN DWORD Flags,
  4110. OUT SetupapiVerifyProblem *Problem,
  4111. OUT LPTSTR ProblemFile,
  4112. OUT LPTSTR CatalogFileUsed, OPTIONAL
  4113. OUT LPTSTR DigitalSigner, OPTIONAL
  4114. OUT LPTSTR SignerVersion, OPTIONAL
  4115. OUT HANDLE *hWVTStateData OPTIONAL
  4116. )
  4117. /*++
  4118. Routine Description:
  4119. This routine verifies the digital signature of the specified file either
  4120. globally (i.e., using all catalogs), or based on the catalog file specified
  4121. in the supplied queue node.
  4122. Arguments:
  4123. LogContext - Supplies a context for logging the verify
  4124. Queue - Optionally, supplies pointer to the queue structure. This contains
  4125. information about the default verification method to use when the file
  4126. isn't associated with a particular catalog.
  4127. QueueNode - Optionally, supplies the queue node containing catalog
  4128. information to be used when verifying the file's signature. If not
  4129. supplied, then the file will be verified using all applicable installed
  4130. catalogs. If this pointer is supplied, then so must the Queue
  4131. parameter.
  4132. Key - Supplies a value that "indexes" the catalog, telling the verify APIs
  4133. which signature datum within the catalog it should use. Typically
  4134. the key is the name of the destination file (sans path) that the source
  4135. file is to be copied to.
  4136. FileToVerifyFullPath - Supplies the full path of the file to be verified.
  4137. OriginalSourceFileFullPath - Optionally, supplies the original source
  4138. file's name, to be returned in the ProblemFile buffer when an error
  4139. occurs. If this parameter is not specified, then the source file's
  4140. original name is assumed to be the same as the filename we're
  4141. verifying, and the path supplied in FileToVerifyFullPath will be
  4142. returned in the ProblemFile buffer in case of error.
  4143. AltPlatformInfo - optionally, supplies alternate platform information used
  4144. to fill in a DRIVER_VER_INFO structure (defined in sdk\inc\softpub.h)
  4145. that is passed to WinVerifyTrust.
  4146. ** NOTE: This structure _must_ have its cbSize field set to **
  4147. ** sizeof(SP_ALTPLATFORM_INFO_V2) -- validation on client-supplied **
  4148. ** buffer is the responsibility of the caller. **
  4149. Flags - supplies flags that alter that behavior of this routine. May be a
  4150. combination of the following values:
  4151. VERIFY_FILE_IGNORE_SELFSIGNED - if this bit is set, then this routine
  4152. will fail validation for self-signed
  4153. binaries. NOTE: when validating via
  4154. Authenticode policy, we always ignore
  4155. self-signed binaries.
  4156. VERIFY_FILE_USE_OEM_CATALOGS - if this bit is set, then all catalogs
  4157. installed in the system will be scanned
  4158. to verify the given file. Otherwise,
  4159. OEM (3rd party) catalogs will NOT be
  4160. scanned to verify the given file. This
  4161. is only applicable if a QueueNode
  4162. specifying a specific catalog is not
  4163. given. NOTE: this flag should not be
  4164. specified when requesting validation
  4165. via Authenticode policy.
  4166. VERIFY_FILE_USE_AUTHENTICODE_CATALOG - Validate the file using a
  4167. catalog signed with Authenticode
  4168. policy. If this flag is set,
  4169. we'll _only_ check for
  4170. Authenticode signatures, so if
  4171. the caller wants to first try
  4172. validating a file for OS code-
  4173. signing usage, then falling back
  4174. to Authenticode, they'll have to
  4175. call this routine twice.
  4176. If this flag is set, then the
  4177. caller may also supply the
  4178. hWVTStateData output parameter,
  4179. which can be used to prompt user
  4180. in order to establish that the
  4181. publisher should be trusted.
  4182. VerifySourceFile will return one
  4183. of two error codes upon
  4184. successful validation via
  4185. Authenticode policy. Refer to
  4186. the "Return Value" section for
  4187. details.
  4188. VERIFY_FILE_DRIVERBLOCKED_ONLY - Only check if the file is in the bad
  4189. driver database, don't do any digital
  4190. sigature validation. NOTE: this flag
  4191. should not be specified when
  4192. requesting validation via Authenticode
  4193. policy.
  4194. VERIFY_FILE_NO_DRIVERBLOCKED_CHECK - Don't check if the file is blocked
  4195. via the Bad Driver Database.
  4196. NOTE: this flag has no effect when
  4197. validating via Authenticode policy
  4198. because we never check the bad
  4199. driver database in that case.
  4200. Problem - Points to a variable that will be filled in upon unsuccessful
  4201. return with the cause of failure.
  4202. ProblemFile - Supplies the address of a character buffer that will be
  4203. filled in upon unsuccessful return to indicate the file that failed
  4204. verification. This may be the name of the file we're verifying (or
  4205. it's original name, if supplied), or it may be the name of the catalog
  4206. used for verification, if the catalog itself isn't properly signed.
  4207. (The type of file can be ascertained from the value returned in the
  4208. Problem output parameter.)
  4209. CatalogFileUsed - if supplied, this parameter points to a character buffer
  4210. at least MAX_PATH characters big that receives the name of the catalog
  4211. file used to verify the specified file. This is only filled in upon
  4212. successful return, or when the Problem is SetupapiVerifyFileProblem
  4213. (i.e., the catalog verified, but the file did not). If this buffer is
  4214. set to the empty string upon a SetupapiVerifyFileProblem failure, then
  4215. we didn't find any applicable catalogs to use for validation.
  4216. Also, this buffer will contain an empty string upon successful return
  4217. if the file was validated without using a catalog (i.e., the file
  4218. contains its own signature).
  4219. DigitalSigner - if supplied, this parameter points to a character buffer of
  4220. at least MAX_PATH characters that receives the name of who digitally
  4221. signed the specified file. This value is only set if the Key is
  4222. correctly signed (i.e. the function returns NO_ERROR).
  4223. SignerVersion - if supplied, this parameter points to a character buffer of
  4224. at least MAX_PATH characters that receives the the signer version as
  4225. returned in the szwVerion field of the DRIVER_VER_INFO structure in
  4226. our call to WinVerifyTrust.
  4227. hWVTStateData - if supplied, this parameter points to a buffer that
  4228. receives a handle to WinVerifyTrust state data. This handle will be
  4229. returned only when validation was successfully performed using
  4230. Authenticode policy. This handle may be used, for example, to retrieve
  4231. signer info when prompting the user about whether they trust the
  4232. publisher. (The status code returned will indicate whether or not this
  4233. is necessary, see "Return Value" section below.)
  4234. This parameter should only be supplied if the
  4235. VERIFY_FILE_USE_AUTHENTICODE_CATALOG bit is set in the supplied Flags.
  4236. If the routine fails, then this handle will be set to NULL.
  4237. It is the caller's responsibility to close this handle when they're
  4238. finished with it by calling pSetupCloseWVTStateData().
  4239. Return Value:
  4240. If the file was successfully validated via driver signing policy (or we
  4241. didn't perform digital signature verification and everything else
  4242. succeeded), then the return value is NO_ERROR.
  4243. If the file was successfully validated via Authenticode policy, and the
  4244. publisher was in the TrustedPublisher store, then the return value is
  4245. ERROR_AUTHENTICODE_TRUSTED_PUBLISHER.
  4246. If the file was successfully validated via Authenticode policy, and the
  4247. publisher was not in the TrustedPublisher store (hence we must prompt the
  4248. user to establish their trust of the publisher), then the return value is
  4249. ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED
  4250. If a failure occurred, the return value is a Win32 error code indicating
  4251. the cause of the failure.
  4252. --*/
  4253. {
  4254. DWORD rc;
  4255. PCTSTR AltCatalogFile;
  4256. LPCTSTR InfFullPath;
  4257. MYASSERT(!QueueNode || Queue);
  4258. //
  4259. // Initialize the output handle for WinVerifyTrust state data.
  4260. //
  4261. if(hWVTStateData) {
  4262. *hWVTStateData = NULL;
  4263. }
  4264. //
  4265. // If the caller requested that we return WinVerifyTrust state data upon
  4266. // successful Authenticode validation, then they'd better have actually
  4267. // requested Authenticode validation!
  4268. //
  4269. MYASSERT(!hWVTStateData || (Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG));
  4270. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  4271. //
  4272. // Nobody had better be calling this expecting to get back any info
  4273. // about a successful verification!
  4274. //
  4275. MYASSERT(!CatalogFileUsed);
  4276. MYASSERT(!DigitalSigner);
  4277. MYASSERT(!SignerVersion);
  4278. //
  4279. // Likewise, we'd better not be called asking to validate using
  4280. // Authenticode policy (and hence, to return WinVerifyTrust state data
  4281. // regarding the signing certificate).
  4282. //
  4283. MYASSERT(!(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG));
  4284. return NO_ERROR;
  4285. }
  4286. //
  4287. // We only support a subset of flags when validating via Authenticode
  4288. // policy. Make sure no illegal flags are set.
  4289. //
  4290. MYASSERT(!(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG) ||
  4291. !(Flags & (VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_DRIVERBLOCKED_ONLY)));
  4292. //
  4293. // If we know the file's destination (i.e., we have a QueueNode), and the
  4294. // INF is headed for %windir%\Inf, we want to catch and disallow that right
  4295. // up front. We don't do this for exception packages, since it's assumed
  4296. // (whether correctly or incorrectly) that they're "part of the OS", and as
  4297. // such, they know what they're doing.
  4298. //
  4299. // We also unfortunately can't do this for Authenticode-signed packages,
  4300. // because there are some IExpress packages out there that copy the INF to
  4301. // the INF directory, and use an Authenticode signature. If we treat this
  4302. // as a signature failure, then this will cause us to bail out of queue
  4303. // committal. Since our Authenticode logic is meant to prevent spoofing/
  4304. // tampering (and that's not the issue in this case), we just have to keep
  4305. // quiet about this. :-(
  4306. //
  4307. if(!(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG) &&
  4308. (QueueNode && !(Queue->Flags & FQF_KEEP_INF_AND_CAT_ORIGINAL_NAMES))) {
  4309. TCHAR TargetPath[MAX_PATH];
  4310. LPCTSTR TargetFilename, p;
  4311. //
  4312. // Is the target file an INF?
  4313. //
  4314. TargetFilename = pSetupStringTableStringFromId(Queue->StringTable,
  4315. QueueNode->TargetFilename
  4316. );
  4317. p = _tcsrchr(TargetFilename, TEXT('.'));
  4318. if(p && !_tcsicmp(p, pszInfSuffix)) {
  4319. //
  4320. // It's an INF. Construct the full target path to see where it's
  4321. // going.
  4322. //
  4323. StringCchCopy(
  4324. TargetPath,
  4325. SIZECHARS(TargetPath),
  4326. pSetupStringTableStringFromId(Queue->StringTable, QueueNode->TargetDirectory)
  4327. );
  4328. pSetupConcatenatePaths(TargetPath,
  4329. TargetFilename,
  4330. SIZECHARS(TargetPath),
  4331. NULL
  4332. );
  4333. if(!pSetupInfIsFromOemLocation(TargetPath, TRUE)) {
  4334. //
  4335. // It is invalid to copy an INF into %windir%\Inf via a file
  4336. // queue. Report this file as unsigned...
  4337. //
  4338. *Problem = SetupapiVerifyIncorrectlyCopiedInf;
  4339. StringCchCopy(ProblemFile, MAX_PATH, FileToVerifyFullPath);
  4340. return ERROR_INCORRECTLY_COPIED_INF;
  4341. }
  4342. }
  4343. }
  4344. //
  4345. // Check to see if the source file is signed.
  4346. //
  4347. if(QueueNode && QueueNode->CatalogInfo) {
  4348. //
  4349. // We should never have the IQF_FROM_BAD_OEM_INF internal flag set in
  4350. // this case.
  4351. //
  4352. MYASSERT(!(QueueNode->InternalFlags & IQF_FROM_BAD_OEM_INF));
  4353. if(*(QueueNode->CatalogInfo->CatalogFilenameOnSystem)) {
  4354. //
  4355. // The fact that our catalog info node has a filename filled in
  4356. // means we successfully verified this catalog previously. Now we
  4357. // simply need to verify the temporary (source) file against the
  4358. // catalog.
  4359. //
  4360. //
  4361. // If our catalog is an Authenticode catalog, we don't want to use
  4362. // WinVerifyTrust to validate using driver signing policy. That's
  4363. // because it will return the same error we get when we have an
  4364. // osattribute mismatch, and this will confuse this routine's
  4365. // callers.
  4366. //
  4367. if(!(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG) &&
  4368. (QueueNode->CatalogInfo->Flags &
  4369. (CATINFO_FLAG_AUTHENTICODE_SIGNED | CATINFO_FLAG_PROMPT_FOR_TRUST))) {
  4370. *Problem = SetupapiVerifyFileProblem;
  4371. StringCchCopy(ProblemFile, MAX_PATH, FileToVerifyFullPath);
  4372. return ERROR_ONLY_VALIDATE_VIA_AUTHENTICODE;
  4373. } else {
  4374. //
  4375. // The caller shouldn't have requested verification using
  4376. // Authenticode policy unless they already knew the catalog was
  4377. // Authenticode signed. We'll do the right thing regardless, but
  4378. // this is a sanity check.
  4379. //
  4380. MYASSERT(!(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG) ||
  4381. (QueueNode->CatalogInfo->Flags &
  4382. (CATINFO_FLAG_AUTHENTICODE_SIGNED | CATINFO_FLAG_PROMPT_FOR_TRUST))
  4383. );
  4384. rc = _VerifyFile(LogContext,
  4385. &(Queue->VerifyContext),
  4386. QueueNode->CatalogInfo->CatalogFilenameOnSystem,
  4387. NULL,
  4388. 0,
  4389. Key,
  4390. FileToVerifyFullPath,
  4391. Problem,
  4392. ProblemFile,
  4393. TRUE,
  4394. AltPlatformInfo,
  4395. Flags,
  4396. CatalogFileUsed,
  4397. NULL,
  4398. DigitalSigner,
  4399. SignerVersion,
  4400. hWVTStateData
  4401. );
  4402. }
  4403. } else {
  4404. //
  4405. // The INF didn't specify a Catalog= entry. This indicates we
  4406. // should perform global validation, except when we're doing
  4407. // Authenticode-based verification (which must be performed in
  4408. // the context of a specific catalog explicitly identified by the
  4409. // INF).
  4410. //
  4411. if(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG) {
  4412. if(QueueNode->CatalogInfo->VerificationFailureError != NO_ERROR) {
  4413. rc = QueueNode->CatalogInfo->VerificationFailureError;
  4414. } else {
  4415. rc = ERROR_NO_AUTHENTICODE_CATALOG;
  4416. }
  4417. if((rc == ERROR_NO_CATALOG_FOR_OEM_INF) ||
  4418. (rc == ERROR_NO_AUTHENTICODE_CATALOG)) {
  4419. //
  4420. // The failure is the INF's fault (it's an OEM INF that
  4421. // copies files without specifying a catalog). Blame
  4422. // the INF, not the file being copied.
  4423. //
  4424. *Problem = SetupapiVerifyInfProblem;
  4425. MYASSERT(QueueNode->CatalogInfo->InfFullPath != -1);
  4426. InfFullPath = pSetupStringTableStringFromId(
  4427. Queue->StringTable,
  4428. QueueNode->CatalogInfo->InfFullPath
  4429. );
  4430. MYASSERT(InfFullPath);
  4431. StringCchCopy(ProblemFile, MAX_PATH, InfFullPath);
  4432. } else {
  4433. //
  4434. // We previously failed to validate the catalog file
  4435. // associated with this queue node.
  4436. //
  4437. *Problem = SetupapiVerifyFileNotSigned;
  4438. //
  4439. // If the caller didn't supply us with an original
  4440. // source filepath (which will be taken care of later),
  4441. // go ahead and copy the path of the file that was to
  4442. // be verified.
  4443. //
  4444. if(!OriginalSourceFileFullPath) {
  4445. StringCchCopy(ProblemFile, MAX_PATH, FileToVerifyFullPath);
  4446. }
  4447. }
  4448. } else {
  4449. //
  4450. // If there's no error associated with this catalog info node,
  4451. // then we simply need to do global validation. If there is an
  4452. // error then we still need to check if the driver is in the
  4453. // bad driver database.
  4454. //
  4455. // If the queue has an alternate default catalog file
  4456. // associated with it, then retrieve that catalog's name for
  4457. // use later.
  4458. //
  4459. AltCatalogFile = (Queue->AltCatalogFile != -1)
  4460. ? pSetupStringTableStringFromId(Queue->StringTable, Queue->AltCatalogFile)
  4461. : NULL;
  4462. rc = _VerifyFile(LogContext,
  4463. &(Queue->VerifyContext),
  4464. AltCatalogFile,
  4465. NULL,
  4466. 0,
  4467. Key,
  4468. FileToVerifyFullPath,
  4469. Problem,
  4470. ProblemFile,
  4471. FALSE,
  4472. AltPlatformInfo,
  4473. Flags |
  4474. ((QueueNode->CatalogInfo->VerificationFailureError == NO_ERROR)
  4475. ? 0
  4476. : VERIFY_FILE_DRIVERBLOCKED_ONLY),
  4477. CatalogFileUsed,
  4478. NULL,
  4479. DigitalSigner,
  4480. SignerVersion,
  4481. NULL
  4482. );
  4483. if((rc == NO_ERROR) &&
  4484. (QueueNode->CatalogInfo->VerificationFailureError != NO_ERROR)) {
  4485. //
  4486. // If there is an error associated with this catalog info
  4487. // node and the file was not in the bad driver database
  4488. // then return the error.
  4489. //
  4490. rc = QueueNode->CatalogInfo->VerificationFailureError;
  4491. if(rc == ERROR_NO_CATALOG_FOR_OEM_INF) {
  4492. //
  4493. // The failure is the INF's fault (it's an OEM INF that
  4494. // copies files without specifying a catalog). Blame
  4495. // the INF, not the file being copied.
  4496. //
  4497. *Problem = SetupapiVerifyInfProblem;
  4498. MYASSERT(QueueNode->CatalogInfo->InfFullPath != -1);
  4499. InfFullPath = pSetupStringTableStringFromId(
  4500. Queue->StringTable,
  4501. QueueNode->CatalogInfo->InfFullPath
  4502. );
  4503. StringCchCopy(ProblemFile, MAX_PATH, InfFullPath);
  4504. } else {
  4505. //
  4506. // We previously failed to validate the catalog file
  4507. // associated with this queue node.
  4508. //
  4509. *Problem = SetupapiVerifyFileNotSigned;
  4510. //
  4511. // If the caller didn't supply us with an original
  4512. // source filepath (which will be taken care of later),
  4513. // go ahead and copy the path of the file that was to
  4514. // be verified.
  4515. //
  4516. if(!OriginalSourceFileFullPath) {
  4517. StringCchCopy(ProblemFile, MAX_PATH, FileToVerifyFullPath);
  4518. }
  4519. }
  4520. }
  4521. }
  4522. }
  4523. } else {
  4524. //
  4525. // We have no queue, or we couldn't associate this source file back
  4526. // to a catalog info node that tells us exactly which catalog to use
  4527. // for verification. Thus, we'll have to settle for global validation.
  4528. // (Except in the Authenticode case, where global validation isn't
  4529. // allowed.)
  4530. //
  4531. if(Flags & VERIFY_FILE_USE_AUTHENTICODE_CATALOG) {
  4532. rc = ERROR_NO_AUTHENTICODE_CATALOG;
  4533. //
  4534. // In this case, we have to blame the file, because we don't have
  4535. // an INF to blame.
  4536. //
  4537. *Problem = SetupapiVerifyFileNotSigned;
  4538. //
  4539. // If the caller didn't supply us with an original source filepath
  4540. // (which will be taken care of later), go ahead and copy the path
  4541. // of the file that was to be verified.
  4542. //
  4543. if(!OriginalSourceFileFullPath) {
  4544. StringCchCopy(ProblemFile, MAX_PATH, FileToVerifyFullPath);
  4545. }
  4546. } else {
  4547. BOOL InfIsBad = FALSE;
  4548. rc = NO_ERROR;
  4549. if(Queue) {
  4550. if(Queue->AltCatalogFile == -1) {
  4551. if(QueueNode && (QueueNode->InternalFlags & IQF_FROM_BAD_OEM_INF)) {
  4552. InfIsBad = TRUE;
  4553. }
  4554. AltCatalogFile = NULL;
  4555. } else {
  4556. //
  4557. // We have an alternate catalog file to use instead of global
  4558. // validation.
  4559. //
  4560. AltCatalogFile = pSetupStringTableStringFromId(Queue->StringTable, Queue->AltCatalogFile);
  4561. }
  4562. } else {
  4563. AltCatalogFile = NULL;
  4564. }
  4565. rc = _VerifyFile(LogContext,
  4566. Queue ? &(Queue->VerifyContext) : NULL,
  4567. AltCatalogFile,
  4568. NULL,
  4569. 0,
  4570. Key,
  4571. FileToVerifyFullPath,
  4572. Problem,
  4573. ProblemFile,
  4574. FALSE,
  4575. AltPlatformInfo,
  4576. Flags |
  4577. (InfIsBad ? VERIFY_FILE_DRIVERBLOCKED_ONLY : 0),
  4578. CatalogFileUsed,
  4579. NULL,
  4580. DigitalSigner,
  4581. SignerVersion,
  4582. NULL
  4583. );
  4584. if(rc == NO_ERROR) {
  4585. if(InfIsBad) {
  4586. //
  4587. // The driver file was not blocked, but the INF was bad so
  4588. // set the appropriate error and problem values.
  4589. //
  4590. rc = ERROR_NO_CATALOG_FOR_OEM_INF;
  4591. *Problem = SetupapiVerifyFileProblem;
  4592. StringCchCopy(ProblemFile, MAX_PATH, FileToVerifyFullPath);
  4593. }
  4594. }
  4595. }
  4596. }
  4597. //
  4598. // If the problem was with the file (as opposed to with the catalog), then
  4599. // use the real source name, if supplied, as opposed to the temporary
  4600. // filename we passed into _VerifyFile.
  4601. //
  4602. if((rc != NO_ERROR) &&
  4603. (rc != ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) &&
  4604. (rc != ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  4605. if(OriginalSourceFileFullPath &&
  4606. ((*Problem == SetupapiVerifyFileNotSigned) || (*Problem == SetupapiVerifyFileProblem))) {
  4607. StringCchCopy(ProblemFile, MAX_PATH, OriginalSourceFileFullPath);
  4608. }
  4609. }
  4610. return rc;
  4611. }
  4612. DWORD
  4613. VerifyDeviceInfFile(
  4614. IN PSETUP_LOG_CONTEXT LogContext,
  4615. IN OUT PVERIFY_CONTEXT VerifyContext, OPTIONAL
  4616. IN LPCTSTR CurrentInfName,
  4617. IN PLOADED_INF pInf,
  4618. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  4619. OUT LPTSTR CatalogFileUsed, OPTIONAL
  4620. OUT LPTSTR DigitalSigner, OPTIONAL
  4621. OUT LPTSTR SignerVersion, OPTIONAL
  4622. IN DWORD Flags,
  4623. OUT HANDLE *hWVTStateData OPTIONAL
  4624. )
  4625. /*++
  4626. Routine Description:
  4627. This routine performs a digital signature verification on the specified
  4628. INF file.
  4629. Arguments:
  4630. LogContext - supplies the log context to be used in logging an error if
  4631. we encounter an error.
  4632. VerifyContext - optionally, supplies the address of a structure that caches
  4633. various verification context handles. These handles may be NULL (if
  4634. not previously acquired, and they may be filled in upon return (in
  4635. either success or failure) if they were acquired during the processing
  4636. of this verification request. It is the caller's responsibility to
  4637. free these various context handles when they are no longer needed by
  4638. calling pSetupFreeVerifyContextMembers.
  4639. CurrentInfName - supplies the full path to the INF to be validated
  4640. pInf - supplies a pointer to the LOADED_INF structure corresponding to this
  4641. INF.
  4642. AltPlatformInfo - optionally, supplies alternate platform information to
  4643. be used when validating this INF.
  4644. CatalogFileUsed - optionally, supplies a character buffer that must be at
  4645. least MAX_PATH characters in size. Upon successful return, this buffer
  4646. will be filled in with the catalog file used to validate the INF.
  4647. DigitalSigner - optionally, supplies a character buffer that must be at
  4648. least MAX_PATH characters in size. Upon successful return, this buffer
  4649. will be filled in with the name of the signer.
  4650. SignerVersion - optionally, supplies a character buffer that must be at
  4651. least MAX_PATH characters in size. Upon successful return, this buffer
  4652. will be filled in with the signer version information.
  4653. Flags - supplies flags that alter the behavior of this routine. May be a
  4654. combination of the following values:
  4655. VERIFY_INF_USE_AUTHENTICODE_CATALOG - Validate the file using a
  4656. catalog signed with Authenticode
  4657. policy. If this flag is set,
  4658. we'll _only_ check for
  4659. Authenticode signatures, so if
  4660. the caller wants to first try
  4661. validating a file for OS code-
  4662. signing usage, then falling back
  4663. to Authenticode, they'll have to
  4664. call this routine twice.
  4665. If this flag is set, then the
  4666. caller may also supply the
  4667. hWVTStateData output parameter,
  4668. which can be used to prompt user
  4669. in order to establish that the
  4670. publisher should be trusted.
  4671. VerifyDeviceInfFile will return
  4672. one of two error codes upon
  4673. successful validation via
  4674. Authenticode policy. Refer to
  4675. the "Return Value" section for
  4676. details.
  4677. hWVTStateData - if supplied, this parameter points to a buffer that
  4678. receives a handle to WinVerifyTrust state data. This handle will be
  4679. returned only when validation was successfully performed using
  4680. Authenticode policy. This handle may be used, for example, to retrieve
  4681. signer info when prompting the user about whether they trust the
  4682. publisher. (The status code returned will indicate whether or not this
  4683. is necessary, see "Return Value" section below.)
  4684. This parameter should only be supplied if the
  4685. VERIFY_INF_USE_AUTHENTICODE_CATALOG bit is set in the supplied Flags.
  4686. If the routine fails, then this handle will be set to NULL.
  4687. It is the caller's responsibility to close this handle when they're
  4688. finished with it by calling pSetupCloseWVTStateData().
  4689. Return Value:
  4690. If the INF was successfully validated via driver signing policy, then the
  4691. return value is NO_ERROR.
  4692. If the INF was successfully validated via Authenticode policy, and the
  4693. publisher was in the TrustedPublisher store, then the return value is
  4694. ERROR_AUTHENTICODE_TRUSTED_PUBLISHER.
  4695. If the INF was successfully validated via Authenticode policy, and the
  4696. publisher was not in the TrustedPublisher store (hence we must prompt the
  4697. user to establish their trust of the publisher), then the return value is
  4698. ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED
  4699. If a failure occurred, the return value is a Win32 error code indicating
  4700. the cause of the failure.
  4701. --*/
  4702. {
  4703. BOOL DifferentOriginalName;
  4704. TCHAR OriginalCatalogName[MAX_PATH];
  4705. TCHAR CatalogPath[MAX_PATH];
  4706. TCHAR OriginalInfFileName[MAX_PATH];
  4707. PTSTR p;
  4708. DWORD Err;
  4709. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform;
  4710. DWORD VerificationPolicyToUse;
  4711. //
  4712. // Initialize the output handle for WinVerifyTrust state data.
  4713. //
  4714. if(hWVTStateData) {
  4715. *hWVTStateData = NULL;
  4716. }
  4717. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  4718. //
  4719. // Nobody had better be calling this expecting to get back any info
  4720. // about a successful verification!
  4721. //
  4722. MYASSERT(!CatalogFileUsed);
  4723. MYASSERT(!DigitalSigner);
  4724. MYASSERT(!SignerVersion);
  4725. //
  4726. // Likewise, we'd better not be called asking to validate using
  4727. // Authenticode policy (and hence, to return WinVerifyTrust state data
  4728. // regarding the signing certificate).
  4729. //
  4730. MYASSERT(!(Flags & VERIFY_INF_USE_AUTHENTICODE_CATALOG));
  4731. return NO_ERROR;
  4732. }
  4733. //
  4734. // If the caller requested that we return WinVerifyTrust state data upon
  4735. // successful Authenticode validation, then they'd better have actually
  4736. // requested Authenticode validation!
  4737. //
  4738. MYASSERT(!hWVTStateData || (Flags & VERIFY_INF_USE_AUTHENTICODE_CATALOG));
  4739. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  4740. return TRUST_E_FAIL;
  4741. }
  4742. CatalogPath[0] = TEXT('\0');
  4743. Err = pGetInfOriginalNameAndCatalogFile(pInf,
  4744. NULL,
  4745. &DifferentOriginalName,
  4746. OriginalInfFileName,
  4747. SIZECHARS(OriginalInfFileName),
  4748. OriginalCatalogName,
  4749. SIZECHARS(OriginalCatalogName),
  4750. AltPlatformInfo
  4751. );
  4752. if(Err != NO_ERROR) {
  4753. return Err;
  4754. }
  4755. if(pSetupInfIsFromOemLocation(CurrentInfName, TRUE)) {
  4756. //
  4757. // INF isn't in %windir%\Inf (i.e., it's 3rd-party), so it had better
  4758. // specify a catalog file...
  4759. //
  4760. if(!*OriginalCatalogName) {
  4761. return ERROR_NO_CATALOG_FOR_OEM_INF;
  4762. }
  4763. //
  4764. // ...and the CAT must reside in the same directory as the INF.
  4765. //
  4766. if(FAILED(StringCchCopy(CatalogPath, SIZECHARS(CatalogPath), CurrentInfName))) {
  4767. return ERROR_PATH_NOT_FOUND;
  4768. }
  4769. p = (PTSTR)pSetupGetFileTitle(CatalogPath);
  4770. if(FAILED(StringCchCopy(p, SIZECHARS(CatalogPath)-(p-CatalogPath), OriginalCatalogName))) {
  4771. return ERROR_PATH_NOT_FOUND;
  4772. }
  4773. } else {
  4774. //
  4775. // The INF lives in %windir%\Inf.
  4776. // If it is a 3rd party INF then we want to set the CatalogPath to
  4777. // the current INF name with .CAT at the end instead of .INF (e.g
  4778. // oem1.cat). If this is not an OEM catalog then we won't set the
  4779. // CatalogPath so we can search all of the catalogs in the system.
  4780. //
  4781. // We will assume that if the INF had a different original name.
  4782. //
  4783. if(DifferentOriginalName) {
  4784. p = (PTSTR)pSetupGetFileTitle(CurrentInfName);
  4785. if(FAILED(StringCchCopy(CatalogPath, SIZECHARS(CatalogPath), p))) {
  4786. return ERROR_PATH_NOT_FOUND;
  4787. }
  4788. p = _tcsrchr(CatalogPath, TEXT('.'));
  4789. if(!p) {
  4790. p = CatalogPath+lstrlen(CatalogPath);
  4791. }
  4792. if(FAILED(StringCchCopy(p,SIZECHARS(CatalogPath)-(p-CatalogPath),pszCatSuffix))) {
  4793. return ERROR_PATH_NOT_FOUND;
  4794. }
  4795. }
  4796. }
  4797. if(DifferentOriginalName) {
  4798. MYASSERT(*OriginalInfFileName);
  4799. } else {
  4800. //
  4801. // INF's current name is the same as its original name, so store the
  4802. // simple filename (sans path) for use as the validation key in the
  4803. // upcoming call to _VerifyFile.
  4804. //
  4805. StringCchCopy(OriginalInfFileName, SIZECHARS(OriginalInfFileName),pSetupGetFileTitle(CurrentInfName));
  4806. }
  4807. //
  4808. // If the caller didn't supply alternate platform information, we need to
  4809. // check and see whether a range of OSATTR versions should be considered
  4810. // valid for this INF's class.
  4811. //
  4812. if(!AltPlatformInfo) {
  4813. IsInfForDeviceInstall(LogContext,
  4814. NULL,
  4815. pInf,
  4816. NULL,
  4817. &ValidationPlatform,
  4818. &VerificationPolicyToUse,
  4819. NULL,
  4820. FALSE
  4821. );
  4822. } else {
  4823. ValidationPlatform = NULL;
  4824. //
  4825. // We still need to find out what verification policy is in effect, in
  4826. // order to determine whether we can use Authenticode policy.
  4827. //
  4828. IsInfForDeviceInstall(LogContext,
  4829. NULL,
  4830. pInf,
  4831. NULL,
  4832. NULL,
  4833. &VerificationPolicyToUse,
  4834. NULL,
  4835. FALSE
  4836. );
  4837. }
  4838. try {
  4839. if(Flags & VERIFY_INF_USE_AUTHENTICODE_CATALOG) {
  4840. if(!(VerificationPolicyToUse & DRIVERSIGN_ALLOW_AUTHENTICODE)) {
  4841. //
  4842. // Authenticode policy can't be used for this INF!
  4843. //
  4844. Err = ERROR_AUTHENTICODE_DISALLOWED;
  4845. leave;
  4846. }
  4847. if(!*CatalogPath) {
  4848. //
  4849. // Authenticode-signed INFs must expicitly reference a catalog.
  4850. //
  4851. Err = ERROR_NO_AUTHENTICODE_CATALOG;
  4852. leave;
  4853. }
  4854. Err = _VerifyFile(LogContext,
  4855. VerifyContext,
  4856. CatalogPath,
  4857. NULL,
  4858. 0,
  4859. OriginalInfFileName,
  4860. CurrentInfName,
  4861. NULL,
  4862. NULL,
  4863. FALSE,
  4864. (AltPlatformInfo ? AltPlatformInfo : ValidationPlatform),
  4865. (VERIFY_FILE_IGNORE_SELFSIGNED
  4866. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK
  4867. | VERIFY_FILE_USE_AUTHENTICODE_CATALOG),
  4868. CatalogFileUsed,
  4869. NULL,
  4870. DigitalSigner,
  4871. SignerVersion,
  4872. hWVTStateData
  4873. );
  4874. } else {
  4875. //
  4876. // Perform standard drivers signing verification.
  4877. //
  4878. Err = _VerifyFile(LogContext,
  4879. VerifyContext,
  4880. (*CatalogPath ? CatalogPath : NULL),
  4881. NULL,
  4882. 0,
  4883. OriginalInfFileName,
  4884. CurrentInfName,
  4885. NULL,
  4886. NULL,
  4887. FALSE,
  4888. (AltPlatformInfo ? AltPlatformInfo : ValidationPlatform),
  4889. (VERIFY_FILE_IGNORE_SELFSIGNED
  4890. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4891. CatalogFileUsed,
  4892. NULL,
  4893. DigitalSigner,
  4894. SignerVersion,
  4895. NULL
  4896. );
  4897. }
  4898. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4899. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  4900. }
  4901. if(ValidationPlatform) {
  4902. MyFree(ValidationPlatform);
  4903. }
  4904. return Err;
  4905. }
  4906. BOOL
  4907. IsFileProtected(
  4908. IN LPCTSTR FileFullPath,
  4909. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  4910. OUT PHANDLE phSfp OPTIONAL
  4911. )
  4912. /*++
  4913. Routine Description:
  4914. This routine determines whether the specified file is a protected system
  4915. file.
  4916. Arguments:
  4917. FileFullPath - supplies the full path to the file of interest
  4918. LogContext - supplies the log context to be used in logging an error if
  4919. we're unable to open an SFC handle.
  4920. phSfp - optionally, supplies the address of a handle variable that will be
  4921. filled in with a handle to the SFC server. This will only be supplied
  4922. when the routine returns TRUE (i.e., the file is SFP-protected).
  4923. Return Value:
  4924. If the file is protected, the return value is TRUE, otherwise it is FALSE.
  4925. --*/
  4926. {
  4927. BOOL ret;
  4928. HANDLE hSfp;
  4929. hSfp = SfcConnectToServer(NULL);
  4930. if(!hSfp) {
  4931. //
  4932. // This ain't good...
  4933. //
  4934. WriteLogEntry(LogContext,
  4935. SETUP_LOG_ERROR,
  4936. MSG_LOG_SFC_CONNECT_FAILED,
  4937. NULL
  4938. );
  4939. return FALSE;
  4940. }
  4941. try {
  4942. ret = SfcIsFileProtected(hSfp, FileFullPath);
  4943. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4944. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4945. ret = FALSE;
  4946. }
  4947. //
  4948. // If the file _is_ protected, and the caller wants the SFP handle (e.g.,
  4949. // to subsequently exempt an unsigned replacement operation), then save
  4950. // the handle in the caller-supplied buffer. Otherwise, close the handle.
  4951. //
  4952. if(ret && phSfp) {
  4953. *phSfp = hSfp;
  4954. } else {
  4955. SfcClose(hSfp);
  4956. }
  4957. return ret;
  4958. }
  4959. PSTR
  4960. GetAnsiMuiSafePathname(
  4961. IN PCTSTR FilePath
  4962. )
  4963. /*++
  4964. Routine Description:
  4965. Remove filename portion of FilePath
  4966. and convert rest of path to be MUI parse safe
  4967. Note that the returned pathname is such that the FileName can be cat'd
  4968. so for "E:\i386\myfile.dl_" FilePath = "E:\i386\" and
  4969. FileName = "myfile.dl_"
  4970. *This is required* (it also happens to make this code easier)
  4971. Arguments:
  4972. FilePath - path+filename to convert
  4973. Return Value:
  4974. If successful, the return value is pointer to ANSI filepath (memory
  4975. allocated by pSetupMalloc)
  4976. If unsuccessful, the return value is NULL and GetLastError returns error
  4977. --*/
  4978. {
  4979. TCHAR Buffer[MAX_PATH];
  4980. LPTSTR FilePart;
  4981. DWORD actsz;
  4982. actsz = GetFullPathName(FilePath,MAX_PATH,Buffer,&FilePart);
  4983. if(actsz == 0) {
  4984. //
  4985. // GetLastError has error
  4986. //
  4987. return NULL;
  4988. }
  4989. if(actsz >= MAX_PATH) {
  4990. //
  4991. // can't do anything with this path
  4992. //
  4993. SetLastError(ERROR_INVALID_DATA);
  4994. return NULL;
  4995. }
  4996. if(!FilePart) {
  4997. //
  4998. // Since GetFullPathName couldn't find the beginning of the filename,
  4999. // assume this means we were handed a simple filename (sans path).
  5000. //
  5001. *Buffer = TEXT('\0');
  5002. } else {
  5003. //
  5004. // Strip the filename from the path.
  5005. //
  5006. *FilePart = TEXT('\0');
  5007. }
  5008. return GetAnsiMuiSafeFilename(Buffer);
  5009. }
  5010. PSTR
  5011. GetAnsiMuiSafeFilename(
  5012. IN PCTSTR FilePath
  5013. )
  5014. /*++
  5015. Routine Description:
  5016. Convert FilePath, which is a native file path to one that is safe to parse
  5017. by ansi API's in an MUI environment.
  5018. returned pointer is allocated and should be free'd
  5019. Arguments:
  5020. FilePath - path to convert (may be an empty string)
  5021. Return Value:
  5022. If successful, the return value is pointer to ANSI filepath (memory
  5023. allocated by pSetupMalloc)
  5024. If unsuccessful, the return value is NULL and GetLastError returns error
  5025. --*/
  5026. {
  5027. TCHAR Buffer[MAX_PATH];
  5028. PTSTR p;
  5029. PSTR ansiPath;
  5030. DWORD actsz;
  5031. DWORD err;
  5032. //
  5033. // NTRAID#NTBUG9-644041-2002/04/12-lonnym -- logic fails if short pathname support is turned off
  5034. //
  5035. actsz = GetShortPathName(FilePath,Buffer,MAX_PATH);
  5036. if(actsz >= MAX_PATH) {
  5037. //
  5038. // file path too big
  5039. //
  5040. SetLastError(ERROR_INVALID_DATA);
  5041. return NULL;
  5042. }
  5043. if(!actsz) {
  5044. //
  5045. // some other error - resort back the current path name
  5046. //
  5047. if(FAILED(StringCchCopy(Buffer,MAX_PATH,FilePath))) {
  5048. SetLastError(ERROR_INVALID_DATA);
  5049. return NULL;
  5050. }
  5051. }
  5052. //
  5053. // convert to ansi now we've (if we can) converted to short path name
  5054. //
  5055. ansiPath = pSetupUnicodeToAnsi(Buffer);
  5056. if(!ansiPath) {
  5057. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  5058. return NULL;
  5059. }
  5060. return ansiPath;
  5061. }
  5062. BOOL
  5063. pSetupAppendPath(
  5064. IN PCTSTR Path1, OPTIONAL
  5065. IN PCTSTR Path2, OPTIONAL
  5066. OUT PTSTR *Combined
  5067. )
  5068. /*++
  5069. Routine Description:
  5070. Call pSetupConcatenatePaths dynamically modifying memory/pointer
  5071. Arguments:
  5072. Path1/Path2 - Optionally, supplies paths to concatenate
  5073. Combined - resultant path (must be freed via MyFree)
  5074. Return Value:
  5075. TRUE if we successfully concatenated the paths into a newly-allocated
  5076. buffer.
  5077. FALSE otherwise.
  5078. Notes:
  5079. If both Path1 and Path2 are NULL, we will return a buffer containing a
  5080. single NULL character (i.e., an empty string).
  5081. --*/
  5082. {
  5083. PTSTR FinalPath;
  5084. UINT Len;
  5085. BOOL b;
  5086. if(!Path1 && !Path2) {
  5087. *Combined = MyMalloc(sizeof(TCHAR));
  5088. if(*Combined) {
  5089. **Combined = TEXT('\0');
  5090. return TRUE;
  5091. } else {
  5092. return FALSE;
  5093. }
  5094. }
  5095. if(!Path1) {
  5096. *Combined = DuplicateString(Path2);
  5097. return *Combined ? TRUE : FALSE;
  5098. }
  5099. if(!Path2) {
  5100. *Combined = DuplicateString(Path1);
  5101. return *Combined ? TRUE : FALSE;
  5102. }
  5103. Len = lstrlen(Path1)+lstrlen(Path2)+2; // slash and null
  5104. FinalPath = MyMalloc(Len*sizeof(TCHAR));
  5105. if(!FinalPath) {
  5106. *Combined = NULL;
  5107. return FALSE;
  5108. }
  5109. try {
  5110. StringCchCopy(FinalPath, Len, Path1);
  5111. b = pSetupConcatenatePaths(FinalPath, Path2, Len, NULL);
  5112. } except(pSetupExceptionFilter(GetExceptionCode())) {
  5113. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  5114. b = FALSE;
  5115. }
  5116. if(!b) {
  5117. MyFree(FinalPath);
  5118. FinalPath = NULL;
  5119. }
  5120. *Combined = FinalPath;
  5121. return b;
  5122. }
  5123. BOOL
  5124. pSetupApplyExtension(
  5125. IN PCTSTR Original,
  5126. IN PCTSTR Extension, OPTIONAL
  5127. OUT PTSTR* NewName
  5128. )
  5129. /*++
  5130. Routine Description:
  5131. Apply Extension onto Original to obtain NewName
  5132. Arguments:
  5133. Original - original filename (may include path) with old extension
  5134. Extension - new extension to apply (with or without dot), if NULL, deletes
  5135. NewName - allocated buffer containing new filename (must be freed via
  5136. MyFree)
  5137. Return Value:
  5138. TRUE if modified filename was successfully returned in newly-allocated
  5139. buffer.
  5140. FALSE otherwise.
  5141. --*/
  5142. {
  5143. PCTSTR End = Original+lstrlen(Original);
  5144. PCTSTR OldExt = End;
  5145. PTSTR NewString = NULL;
  5146. TCHAR c;
  5147. UINT len;
  5148. UINT sublen;
  5149. if(Extension && (*Extension == TEXT('.'))) {
  5150. Extension++;
  5151. }
  5152. while(End != Original) {
  5153. End = CharPrev(Original, End);
  5154. if((*End == TEXT('/')) || (*End == TEXT('\\'))) {
  5155. break;
  5156. }
  5157. if(*End == TEXT('.')) {
  5158. OldExt = End;
  5159. break;
  5160. }
  5161. }
  5162. sublen = (UINT)(OldExt-Original);
  5163. len = sublen + (Extension ? lstrlen(Extension) : 0) + 2;
  5164. NewString = MyMalloc(len*sizeof(TCHAR));
  5165. if(!NewString) {
  5166. *NewName = NULL;
  5167. return FALSE;
  5168. }
  5169. try {
  5170. CopyMemory(NewString, Original, sublen * sizeof(TCHAR));
  5171. NewString[sublen++] = Extension ? TEXT('.') : TEXT('\0');
  5172. if(Extension) {
  5173. MYVERIFY(SUCCEEDED(StringCchCopy(NewString + sublen,
  5174. len - sublen,
  5175. Extension))
  5176. );
  5177. }
  5178. } except(pSetupExceptionFilter(GetExceptionCode())) {
  5179. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  5180. MyFree(NewString);
  5181. NewString = NULL;
  5182. }
  5183. *NewName = NewString;
  5184. return (NewString != NULL);
  5185. }
  5186. BOOL
  5187. ClassGuidInDrvSignPolicyList(
  5188. IN PSETUP_LOG_CONTEXT OptLogContext, OPTIONAL
  5189. IN CONST GUID *DeviceSetupClassGuid,
  5190. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform OPTIONAL
  5191. )
  5192. /*++
  5193. Routine Description:
  5194. This routine determines whether the specified device setup class is among
  5195. the list of classes for which driver signing policy is applicable (i.e., as
  5196. indicated by the class's inclusion in the [DriverSigningClasses] section of
  5197. %windir%\Inf\certclas.inf). Additionally, if an non-native signature
  5198. validation lower-bound is applicable, a newly-allocated alternate platform
  5199. info structure is returned to the caller (if requested) to be used in
  5200. subsequent validation attempts associated with this class.
  5201. Arguments:
  5202. LogContext - Optionally, supplies the log context for any log entries that
  5203. might be generated by this routine.
  5204. DeviceSetupClassGuid - Supplies the address of the GUID we're attempting to
  5205. find in our driver signing policy list.
  5206. ValidationPlatform - Optionally, supplies the address of a (version 2)
  5207. altplatform info pointer (initialized to NULL) that is filled in upon
  5208. return with a newly-allocated structure specifying the appropriate
  5209. parameters to be passed to WinVerifyTrust when validating this INF.
  5210. These parameters are retrieved from certclas.inf for the relevant
  5211. device setup class GUID. If no special parameters are specified for
  5212. this class (or if the INF has no class at all), then this pointer is
  5213. not modified (i.e., left as NULL) causing us to use WinVerifyTrust's
  5214. default validation. Note that if we fail to allocate this structure
  5215. due to low-memory, the pointer will be left as NULL in that case as
  5216. well. This is OK, because this simply means we'll do default
  5217. validation in that case.
  5218. The caller is responsible for freeing the memory allocated for this
  5219. structure.
  5220. Return Value:
  5221. If the device setup class is in our driver signing policy list, the return
  5222. value is non-zero (TRUE). Otherwise, it is FALSE.
  5223. --*/
  5224. {
  5225. DWORD Err;
  5226. BOOL UseDrvSignPolicy;
  5227. INT i;
  5228. TCHAR CertClassInfPath[MAX_PATH];
  5229. HINF hCertClassInf = INVALID_HANDLE_VALUE;
  5230. INFCONTEXT InfContext;
  5231. UINT ErrorLine;
  5232. LONG LineCount;
  5233. PCTSTR GuidString;
  5234. PSETUP_LOG_CONTEXT LogContext = NULL;
  5235. //
  5236. // Default is to lump all device installs under driver signing policy
  5237. //
  5238. UseDrvSignPolicy = TRUE;
  5239. //
  5240. // If the caller supplied the ValidationPlatform parameter it must be
  5241. // pointing to a NULL pointer...
  5242. //
  5243. MYASSERT(!ValidationPlatform || !*ValidationPlatform);
  5244. if(!LockDrvSignPolicyList(&GlobalDrvSignPolicyList)) {
  5245. return UseDrvSignPolicy;
  5246. }
  5247. try {
  5248. InheritLogContext(OptLogContext, &LogContext); // want to group logging
  5249. if(GlobalDrvSignPolicyList.NumMembers == -1) {
  5250. //
  5251. // We've not yet retrieved the list from certclas.inf. First,
  5252. // verify the INF to make sure no one has tampered with it...
  5253. //
  5254. LPTSTR strp = CertClassInfPath;
  5255. size_t strl = SIZECHARS(CertClassInfPath);
  5256. if(FAILED(StringCchCopyEx(strp,strl,InfDirectory,&strp,&strl,0)) ||
  5257. FAILED(StringCchCopy(strp,strl,TEXT("\\certclas.inf")))) {
  5258. Err = ERROR_PATH_NOT_FOUND;
  5259. } else {
  5260. Err = _VerifyFile(LogContext,
  5261. NULL,
  5262. NULL,
  5263. NULL,
  5264. 0,
  5265. pSetupGetFileTitle(CertClassInfPath),
  5266. CertClassInfPath,
  5267. NULL,
  5268. NULL,
  5269. FALSE,
  5270. NULL,
  5271. (VERIFY_FILE_IGNORE_SELFSIGNED | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  5272. NULL,
  5273. NULL,
  5274. NULL,
  5275. NULL,
  5276. NULL
  5277. );
  5278. }
  5279. if(Err == NO_ERROR) {
  5280. //
  5281. // Open up driver signing class list INF for use when examining
  5282. // the individual INFs in the LOADED_INF list below.
  5283. //
  5284. Err = GLE_FN_CALL(INVALID_HANDLE_VALUE,
  5285. hCertClassInf = SetupOpenInfFile(
  5286. CertClassInfPath,
  5287. NULL,
  5288. INF_STYLE_WIN4,
  5289. &ErrorLine)
  5290. );
  5291. if(Err != NO_ERROR) {
  5292. //
  5293. // This failure is highly unlikely to occur, since we just
  5294. // got through validating the INF.
  5295. //
  5296. WriteLogEntry(LogContext,
  5297. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  5298. MSG_LOG_CERTCLASS_LOAD_FAILED,
  5299. NULL,
  5300. CertClassInfPath,
  5301. ErrorLine
  5302. );
  5303. }
  5304. } else {
  5305. WriteLogEntry(LogContext,
  5306. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  5307. MSG_LOG_CERTCLASS_INVALID,
  5308. NULL,
  5309. CertClassInfPath
  5310. );
  5311. }
  5312. if(Err != NO_ERROR) {
  5313. //
  5314. // Somebody mucked with/deleted certclas.inf! (Or, much less
  5315. // likely, we encountered some other failure whilst trying to
  5316. // load the INF.) Since we don't know which classes are
  5317. // subject to driver signing policy, we assume they all are.
  5318. //
  5319. WriteLogError(LogContext,
  5320. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  5321. Err
  5322. );
  5323. WriteLogEntry(LogContext,
  5324. SETUP_LOG_WARNING,
  5325. MSG_LOG_DRIVER_SIGNING_FOR_ALL_CLASSES,
  5326. NULL
  5327. );
  5328. //
  5329. // Set the NumMembers field to zero, so we'll know we
  5330. // previously attempted (and failed) to retrieve the list. We
  5331. // do this so we don't keep re-trying to get this list.
  5332. //
  5333. GlobalDrvSignPolicyList.NumMembers = 0;
  5334. leave;
  5335. }
  5336. //
  5337. // Certclas.inf validated, and we successfully opened it. Now
  5338. // retrieve the list contained therein.
  5339. //
  5340. LineCount = SetupGetLineCount(hCertClassInf,
  5341. pszDriverSigningClasses
  5342. );
  5343. MYASSERT(LineCount > 0);
  5344. if((LineCount <= 0) ||
  5345. (NULL == (GlobalDrvSignPolicyList.Members = MyMalloc(LineCount * sizeof(DRVSIGN_CLASS_LIST_NODE))))) {
  5346. leave;
  5347. }
  5348. if(!SetupFindFirstLine(hCertClassInf,
  5349. pszDriverSigningClasses,
  5350. NULL,
  5351. &InfContext)) {
  5352. MYASSERT(FALSE);
  5353. leave;
  5354. }
  5355. i = 0;
  5356. do {
  5357. MYASSERT(i < LineCount);
  5358. //
  5359. // The format of a line in the [DriverSigningClasses]
  5360. // section is as follows:
  5361. //
  5362. // {GUID} [= FirstValidatedMajorVersion, FirstValidatedMinorVersion]
  5363. //
  5364. GuidString = pSetupGetField(&InfContext, 0);
  5365. if(GuidString &&
  5366. (NO_ERROR == pSetupGuidFromString(GuidString, &(GlobalDrvSignPolicyList.Members[i].DeviceSetupClassGuid)))) {
  5367. if(SetupGetIntField(&InfContext, 1, &(GlobalDrvSignPolicyList.Members[i].MajorVerLB)) &&
  5368. SetupGetIntField(&InfContext, 2, &(GlobalDrvSignPolicyList.Members[i].MinorVerLB))) {
  5369. //
  5370. // We successfully retrieved major/minor
  5371. // version info for validation lower-bound.
  5372. // Do a sanity-check on these.
  5373. //
  5374. if(GlobalDrvSignPolicyList.Members[i].MajorVerLB <= 0) {
  5375. GlobalDrvSignPolicyList.Members[i].MajorVerLB = -1;
  5376. GlobalDrvSignPolicyList.Members[i].MinorVerLB = -1;
  5377. }
  5378. } else {
  5379. //
  5380. // Set major/minor version info to -1 to
  5381. // indicate there's no validation platform
  5382. // override.
  5383. //
  5384. GlobalDrvSignPolicyList.Members[i].MajorVerLB = -1;
  5385. GlobalDrvSignPolicyList.Members[i].MinorVerLB = -1;
  5386. }
  5387. i++;
  5388. }
  5389. } while(SetupFindNextLine(&InfContext, &InfContext));
  5390. //
  5391. // Update NumMembers field in our list to indicate the
  5392. // number of class GUID entries we actually found.
  5393. //
  5394. GlobalDrvSignPolicyList.NumMembers = i;
  5395. }
  5396. //
  5397. // We now have a list. If the list is empty, this means we
  5398. // encountered some problem retrieving the list, thus all device
  5399. // classes should be subject to driver signing policy. Otherwise,
  5400. // try to find the caller-specified class in our list.
  5401. //
  5402. if(GlobalDrvSignPolicyList.NumMembers) {
  5403. //
  5404. // OK, we know we have a valid list--now default to non-driver
  5405. // signing policy unless our list search proves fruitful.
  5406. //
  5407. UseDrvSignPolicy = FALSE;
  5408. for(i = 0; i < GlobalDrvSignPolicyList.NumMembers; i++) {
  5409. if(!memcmp(DeviceSetupClassGuid,
  5410. &(GlobalDrvSignPolicyList.Members[i].DeviceSetupClassGuid),
  5411. sizeof(GUID))) {
  5412. //
  5413. // We found a match!
  5414. //
  5415. UseDrvSignPolicy = TRUE;
  5416. //
  5417. // Now, check to see if we have any validation platform
  5418. // override info...
  5419. //
  5420. if(ValidationPlatform &&
  5421. (GlobalDrvSignPolicyList.Members[i].MajorVerLB != -1)) {
  5422. MYASSERT(GlobalDrvSignPolicyList.Members[i].MinorVerLB != -1);
  5423. *ValidationPlatform = MyMalloc(sizeof(SP_ALTPLATFORM_INFO_V2));
  5424. //
  5425. // If the memory allocation fails, we just won't report
  5426. // the altplatform info, so the validation will be done
  5427. // based on the current OS version (instead of widening
  5428. // it up to allow a range of valid versions).
  5429. //
  5430. if(*ValidationPlatform) {
  5431. ZeroMemory(*ValidationPlatform, sizeof(SP_ALTPLATFORM_INFO_V2));
  5432. (*ValidationPlatform)->cbSize = sizeof(SP_ALTPLATFORM_INFO_V2);
  5433. (*ValidationPlatform)->Platform = VER_PLATFORM_WIN32_NT;
  5434. (*ValidationPlatform)->Flags = SP_ALTPLATFORM_FLAGS_VERSION_RANGE;
  5435. (*ValidationPlatform)->MajorVersion = VER_PRODUCTMAJORVERSION;
  5436. (*ValidationPlatform)->MinorVersion = VER_PRODUCTMINORVERSION;
  5437. (*ValidationPlatform)->ProcessorArchitecture =
  5438. #if defined(_X86_)
  5439. PROCESSOR_ARCHITECTURE_INTEL;
  5440. #elif defined(_IA64_)
  5441. PROCESSOR_ARCHITECTURE_IA64;
  5442. #elif defined(_AMD64_)
  5443. PROCESSOR_ARCHITECTURE_AMD64;
  5444. #else
  5445. #error "no target architecture"
  5446. #endif
  5447. (*ValidationPlatform)->FirstValidatedMajorVersion
  5448. = (DWORD)(GlobalDrvSignPolicyList.Members[i].MajorVerLB);
  5449. (*ValidationPlatform)->FirstValidatedMinorVersion
  5450. = (DWORD)(GlobalDrvSignPolicyList.Members[i].MinorVerLB);
  5451. }
  5452. }
  5453. //
  5454. // Since we've found a match, we can break out of the loop.
  5455. //
  5456. break;
  5457. }
  5458. }
  5459. }
  5460. } except(pSetupExceptionFilter(GetExceptionCode())) {
  5461. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  5462. //
  5463. // If we hit an exception, don't trust information in newly-allocated
  5464. // validation platform buffer (if any)
  5465. //
  5466. if(ValidationPlatform && *ValidationPlatform) {
  5467. MyFree(*ValidationPlatform);
  5468. *ValidationPlatform = NULL;
  5469. }
  5470. }
  5471. if(hCertClassInf != INVALID_HANDLE_VALUE) {
  5472. SetupCloseInfFile(hCertClassInf);
  5473. }
  5474. if(LogContext) {
  5475. DeleteLogContext(LogContext);
  5476. }
  5477. UnlockDrvSignPolicyList(&GlobalDrvSignPolicyList);
  5478. return UseDrvSignPolicy;
  5479. }
  5480. BOOL
  5481. InitDrvSignPolicyList(
  5482. VOID
  5483. )
  5484. /*++
  5485. Routine Description:
  5486. This routine initializes the global "Driver Signing Policy" list that is
  5487. retrieved (on first use) from %windir%\Inf\certclas.inf.
  5488. Arguments:
  5489. None
  5490. Return Value:
  5491. If success, the return value is TRUE, otherwise, it is FALSE.
  5492. --*/
  5493. {
  5494. ZeroMemory(&GlobalDrvSignPolicyList, sizeof(DRVSIGN_POLICY_LIST));
  5495. GlobalDrvSignPolicyList.NumMembers = -1;
  5496. return InitializeSynchronizedAccess(&GlobalDrvSignPolicyList.Lock);
  5497. }
  5498. VOID
  5499. DestroyDrvSignPolicyList(
  5500. VOID
  5501. )
  5502. /*++
  5503. Routine Description:
  5504. This routine destroys the global "Driver Signing Policy" list that is
  5505. retrieved (on first use) from %windir%\Inf\certclas.inf.
  5506. Arguments:
  5507. None
  5508. Return Value:
  5509. None
  5510. --*/
  5511. {
  5512. if(LockDrvSignPolicyList(&GlobalDrvSignPolicyList)) {
  5513. if(GlobalDrvSignPolicyList.Members) {
  5514. MyFree(GlobalDrvSignPolicyList.Members);
  5515. }
  5516. DestroySynchronizedAccess(&GlobalDrvSignPolicyList.Lock);
  5517. }
  5518. }
  5519. VOID
  5520. pSetupFreeVerifyContextMembers(
  5521. IN PVERIFY_CONTEXT VerifyContext
  5522. )
  5523. /*++
  5524. Routine Description:
  5525. This routine frees the various context handles contained in the specified
  5526. VerifyContext structure.
  5527. Arguments:
  5528. VerifyContext - supplies a pointer to a verification context structure
  5529. whose non-NULL members are to be freed.
  5530. Return Value:
  5531. None
  5532. --*/
  5533. {
  5534. //
  5535. // Release the crypto context (if there is one)
  5536. //
  5537. if(VerifyContext->hCatAdmin) {
  5538. CryptCATAdminReleaseContext(VerifyContext->hCatAdmin, 0);
  5539. }
  5540. //
  5541. // Release the handle to the bad driver database (if there is one)
  5542. //
  5543. if(VerifyContext->hSDBDrvMain) {
  5544. SdbReleaseDatabase(VerifyContext->hSDBDrvMain);
  5545. }
  5546. //
  5547. // Release the handle to the trusted publisher cert store (if there is
  5548. // one)
  5549. //
  5550. if(VerifyContext->hStoreTrustedPublisher) {
  5551. CertCloseStore(VerifyContext->hStoreTrustedPublisher, 0);
  5552. }
  5553. }
  5554. BOOL
  5555. pSetupIsAuthenticodePublisherTrusted(
  5556. IN PCCERT_CONTEXT CertContext,
  5557. IN OUT HCERTSTORE *hStoreTrustedPublisher OPTIONAL
  5558. )
  5559. /*++
  5560. Routine Description:
  5561. This routine checks to see whether the specified certificate is in the
  5562. "TrustedPublisher" certificate store.
  5563. Arguments:
  5564. CertContext - supplies the certificate context to look for in the
  5565. TrustedPublisher certificate store.
  5566. hStoreTrustedPublisher - optionally, supplies the address of a certificate
  5567. store handle. If the handle pointed to is NULL, a handle will be
  5568. acquired (if possible) via CertOpenStore and returned to the caller.
  5569. If the handle pointed to is non-NULL, then that handle will be used by
  5570. this routine. If the pointer itself is NULL, then an HCERTSTORE will
  5571. be acquired for the duration of this call, and released before
  5572. returning.
  5573. NOTE: it is the caller's responsibility to free the certificate store
  5574. handle returned by this routine by calling CertCloseStore. This handle
  5575. may be opened in either success or failure cases, so the caller must
  5576. check for non-NULL returned handle in both cases.
  5577. Return Value:
  5578. If the certificate was located in the "TrustedPublisher" certificate store,
  5579. the return value is non-zero (i.e., TRUE).
  5580. Otherwise, the return value is FALSE.
  5581. --*/
  5582. {
  5583. BYTE rgbHash[MAX_HASH_LEN];
  5584. CRYPT_DATA_BLOB HashBlob;
  5585. PCCERT_CONTEXT pFoundCert = NULL;
  5586. BOOL IsPublisherTrusted = FALSE;
  5587. HCERTSTORE LocalhStore = NULL;
  5588. try {
  5589. HashBlob.pbData = rgbHash;
  5590. HashBlob.cbData = sizeof(rgbHash);
  5591. if(!CertGetCertificateContextProperty(CertContext,
  5592. CERT_SIGNATURE_HASH_PROP_ID,
  5593. rgbHash,
  5594. &HashBlob.cbData)
  5595. || (MIN_HASH_LEN > HashBlob.cbData))
  5596. {
  5597. leave;
  5598. }
  5599. //
  5600. // Check if trusted publisher
  5601. //
  5602. if(hStoreTrustedPublisher && *hStoreTrustedPublisher) {
  5603. LocalhStore = *hStoreTrustedPublisher;
  5604. } else {
  5605. LocalhStore = CertOpenStore(
  5606. CERT_STORE_PROV_SYSTEM_W,
  5607. 0,
  5608. (HCRYPTPROV)NULL,
  5609. (CERT_SYSTEM_STORE_CURRENT_USER |
  5610. CERT_STORE_MAXIMUM_ALLOWED_FLAG |
  5611. CERT_STORE_SHARE_CONTEXT_FLAG),
  5612. (const void *) L"TrustedPublisher"
  5613. );
  5614. if(!LocalhStore) {
  5615. leave;
  5616. }
  5617. //
  5618. // Try to setup for auto-resync, but it's not a critical failure if
  5619. // we can't do this...
  5620. //
  5621. CertControlStore(LocalhStore,
  5622. 0,
  5623. CERT_STORE_CTRL_AUTO_RESYNC,
  5624. NULL
  5625. );
  5626. if(hStoreTrustedPublisher) {
  5627. *hStoreTrustedPublisher = LocalhStore;
  5628. }
  5629. }
  5630. pFoundCert = CertFindCertificateInStore(LocalhStore,
  5631. 0,
  5632. 0,
  5633. CERT_FIND_SIGNATURE_HASH,
  5634. (const void *) &HashBlob,
  5635. NULL
  5636. );
  5637. if(pFoundCert) {
  5638. IsPublisherTrusted = TRUE;
  5639. }
  5640. } except(pSetupExceptionFilter(GetExceptionCode())) {
  5641. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  5642. }
  5643. if(pFoundCert) {
  5644. CertFreeCertificateContext(pFoundCert);
  5645. }
  5646. if(!hStoreTrustedPublisher && LocalhStore) {
  5647. CertCloseStore(LocalhStore, 0);
  5648. }
  5649. return IsPublisherTrusted;
  5650. }
  5651. BOOL
  5652. IsAutoCertInstallAllowed(
  5653. VOID
  5654. )
  5655. /*++
  5656. Routine Description:
  5657. This routine indicates whether a certificate should automatically be
  5658. installed. The criteria it uses are:
  5659. 1. Must be in GUI-mode setup or mini-setup.
  5660. 2. Must be on an interactive windowstation
  5661. 3. Must be in LocalSystem security context.
  5662. (#2 & #3) are to prevent spoofing of registry values in #1.)
  5663. Arguments:
  5664. None.
  5665. Return Value:
  5666. If the certificate should be auto-installed, the return value is TRUE.
  5667. Otherwise, it is FALSE.
  5668. --*/
  5669. {
  5670. //
  5671. // Only auto-install certificates if we're in GUI-mode setup (or
  5672. // mini-setup)...
  5673. //
  5674. if(!GuiSetupInProgress) {
  5675. return FALSE;
  5676. }
  5677. //
  5678. // ...and if we're on an interactive windowstation...
  5679. //
  5680. if(!IsInteractiveWindowStation()) {
  5681. return FALSE;
  5682. }
  5683. //
  5684. // ...and if we're in LocalSystem security context.
  5685. //
  5686. if(!pSetupIsLocalSystem()) {
  5687. return FALSE;
  5688. }
  5689. return TRUE;
  5690. }
  5691. DWORD
  5692. pSetupInstallCertificate(
  5693. IN PCCERT_CONTEXT CertContext
  5694. )
  5695. /*++
  5696. Routine Description:
  5697. This routine will install the specified certificate into the
  5698. TrustedPublisher certificate store.
  5699. Arguments:
  5700. CertContext - supplies the context for the certificate to be installed.
  5701. Return Value:
  5702. If the certificate was successfully installed, the return value is
  5703. NO_ERROR.
  5704. Otherwise, it is a Win32 error indicating the cause of the failure.
  5705. --*/
  5706. {
  5707. DWORD Err;
  5708. HCERTSTORE hCertStore;
  5709. Err = GLE_FN_CALL(NULL,
  5710. hCertStore = CertOpenStore(
  5711. CERT_STORE_PROV_SYSTEM_W,
  5712. 0,
  5713. (HCRYPTPROV)NULL,
  5714. (CERT_SYSTEM_STORE_LOCAL_MACHINE
  5715. | CERT_STORE_OPEN_EXISTING_FLAG),
  5716. (const void *) L"TrustedPublisher")
  5717. );
  5718. if(Err != NO_ERROR) {
  5719. return Err;
  5720. }
  5721. try {
  5722. Err = GLE_FN_CALL(FALSE,
  5723. CertAddCertificateContextToStore(hCertStore,
  5724. CertContext,
  5725. CERT_STORE_ADD_USE_EXISTING,
  5726. NULL)
  5727. );
  5728. } except(pSetupExceptionFilter(GetExceptionCode())) {
  5729. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  5730. }
  5731. if(hCertStore) {
  5732. CertCloseStore(hCertStore, 0);
  5733. }
  5734. return Err;
  5735. }