Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5577 lines
195 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. //
  19. // Instantiate exception class GUID.
  20. //
  21. #include <initguid.h>
  22. DEFINE_GUID( GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER, 0xF5776D81L, 0xAE53, 0x4935, 0x8E, 0x84, 0xB0, 0xB2, 0x83, 0xD8, 0xBC, 0xEF );
  23. // Bit 0 indicates policy for filters (0 = critical, 1 = non-critical)
  24. #define DDB_DRIVER_POLICY_CRITICAL_BIT (1 << 0)
  25. // Bit 1 indicates policy for user-mode setup blocking (0 = block, 1 = no-block)
  26. #define DDB_DRIVER_POLICY_SETUP_NO_BLOCK_BIT (1 << 1)
  27. //
  28. // Global list of device setup classes subject to driver signing policy, along
  29. // validation platform overrides (where applicable).
  30. //
  31. DRVSIGN_POLICY_LIST GlobalDrvSignPolicyList;
  32. //
  33. // private function prototypes
  34. //
  35. BOOL
  36. ClassGuidInDrvSignPolicyList(
  37. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  38. IN CONST GUID *DeviceSetupClassGuid, OPTIONAL
  39. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform OPTIONAL
  40. );
  41. //
  42. // helper to determine log level to use
  43. //
  44. __inline
  45. DWORD
  46. GetCatLogLevel(DWORD Err)
  47. {
  48. switch(Err) {
  49. case ERROR_FILE_NOT_FOUND:
  50. case ERROR_PATH_NOT_FOUND:
  51. case E_NOTIMPL:
  52. return SETUP_LOG_VVERBOSE;
  53. default:
  54. return SETUP_LOG_INFO;
  55. }
  56. }
  57. DWORD
  58. ReadAsciiOrUnicodeTextFile(
  59. IN HANDLE FileHandle,
  60. OUT PTEXTFILE_READ_BUFFER Result,
  61. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  62. )
  63. /*++
  64. Routine Description:
  65. Read in a text file that may be in either ascii or unicode format.
  66. #ifdef UNICODE
  67. If the file is ascii, it is assumed to be ANSI format and is converted
  68. to Unicode.
  69. #else
  70. If the file is unicode, it will be converted to ascii using the ANSI
  71. codepage.
  72. NOTE: On Windows 95, the IsTextUnicode API is not implemented, thus
  73. the unicode file must have a byte order mark (BOM) in order for us to
  74. recognize it under Win95.
  75. #endif
  76. Arguments:
  77. FileHandle - Supplies the handle of the text file to be read.
  78. Result - supplies the address of a TEXTFILE_READ_BUFFER structure that
  79. receives information about the text file buffer read. The structure
  80. is defined as follows:
  81. typedef struct _TEXTFILE_READ_BUFFER {
  82. PCTSTR TextBuffer;
  83. DWORD TextBufferSize;
  84. HANDLE FileHandle;
  85. HANDLE MappingHandle;
  86. PVOID ViewAddress;
  87. } TEXTFILE_READ_BUFFER, *PTEXTFILE_READ_BUFFER;
  88. TextBuffer - pointer to the read-only character string containing
  89. the entire text of the file.
  90. (NOTE: If the file is a Unicode file with a Byte Order Mark
  91. prefix, this Unicode character is not included in the returned
  92. buffer.)
  93. TextBufferSize - size of the TextBuffer (in characters).
  94. FileHandle - If this is a valid handle (i.e., it's not equal to
  95. INVALID_HANDLE_VALUE), then the file was already the native
  96. character type, so the TextBuffer is simply the mapped-in image
  97. of the file. This field is reserved for use by the
  98. DestroyTextFileReadBuffer routine, and should not be accessed.
  99. MappingHandle - If FileHandle is valid, then this contains the
  100. mapping handle for the file image mapping.
  101. This field is reserved for use by the DestroyTextFileReadBuffer
  102. routine, and should not be accessed.
  103. ViewAddress - If FileHandle is valid, then this contains the
  104. starting memory address where the file image was mapped in.
  105. This field is reserved for use by the DestroyTextFileReadBuffer
  106. routine, and should not be accessed.
  107. LogContext - for logging of errors/tracing
  108. Return Value:
  109. Win32 error value indicating the outcome.
  110. Remarks:
  111. Upon return from this routine, the caller MUST NOT attempt to close FileHandle.
  112. This routine with either close the handle itself (after it's finished with it, or
  113. upon error), or it will store the handle away in the TEXTFILE_READ_BUFFER struct,
  114. to be later closed via DestroyTextFileReadBuffer().
  115. --*/
  116. {
  117. DWORD rc;
  118. DWORD FileSize;
  119. HANDLE MappingHandle;
  120. PVOID ViewAddress, TextStartAddress;
  121. BOOL IsNativeChar;
  122. #ifdef UNICODE
  123. UINT SysCodePage = CP_ACP;
  124. #endif
  125. //
  126. // Map the file for read access.
  127. //
  128. rc = pSetupMapFileForRead(
  129. FileHandle,
  130. &FileSize,
  131. &MappingHandle,
  132. &ViewAddress
  133. );
  134. if(rc != NO_ERROR) {
  135. //
  136. // We couldn't map the file--close the file handle now.
  137. //
  138. CloseHandle(FileHandle);
  139. } else {
  140. //
  141. // Determine whether the file is unicode. Guard with try/except in
  142. // case we get an inpage error.
  143. //
  144. try {
  145. //
  146. // Check to see if the file starts with a Unicode Byte Order Mark
  147. // (BOM) character (0xFEFF). If so, then we know that the file
  148. // is Unicode, and don't have to go through the slow process of
  149. // trying to figure it out.
  150. //
  151. TextStartAddress = ViewAddress;
  152. if((FileSize >= sizeof(WCHAR)) && (*(PWCHAR)TextStartAddress == 0xFEFF)) {
  153. //
  154. // The file has the BOM prefix. Adjust the pointer to the
  155. // start of the text, so that we don't include the marker
  156. // in the text buffer we return.
  157. //
  158. #ifdef UNICODE
  159. IsNativeChar = TRUE;
  160. #else
  161. IsNativeChar = FALSE;
  162. #endif // UNICODE
  163. ((PWCHAR)TextStartAddress)++;
  164. FileSize -= sizeof(WCHAR);
  165. } else {
  166. IsNativeChar = IsTextUnicode(TextStartAddress,FileSize,NULL);
  167. #ifndef UNICODE
  168. IsNativeChar = !IsNativeChar;
  169. #endif // !UNICODE
  170. }
  171. } except(EXCEPTION_EXECUTE_HANDLER) {
  172. rc = ERROR_READ_FAULT;
  173. }
  174. if(rc == NO_ERROR) {
  175. if(IsNativeChar) {
  176. //
  177. // No conversion is required--we'll just use the mapped-in
  178. // image in memory.
  179. //
  180. Result->TextBuffer = TextStartAddress;
  181. Result->TextBufferSize = FileSize / sizeof(TCHAR);
  182. Result->FileHandle = FileHandle;
  183. Result->MappingHandle = MappingHandle;
  184. Result->ViewAddress = ViewAddress;
  185. } else {
  186. DWORD NativeCharCount;
  187. PTCHAR Buffer;
  188. //
  189. // Need to convert the file to the native character type.
  190. // Allocate a buffer that is maximally sized.
  191. #ifdef UNICODE
  192. // The maximum size of the unicode text is
  193. // double the size of the oem text, and would occur
  194. // when each oem character is single-byte.
  195. #else
  196. // The maximum size of the ANSI text is the same number
  197. // of bytes that the Unicode text occupies.
  198. //
  199. #endif // UNICODE
  200. if(Buffer = MyMalloc(FileSize * sizeof(TCHAR))) {
  201. try {
  202. #ifdef UNICODE
  203. //
  204. // RAID#397463-1999/09/01-JamieHun Implement ANSI Inf Language=xxxx
  205. // come up with a better way of determining what code-page to interpret INF file under
  206. // currently we use the install-base
  207. //
  208. SysCodePage = CP_ACP;
  209. NativeCharCount = MultiByteToWideChar(SysCodePage,
  210. MB_PRECOMPOSED,
  211. TextStartAddress,
  212. FileSize,
  213. Buffer,
  214. FileSize
  215. );
  216. #else
  217. NativeCharCount = WideCharToMultiByte(CP_ACP,
  218. 0,
  219. TextStartAddress,
  220. FileSize / sizeof(WCHAR),
  221. Buffer,
  222. FileSize,
  223. NULL,
  224. NULL
  225. );
  226. #endif // UNICODE
  227. if(!NativeCharCount) {
  228. rc = GetLastError();
  229. }
  230. } except(EXCEPTION_EXECUTE_HANDLER) {
  231. rc = ERROR_READ_FAULT;
  232. }
  233. } else {
  234. rc = ERROR_NOT_ENOUGH_MEMORY;
  235. }
  236. if(rc == NO_ERROR) {
  237. //
  238. // If the converted buffer doesn't require the entire block
  239. // we allocated, attempt to reallocate the buffer to its
  240. // correct size. We don't care if this fails, since the
  241. // buffer we have is perfectly fine (just bigger than we
  242. // need).
  243. //
  244. if(!(Result->TextBuffer = MyRealloc(Buffer, NativeCharCount * sizeof(TCHAR)))) {
  245. Result->TextBuffer = Buffer;
  246. }
  247. Result->TextBufferSize = NativeCharCount;
  248. Result->FileHandle = INVALID_HANDLE_VALUE;
  249. } else {
  250. //
  251. // Free the buffer, if it was previously allocated.
  252. //
  253. if(Buffer) {
  254. MyFree(Buffer);
  255. }
  256. }
  257. }
  258. }
  259. //
  260. // If the file was already in native character form and we didn't
  261. // enounter any errors, then we don't want to close it, because we
  262. // use the mapped-in view directly.
  263. //
  264. if((rc != NO_ERROR) || !IsNativeChar) {
  265. pSetupUnmapAndCloseFile(FileHandle, MappingHandle, ViewAddress);
  266. }
  267. }
  268. return rc;
  269. }
  270. BOOL
  271. DestroyTextFileReadBuffer(
  272. IN PTEXTFILE_READ_BUFFER ReadBuffer
  273. )
  274. /*++
  275. Routine Description:
  276. Destroy a textfile read buffer created by ReadAsciiOrUnicodeTextFile.
  277. Arguments:
  278. ReadBuffer - supplies the address of a TEXTFILE_READ_BUFFER structure
  279. for the buffer to be destroyed.
  280. Return Value:
  281. BOOLean value indicating success or failure.
  282. --*/
  283. {
  284. //
  285. // If our ReadBuffer structure has a valid FileHandle, then we must
  286. // unmap and close the file, otherwise, we simply need to free the
  287. // allocated buffer.
  288. //
  289. if(ReadBuffer->FileHandle != INVALID_HANDLE_VALUE) {
  290. return pSetupUnmapAndCloseFile(ReadBuffer->FileHandle,
  291. ReadBuffer->MappingHandle,
  292. ReadBuffer->ViewAddress
  293. );
  294. } else {
  295. MyFree(ReadBuffer->TextBuffer);
  296. return TRUE;
  297. }
  298. }
  299. BOOL
  300. GetVersionInfoFromImage(
  301. IN PCTSTR FileName,
  302. OUT PDWORDLONG Version,
  303. OUT LANGID *Language
  304. )
  305. /*++
  306. Routine Description:
  307. Retrieve file version and language info from a file.
  308. The version is specified in the dwFileVersionMS and dwFileVersionLS fields
  309. of a VS_FIXEDFILEINFO, as filled in by the win32 version APIs. For the
  310. language we look at the translation table in the version resources and assume
  311. that the first langid/codepage pair specifies the language.
  312. If the file is not a coff image or does not have version resources,
  313. the function fails. The function does not fail if we are able to retrieve
  314. the version but not the language.
  315. Arguments:
  316. FileName - supplies the full path of the file whose version data is desired.
  317. Version - receives the version stamp of the file. If the file is not a coff image
  318. or does not contain the appropriate version resource data, the function fails.
  319. Language - receives the language id of the file. If the file is not a coff image
  320. or does not contain the appropriate version resource data, this will be 0
  321. and the function succeeds.
  322. Return Value:
  323. TRUE if we were able to retreive at least the version stamp.
  324. FALSE otherwise.
  325. --*/
  326. {
  327. DWORD d;
  328. PVOID VersionBlock;
  329. VS_FIXEDFILEINFO *FixedVersionInfo;
  330. UINT DataLength;
  331. BOOL b;
  332. PWORD Translation;
  333. DWORD Ignored;
  334. //
  335. // Assume failure
  336. //
  337. b = FALSE;
  338. //
  339. // Get the size of version info block.
  340. //
  341. if(d = GetFileVersionInfoSize((PTSTR)FileName,&Ignored)) {
  342. //
  343. // Allocate memory block of sufficient size to hold version info block
  344. //
  345. VersionBlock = MyMalloc(d*sizeof(TCHAR));
  346. if(VersionBlock) {
  347. //
  348. // Get the version block from the file.
  349. //
  350. if(GetFileVersionInfo((PTSTR)FileName,0,d*sizeof(TCHAR),VersionBlock)) {
  351. //
  352. // Get fixed version info.
  353. //
  354. if(VerQueryValue(VersionBlock,TEXT("\\"),&FixedVersionInfo,&DataLength)) {
  355. //
  356. // If we get here, we declare success, even if there is
  357. // no language.
  358. //
  359. b = TRUE;
  360. //
  361. // Return version to caller.
  362. //
  363. *Version = (((DWORDLONG)FixedVersionInfo->dwFileVersionMS) << 32)
  364. + FixedVersionInfo->dwFileVersionLS;
  365. //
  366. // Attempt to get language of file. We'll simply ask for the
  367. // translation table and use the first language id we find in there
  368. // as *the* language of the file.
  369. //
  370. // The translation table consists of LANGID/Codepage pairs.
  371. //
  372. if(VerQueryValue(VersionBlock,TEXT("\\VarFileInfo\\Translation"),&Translation,&DataLength)
  373. && (DataLength >= (2*sizeof(WORD)))) {
  374. *Language = Translation[0];
  375. } else {
  376. //
  377. // No language
  378. //
  379. *Language = 0;
  380. }
  381. }
  382. }
  383. MyFree(VersionBlock);
  384. }
  385. }
  386. return(b);
  387. }
  388. BOOL
  389. pSetupGetVersionInfoFromImage(
  390. IN PCTSTR FileName,
  391. OUT PULARGE_INTEGER Version,
  392. OUT LANGID *Language
  393. )
  394. /*++
  395. Routine Description:
  396. See GetVersionInfoFromImage for description
  397. Semi-public version that uses the more friendly ULARGE_INTEGER
  398. Arguments:
  399. FileName - supplies the full path of the file whose version data is desired.
  400. Version - receives the version stamp of the file. If the file is not a coff image
  401. or does not contain the appropriate version resource data, the function fails.
  402. Language - receives the language id of the file. If the file is not a coff image
  403. or does not contain the appropriate version resource data, this will be 0
  404. and the function succeeds.
  405. Return Value:
  406. TRUE if we were able to retreive at least the version stamp.
  407. FALSE otherwise.
  408. --*/
  409. {
  410. DWORDLONG privateVersion=0;
  411. BOOL result;
  412. result = GetVersionInfoFromImage(FileName,&privateVersion,Language);
  413. if (result && Version) {
  414. Version->QuadPart = privateVersion;
  415. }
  416. return result;
  417. }
  418. DWORD
  419. GetSetFileTimestamp(
  420. IN PCTSTR FileName,
  421. OUT FILETIME *CreateTime, OPTIONAL
  422. OUT FILETIME *AccessTime, OPTIONAL
  423. OUT FILETIME *WriteTime, OPTIONAL
  424. IN BOOL Set
  425. )
  426. /*++
  427. Routine Description:
  428. Get or set a file's timestamp values.
  429. Arguments:
  430. FileName - supplies full path of file to get or set timestamps
  431. CreateTime - if specified and the underlying filesystem supports it,
  432. receives the creation time of the file.
  433. AccessTime - if specified and the underlying filesystem supports it,
  434. receives the last access time of the file.
  435. WriteTime - if specified, receives the last write time of the file.
  436. Return Value:
  437. If successful, returns NO_ERROR, otherwise returns the Win32 error
  438. indicating the cause of failure.
  439. --*/
  440. {
  441. HANDLE h;
  442. DWORD d;
  443. BOOL b;
  444. h = CreateFile(
  445. FileName,
  446. Set ? GENERIC_WRITE : GENERIC_READ,
  447. FILE_SHARE_READ | FILE_SHARE_WRITE,
  448. NULL,
  449. OPEN_EXISTING,
  450. 0,
  451. NULL
  452. );
  453. if(h == INVALID_HANDLE_VALUE) {
  454. return(GetLastError());
  455. }
  456. b = Set
  457. ? SetFileTime(h,CreateTime,AccessTime,WriteTime)
  458. : GetFileTime(h,CreateTime,AccessTime,WriteTime);
  459. d = b ? NO_ERROR : GetLastError();
  460. CloseHandle(h);
  461. return(d);
  462. }
  463. DWORD
  464. RetreiveFileSecurity(
  465. IN PCTSTR FileName,
  466. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
  467. )
  468. /*++
  469. Routine Description:
  470. Retreive security information from a file and place it into a buffer.
  471. Arguments:
  472. FileName - supplies name of file whose security information is desired.
  473. SecurityDescriptor - If the function is successful, receives pointer
  474. to buffer containing security information for the file. The pointer
  475. may be NULL, indicating that there is no security information
  476. associated with the file or that the underlying filesystem does not
  477. support file security.
  478. Return Value:
  479. Win32 error code indicating outcome. If NO_ERROR check the value returned
  480. in SecurityDescriptor.
  481. The caller can free the buffer with MyFree() when done with it.
  482. --*/
  483. {
  484. BOOL b;
  485. DWORD d;
  486. DWORD BytesRequired;
  487. PSECURITY_DESCRIPTOR p;
  488. BytesRequired = 1024;
  489. while (TRUE) {
  490. //
  491. // Allocate a buffer of the required size.
  492. //
  493. p = MyMalloc(BytesRequired);
  494. if(!p) {
  495. return(ERROR_NOT_ENOUGH_MEMORY);
  496. }
  497. //
  498. // Get the security.
  499. //
  500. b = GetFileSecurity(
  501. FileName,
  502. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  503. p,
  504. BytesRequired,
  505. &BytesRequired
  506. );
  507. //
  508. // Return with sucess
  509. //
  510. if(b) {
  511. *SecurityDescriptor = p;
  512. return(NO_ERROR);
  513. }
  514. //
  515. // Return an error code, unless we just need a bigger buffer
  516. //
  517. MyFree(p);
  518. d = GetLastError();
  519. if(d != ERROR_INSUFFICIENT_BUFFER) {
  520. return (d);
  521. }
  522. //
  523. // There's a bug in GetFileSecurity that can cause it to ask for a
  524. // REALLY big buffer. In that case, we return an error.
  525. //
  526. if (BytesRequired > 0xF0000000) {
  527. return (ERROR_INVALID_DATA);
  528. }
  529. //
  530. // Otherwise, we'll try again with a bigger buffer
  531. //
  532. }
  533. }
  534. DWORD
  535. StampFileSecurity(
  536. IN PCTSTR FileName,
  537. IN PSECURITY_DESCRIPTOR SecurityInfo
  538. )
  539. /*++
  540. Routine Description:
  541. Set security information on a file.
  542. Arguments:
  543. FileName - supplies name of file whose security information is desired.
  544. SecurityDescriptor - supplies pointer to buffer containing security information
  545. for the file. This buffer should have been returned by a call to
  546. RetreiveFileSecurity. If the underlying filesystem does not support
  547. file security, the function fails.
  548. Return Value:
  549. Win32 error code indicating outcome.
  550. --*/
  551. {
  552. BOOL b;
  553. b = SetFileSecurity(
  554. FileName,
  555. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  556. SecurityInfo
  557. );
  558. return(b ? NO_ERROR : GetLastError());
  559. }
  560. DWORD
  561. TakeOwnershipOfFile(
  562. IN PCTSTR Filename
  563. )
  564. /*++
  565. Routine Description:
  566. Sets the owner of a given file to the default owner specified in
  567. the current process token.
  568. Arguments:
  569. FileName - supplies name of the file of which to take ownership.
  570. Return Value:
  571. Win32 error code indicating outcome.
  572. --*/
  573. {
  574. BOOL b;
  575. SECURITY_DESCRIPTOR SecurityDescriptor;
  576. DWORD Err;
  577. HANDLE Token;
  578. DWORD BytesRequired;
  579. PTOKEN_OWNER OwnerInfo;
  580. //
  581. // Open the process token.
  582. //
  583. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  584. Err = GetLastError();
  585. goto clean0;
  586. }
  587. //
  588. // Get the current process's default owner sid.
  589. //
  590. GetTokenInformation(Token,TokenOwner,NULL,0,&BytesRequired);
  591. Err = GetLastError();
  592. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  593. goto clean1;
  594. }
  595. OwnerInfo = MyMalloc(BytesRequired);
  596. if(!OwnerInfo) {
  597. Err = ERROR_NOT_ENOUGH_MEMORY;
  598. goto clean1;
  599. }
  600. b = GetTokenInformation(Token,TokenOwner,OwnerInfo,BytesRequired,&BytesRequired);
  601. if(!b) {
  602. Err = GetLastError();
  603. goto clean2;
  604. }
  605. //
  606. // Initialize the security descriptor.
  607. //
  608. if(!InitializeSecurityDescriptor(&SecurityDescriptor,SECURITY_DESCRIPTOR_REVISION)
  609. || !SetSecurityDescriptorOwner(&SecurityDescriptor,OwnerInfo->Owner,FALSE)) {
  610. Err = GetLastError();
  611. goto clean2;
  612. }
  613. //
  614. // Set file security.
  615. //
  616. Err = SetFileSecurity(Filename,OWNER_SECURITY_INFORMATION,&SecurityDescriptor)
  617. ? NO_ERROR
  618. : GetLastError();
  619. //
  620. // Not all filesystems support this operation.
  621. //
  622. if(Err == ERROR_NOT_SUPPORTED) {
  623. Err = NO_ERROR;
  624. }
  625. clean2:
  626. MyFree(OwnerInfo);
  627. clean1:
  628. CloseHandle(Token);
  629. clean0:
  630. return(Err);
  631. }
  632. DWORD
  633. SearchForInfFile(
  634. IN PCTSTR InfName,
  635. OUT LPWIN32_FIND_DATA FindData,
  636. IN DWORD SearchControl,
  637. OUT PTSTR FullInfPath,
  638. IN UINT FullInfPathSize,
  639. OUT PUINT RequiredSize OPTIONAL
  640. )
  641. /*++
  642. Routine Description:
  643. This routine searches for an INF file in the manner specified
  644. by the SearchControl parameter. If the file is found, its
  645. full path is returned.
  646. Arguments:
  647. InfName - Supplies name of INF to search for. This name is simply
  648. appended to the two search directory paths, so if the name
  649. contains directories, the file will searched for in the
  650. subdirectory under the search directory. I.e.:
  651. \foo\bar.inf
  652. will be searched for as %windir%\inf\foo\bar.inf and
  653. %windir%\system32\foo\bar.inf.
  654. FindData - Supplies the address of a Win32 Find Data structure that
  655. receives information about the file specified (if it is found).
  656. SearchControl - Specifies the order in which directories should
  657. be searched:
  658. INFINFO_DEFAULT_SEARCH : search %windir%\inf, then %windir%\system32
  659. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  660. INFINFO_INF_PATH_LIST_SEARCH : search for the INF in each of the
  661. directories listed in the DevicePath value entry under:
  662. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  663. FullInfPath - If the file is found, receives the full path of the INF.
  664. FullInfPathSize - Supplies the size of the FullInfPath buffer (in
  665. characters).
  666. RequiredSize - Optionally, receives the number of characters (including
  667. terminating NULL) required to store the FullInfPath.
  668. Return Value:
  669. Win32 error code indicating whether the function was successful. Common
  670. return values are:
  671. NO_ERROR if the file was found, and the INF file path returned
  672. successfully.
  673. ERROR_INSUFFICIENT_BUFFER if the supplied buffer was not large enough
  674. to hold the full INF path (RequiredSize will indicated how large
  675. the buffer needs to be)
  676. ERROR_FILE_NOT_FOUND if the file was not found.
  677. ERROR_INVALID_PARAMETER if the SearchControl parameter is invalid.
  678. --*/
  679. {
  680. PCTSTR PathList;
  681. TCHAR CurInfPath[MAX_PATH];
  682. PCTSTR PathPtr, InfPathLocation;
  683. DWORD PathLength;
  684. BOOL b, FreePathList;
  685. DWORD d;
  686. //
  687. // Retrieve the path list.
  688. //
  689. if(SearchControl == INFINFO_INF_PATH_LIST_SEARCH) {
  690. //
  691. // Just use our global list of INF search paths.
  692. //
  693. PathList = InfSearchPaths;
  694. FreePathList = FALSE;
  695. } else {
  696. if(!(PathList = AllocAndReturnDriverSearchList(SearchControl))) {
  697. return ERROR_NOT_ENOUGH_MEMORY;
  698. }
  699. FreePathList = TRUE;
  700. }
  701. //
  702. // Now look for the INF in each path in our MultiSz list.
  703. //
  704. InfPathLocation = NULL;
  705. d = NO_ERROR;
  706. for(PathPtr = PathList; *PathPtr; PathPtr += (lstrlen(PathPtr) + 1)) {
  707. //
  708. // Concatenate the INF file name with the current search path.
  709. //
  710. lstrcpy(CurInfPath, PathPtr);
  711. pSetupConcatenatePaths(CurInfPath,
  712. InfName,
  713. SIZECHARS(CurInfPath),
  714. &PathLength
  715. );
  716. if(b = FileExists(CurInfPath, FindData)) {
  717. if(!(FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  718. InfPathLocation = CurInfPath;
  719. break;
  720. }
  721. } else {
  722. //
  723. // See if we got a 'real' error
  724. //
  725. d = GetLastError();
  726. if((d == ERROR_NO_MORE_FILES) || (d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
  727. //
  728. // Not really an error--continue looking.
  729. //
  730. d = NO_ERROR;
  731. } else {
  732. //
  733. // This is a 'real' error, abort the search.
  734. //
  735. break;
  736. }
  737. }
  738. }
  739. //
  740. // Whatever the outcome, we're through with the PathList buffer.
  741. //
  742. if(FreePathList) {
  743. MyFree(PathList);
  744. }
  745. if(d != NO_ERROR) {
  746. return d;
  747. } else if(!InfPathLocation) {
  748. return ERROR_FILE_NOT_FOUND;
  749. }
  750. if(RequiredSize) {
  751. *RequiredSize = PathLength;
  752. }
  753. if(PathLength > FullInfPathSize) {
  754. return ERROR_INSUFFICIENT_BUFFER;
  755. }
  756. CopyMemory(FullInfPath,
  757. InfPathLocation,
  758. PathLength * sizeof(TCHAR)
  759. );
  760. return NO_ERROR;
  761. }
  762. DWORD
  763. MultiSzFromSearchControl(
  764. IN DWORD SearchControl,
  765. OUT PTCHAR PathList,
  766. IN DWORD PathListSize,
  767. OUT PDWORD RequiredSize OPTIONAL
  768. )
  769. /*++
  770. Routine Description:
  771. This routine takes a search control ordinal and builds a MultiSz list
  772. based on the search list it specifies.
  773. Arguments:
  774. SearchControl - Specifies the directory list to be built. May be one
  775. of the following values:
  776. INFINFO_DEFAULT_SEARCH : %windir%\inf, then %windir%\system32
  777. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  778. INFINFO_INF_PATH_LIST_SEARCH : Each of the directories listed in
  779. the DevicePath value entry under:
  780. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  781. PathList - Supplies the address of a character buffer that will receive
  782. the MultiSz list.
  783. PathListSize - Supplies the size, in characters, of the PathList buffer.
  784. RequiredSize - Optionally, receives the number of characters required
  785. to store the MultiSz PathList.
  786. (NOTE: The user-supplied buffer is used to retrieve the value entry
  787. from the registry. Therefore, if the value is a REG_EXPAND_SZ entry,
  788. the RequiredSize parameter may be set too small on an
  789. ERROR_INSUFFICIENT_BUFFER error. This will happen if the buffer was
  790. too small to retrieve the value entry, before expansion. In this case,
  791. calling the API again with a buffer sized according to the RequiredSize
  792. output may fail with an ERROR_INSUFFICIENT_BUFFER yet again, since
  793. expansion may require an even larger buffer.)
  794. Return Value:
  795. If successful, returns NO_ERROR.
  796. If failure, returns an ERROR_* status code.
  797. --*/
  798. {
  799. HKEY hk;
  800. PCTSTR Path1, Path2;
  801. PTSTR PathBuffer;
  802. DWORD RegDataType, PathLength, PathLength1, PathLength2;
  803. DWORD NumPaths, Err;
  804. BOOL UseDefaultDevicePath;
  805. if(PathList) {
  806. Err = NO_ERROR; // assume success.
  807. } else {
  808. return ERROR_INVALID_PARAMETER;
  809. }
  810. UseDefaultDevicePath = FALSE;
  811. if(SearchControl == INFINFO_INF_PATH_LIST_SEARCH) {
  812. //
  813. // Retrieve the INF search path list from the registry.
  814. //
  815. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  816. pszPathSetup,
  817. 0,
  818. KEY_READ,
  819. &hk) != ERROR_SUCCESS) {
  820. //
  821. // Fall back to default (just the Inf directory).
  822. //
  823. UseDefaultDevicePath = TRUE;
  824. } else {
  825. PathBuffer = NULL;
  826. try {
  827. //
  828. // Get the DevicePath value entry. Support REG_SZ or REG_EXPAND_SZ data.
  829. //
  830. PathLength = PathListSize * sizeof(TCHAR);
  831. Err = RegQueryValueEx(hk,
  832. pszDevicePath,
  833. NULL,
  834. &RegDataType,
  835. (LPBYTE)PathList,
  836. &PathLength
  837. );
  838. //
  839. // Need path length in characters from now on.
  840. //
  841. PathLength /= sizeof(TCHAR);
  842. if(Err == ERROR_SUCCESS) {
  843. //
  844. // Check if the callers buffer has room for extra NULL terminator.
  845. //
  846. if (PathLength >= PathListSize) {
  847. PathLength++;
  848. Err = ERROR_INSUFFICIENT_BUFFER;
  849. } else if((RegDataType == REG_SZ) || (RegDataType == REG_EXPAND_SZ)) {
  850. //
  851. // Convert this semicolon-delimited list to a REG_MULTI_SZ.
  852. //
  853. NumPaths = DelimStringToMultiSz(PathList,
  854. PathLength,
  855. TEXT(';')
  856. );
  857. #if 0
  858. if(RegDataType == REG_EXPAND_SZ) {
  859. #endif
  860. //
  861. // Allocate a temporary buffer large enough to hold the number
  862. // of paths in the MULTI_SZ list, each having maximum length
  863. // (plus an extra terminating NULL at the end).
  864. //
  865. if(!(PathBuffer = MyMalloc((NumPaths * MAX_PATH * sizeof(TCHAR))
  866. + sizeof(TCHAR)))) {
  867. Err = ERROR_NOT_ENOUGH_MEMORY;
  868. goto clean0;
  869. }
  870. PathLength = 0;
  871. for(Path1 = PathList;
  872. *Path1;
  873. Path1 += lstrlen(Path1) + 1) {
  874. if(RegDataType == REG_EXPAND_SZ) {
  875. PathLength += ExpandEnvironmentStrings(Path1,
  876. PathBuffer + PathLength,
  877. MAX_PATH
  878. );
  879. } else {
  880. lstrcpy(PathBuffer + PathLength, Path1);
  881. PathLength += lstrlen(Path1) + 1;
  882. }
  883. //
  884. // If the last character in this path is a backslash, then strip
  885. // it off.
  886. // PathLength at this point includes terminating NULL
  887. // char at PathBuffer[PathLength-1] is (or should be) NULL
  888. // char at PathBuffer[PathLength-2] may be '\'
  889. //
  890. if(*CharPrev(PathBuffer,PathBuffer + PathLength - 1) == TEXT('\\')) {
  891. *(PathBuffer + PathLength - 2) = TEXT('\0');
  892. PathLength--;
  893. }
  894. }
  895. //
  896. // Add additional terminating NULL at the end.
  897. //
  898. *(PathBuffer + PathLength) = TEXT('\0');
  899. if(++PathLength > PathListSize) {
  900. Err = ERROR_INSUFFICIENT_BUFFER;
  901. } else {
  902. CopyMemory(PathList,
  903. PathBuffer,
  904. PathLength * sizeof(TCHAR)
  905. );
  906. }
  907. MyFree(PathBuffer);
  908. PathBuffer = NULL;
  909. #if 0
  910. }
  911. #endif
  912. } else {
  913. //
  914. // Bad data type--just use the Inf directory.
  915. //
  916. UseDefaultDevicePath = TRUE;
  917. }
  918. } else if(Err == ERROR_MORE_DATA){
  919. Err = ERROR_INSUFFICIENT_BUFFER;
  920. } else {
  921. //
  922. // Fall back to default (just the Inf directory).
  923. //
  924. UseDefaultDevicePath = TRUE;
  925. }
  926. clean0: ; // nothing to do
  927. } except(EXCEPTION_EXECUTE_HANDLER) {
  928. //
  929. // Fall back to default (just the Inf directory).
  930. //
  931. UseDefaultDevicePath = TRUE;
  932. if(PathBuffer) {
  933. MyFree(PathBuffer);
  934. }
  935. }
  936. RegCloseKey(hk);
  937. }
  938. }
  939. if(UseDefaultDevicePath) {
  940. PathLength = lstrlen(InfDirectory) + 2;
  941. if(PathLength > PathListSize) {
  942. Err = ERROR_INSUFFICIENT_BUFFER;
  943. } else {
  944. Err = NO_ERROR;
  945. CopyMemory(PathList, InfDirectory, (PathLength - 1) * sizeof(TCHAR));
  946. //
  947. // Add extra NULL to terminate the list.
  948. //
  949. PathList[PathLength - 1] = TEXT('\0');
  950. }
  951. } else if((Err == NO_ERROR) && (SearchControl != INFINFO_INF_PATH_LIST_SEARCH)) {
  952. switch(SearchControl) {
  953. case INFINFO_DEFAULT_SEARCH :
  954. Path1 = InfDirectory;
  955. Path2 = SystemDirectory;
  956. break;
  957. case INFINFO_REVERSE_DEFAULT_SEARCH :
  958. Path1 = SystemDirectory;
  959. Path2 = InfDirectory;
  960. break;
  961. default :
  962. return ERROR_INVALID_PARAMETER;
  963. }
  964. PathLength1 = lstrlen(Path1) + 1;
  965. PathLength2 = lstrlen(Path2) + 1;
  966. PathLength = PathLength1 + PathLength2 + 1;
  967. if(PathLength > PathListSize) {
  968. Err = ERROR_INSUFFICIENT_BUFFER;
  969. } else {
  970. CopyMemory(PathList, Path1, PathLength1 * sizeof(TCHAR));
  971. CopyMemory(&(PathList[PathLength1]), Path2, PathLength2 * sizeof(TCHAR));
  972. //
  973. // Add additional terminating NULL at the end.
  974. //
  975. PathList[PathLength - 1] = 0;
  976. }
  977. }
  978. if(((Err == NO_ERROR) || (Err == ERROR_INSUFFICIENT_BUFFER)) && RequiredSize) {
  979. *RequiredSize = PathLength;
  980. }
  981. return Err;
  982. }
  983. PTSTR
  984. AllocAndReturnDriverSearchList(
  985. IN DWORD SearchControl
  986. )
  987. /*++
  988. Routine Description:
  989. This routine returns a buffer contains a multi-sz list of all directory paths in our
  990. driver search path list.
  991. The buffer returned must be freed with MyFree().
  992. Arguments:
  993. SearchControl - Specifies the directory list to be retrieved. May be one
  994. of the following values:
  995. INFINFO_DEFAULT_SEARCH : %windir%\inf, then %windir%\system32
  996. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  997. INFINFO_INF_PATH_LIST_SEARCH : Each of the directories listed in
  998. the DevicePath value entry under:
  999. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  1000. Returns:
  1001. Pointer to the allocated buffer containing the list, or NULL if out-of-memory.
  1002. --*/
  1003. {
  1004. PTSTR PathListBuffer, TrimBuffer;
  1005. DWORD BufferSize;
  1006. DWORD Err;
  1007. //
  1008. // Start out with a buffer of MAX_PATH length, which should cover most cases.
  1009. //
  1010. BufferSize = MAX_PATH;
  1011. if(PathListBuffer = MyMalloc((BufferSize+2) * sizeof(TCHAR))) {
  1012. //
  1013. // Loop on a call to MultiSzFromSearchControl until we succeed or hit some
  1014. // error other than buffer-too-small. There are two reasons for this. 1st, it
  1015. // is possible that someone could have added a new path to the registry list
  1016. // between calls, and 2nd, since that routine uses our buffer to retrieve the
  1017. // original (non-expanded) list, it can only report the size it needs to retrieve
  1018. // the unexpanded list. After it is given enough space to retrieve it, _then_ it
  1019. // can tell us how much space we really need.
  1020. //
  1021. // With all that said, we'll almost never see this call made more than once.
  1022. //
  1023. while(TRUE) {
  1024. if((Err = MultiSzFromSearchControl(SearchControl,
  1025. PathListBuffer,
  1026. BufferSize,
  1027. &BufferSize)) == NO_ERROR) {
  1028. //
  1029. // We've successfully retrieved the path list. If the list is larger
  1030. // than necessary (the normal case), then trim it down before returning.
  1031. // (If this fails it's no big deal--we'll just keep on using the original
  1032. // buffer.)
  1033. //
  1034. if(TrimBuffer = MyRealloc(PathListBuffer, (BufferSize+2) * sizeof(TCHAR))) {
  1035. return TrimBuffer;
  1036. } else {
  1037. return PathListBuffer;
  1038. }
  1039. } else {
  1040. //
  1041. // Free our current buffer before we find out what went wrong.
  1042. //
  1043. MyFree(PathListBuffer);
  1044. if((Err != ERROR_INSUFFICIENT_BUFFER) ||
  1045. !(PathListBuffer = MyMalloc((BufferSize+2) * sizeof(TCHAR)))) {
  1046. //
  1047. // We failed.
  1048. //
  1049. return NULL;
  1050. }
  1051. }
  1052. }
  1053. }
  1054. return NULL;
  1055. }
  1056. BOOL
  1057. DoMove(
  1058. IN PCTSTR CurrentName,
  1059. IN PCTSTR NewName
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. Wrapper for MoveFileEx on NT, DeleteFile followed by MoveFile on Win9x.
  1064. Arguments:
  1065. CurrentName - supplies the name of the file as it exists currently.
  1066. NewName - supplies the new name
  1067. Returns:
  1068. Boolean value indicating outcome. If failure, last error is set.
  1069. --*/
  1070. {
  1071. BOOL b;
  1072. //
  1073. // Try to be as efficient as possible on Windows NT.
  1074. //
  1075. if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1076. b = MoveFileEx(CurrentName,NewName,MOVEFILE_REPLACE_EXISTING);
  1077. } else {
  1078. DeleteFile(NewName);
  1079. b = MoveFile(CurrentName,NewName);
  1080. }
  1081. return(b);
  1082. }
  1083. BOOL
  1084. DelayedMove(
  1085. IN PCTSTR CurrentName,
  1086. IN PCTSTR NewName OPTIONAL
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. Queue a file for copy or delete on next reboot.
  1091. On Windows NT this means using MoveFileEx(). On Win95 this means
  1092. using the wininit.ini mechanism.
  1093. It is assumed that the target file already exists. On Win95, we need
  1094. to know the short filename since the wininit.ini mechanism only understands
  1095. SFNs and we have to do a bunch of special crud to make this all work.
  1096. Note: we do NOT attempt to deal with the long filename of the target
  1097. when renaming on Win95. In other words, if the target name is not 8.3,
  1098. it will wind up as 8.3 after processing of wininit.ini is done!
  1099. If a referenced file does not exist we have no choice but to use
  1100. the name passed in, which better be 8.3!
  1101. Arguments:
  1102. CurrentName - supplies the name of the file as it exists currently.
  1103. NewName - if specified supplies the new name. If not specified
  1104. then the file named by CurrentName is deleted on next reboot.
  1105. Returns:
  1106. Boolean value indicating outcome. If failure, last error is set.
  1107. --*/
  1108. {
  1109. BOOL b;
  1110. DWORD err;
  1111. if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1112. b = MoveFileEx(
  1113. CurrentName,
  1114. NewName,
  1115. MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT
  1116. );
  1117. } else {
  1118. #ifdef UNICODE
  1119. //
  1120. // The code below runs only on Win95 because of the version check
  1121. // just above. Thus we should never get here. The code below makes
  1122. // assumptions about maximum section lengths, etc, that are only
  1123. // valid on Win95. The SDK says that sections are limited to 32K,
  1124. // for example, and there are several hard-coded constants that take
  1125. // advantage of this.
  1126. //
  1127. b = FALSE;
  1128. err = ERROR_CALL_NOT_IMPLEMENTED;
  1129. #else
  1130. CHAR WininitFile[MAX_PATH];
  1131. CHAR NewSFN[MAX_PATH];
  1132. CHAR CurrentSFN[MAX_PATH];
  1133. CHAR *Buffer;
  1134. CHAR *p,*q;
  1135. DWORD Size;
  1136. DWORD d;
  1137. //
  1138. // Calculate full path of wininit.ini and get short filenames.
  1139. // We want to calculate the length of the data we're adding to
  1140. // wininit.ini up front, so we can leave room in the buffer
  1141. // (taking advantage of the 32K max section size on Win95).
  1142. // Trial and error dictates that when you get to that magic 32K
  1143. // number things can go really haywire unless you ensure you
  1144. // don't overflow a 16 bit signed 16-bit number, so we limit
  1145. // everything to 32767 to be safe.
  1146. //
  1147. // For renames, we add a line to delete the target file first.
  1148. // Not sure if this is really necessary, but it won't hurt anything.
  1149. //
  1150. if(Buffer = MyMalloc(32767)) {
  1151. lstrcpyn(WininitFile,WindowsDirectory,MAX_PATH);
  1152. pSetupConcatenatePaths(WininitFile,"WININIT.INI",MAX_PATH,NULL);
  1153. if(!GetShortPathName(CurrentName,CurrentSFN,MAX_PATH)) {
  1154. lstrcpyn(CurrentSFN,CurrentName,MAX_PATH);
  1155. }
  1156. if(NewName) {
  1157. if(!GetShortPathName(NewName,NewSFN,MAX_PATH)) {
  1158. lstrcpyn(NewSFN,NewName,MAX_PATH);
  1159. }
  1160. //
  1161. // NUL=NewSFN
  1162. // NewSFN=CurrentSFN
  1163. //
  1164. // plus terminating nul chars for each line.
  1165. //
  1166. Size = 3 + 1 + lstrlen(NewSFN) + 1
  1167. + lstrlen(NewSFN) + 1 + lstrlen(CurrentSFN) + 1;
  1168. } else {
  1169. //
  1170. // NUL=CurrentSFN
  1171. //
  1172. // plus terminating nul char for the line
  1173. //
  1174. Size = 3 + 1 + lstrlen(CurrentSFN) + 1;
  1175. lstrcpy(NewSFN,"NUL");
  1176. }
  1177. //
  1178. // Fetch the section and see if the line is already in there.
  1179. // If so, we're done.
  1180. //
  1181. d = GetPrivateProfileSection("Rename",Buffer,32767,WininitFile);
  1182. for(p=Buffer; *p; p+=lstrlen(p)+1) {
  1183. if(q = _mbschr(p,'=')) {
  1184. *q = 0;
  1185. if(!lstrcmpi(p,NewSFN) && !lstrcmpi(q+1,CurrentSFN)) {
  1186. break;
  1187. }
  1188. *q = '=';
  1189. }
  1190. }
  1191. if((*p == 0) && (Size <= 32766-d)) {
  1192. //
  1193. // Add our line(s), and make sure we have that extra nul
  1194. // to terminate things properly. We guaranteed that there'd be
  1195. // enough room by the checks above.
  1196. //
  1197. if(NewName) {
  1198. d += wsprintf(Buffer+d,"NUL=%s",NewSFN) + 1;
  1199. d += wsprintf(Buffer+d,"%s=%s",NewSFN,CurrentSFN) + 1;
  1200. } else {
  1201. d += wsprintf(Buffer+d,"NUL=%s",CurrentSFN) + 1;
  1202. }
  1203. Buffer[d] = 0;
  1204. //
  1205. // Write the section back out.
  1206. //
  1207. b = WritePrivateProfileSection("Rename",Buffer,WininitFile);
  1208. err = b ? NO_ERROR : GetLastError();
  1209. } else {
  1210. //
  1211. // The section is full or the line was already there.
  1212. // Just ignore it (in the section full case there's nothing
  1213. // the user can do anyway).
  1214. //
  1215. b = TRUE;
  1216. err = NO_ERROR;
  1217. }
  1218. MyFree(Buffer);
  1219. } else {
  1220. b = FALSE;
  1221. err = ERROR_NOT_ENOUGH_MEMORY;
  1222. }
  1223. #endif
  1224. SetLastError(err);
  1225. }
  1226. return(b);
  1227. }
  1228. DWORD
  1229. IsInstalledCatalogFromOem(
  1230. IN PCTSTR CatalogFile
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. Determin if a catalog is an OEM catalog.
  1235. Arguments:
  1236. CatalogFile - supplies name of catalog file.
  1237. Return Value:
  1238. BOOL. TRUE if the CatalogFile is an OEM Catalog file, and FALSE otherwise.
  1239. --*/
  1240. {
  1241. PTSTR p;
  1242. //
  1243. // First check that the first 3 characters are OEM
  1244. //
  1245. if (_tcsnicmp(CatalogFile, TEXT("oem"), 3)) {
  1246. return FALSE;
  1247. }
  1248. //
  1249. // Next verify that any characters after "oem" and before ".cat"
  1250. // are digits.
  1251. //
  1252. p = (PTSTR)CatalogFile;
  1253. p = CharNext(p);
  1254. p = CharNext(p);
  1255. p = CharNext(p);
  1256. while ((*p != TEXT('\0')) && (*p != TEXT('.'))) {
  1257. if ((*p < TEXT('0')) || (*p > TEXT('9'))) {
  1258. return FALSE;
  1259. }
  1260. p = CharNext(p);
  1261. }
  1262. //
  1263. // Finally, verify that the last 4 characters are ".cat"
  1264. //
  1265. if (lstrcmpi(p, TEXT(".cat"))) {
  1266. return FALSE;
  1267. }
  1268. //
  1269. // This is an OEM catalog file
  1270. //
  1271. return TRUE;
  1272. }
  1273. DWORD
  1274. pSetupInstallCatalog(
  1275. IN LPCTSTR CatalogFullPath,
  1276. IN LPCTSTR NewBaseName, OPTIONAL
  1277. OUT LPTSTR NewCatalogFullPath OPTIONAL
  1278. )
  1279. /*++
  1280. Routine Description:
  1281. This routine installs a catalog file. The file is copied by the system
  1282. into a special directory, and is optionally renamed.
  1283. Arguments:
  1284. CatalogFullPath - supplies the fully-qualified win32 path of the catalog
  1285. to be installed on the system.
  1286. NewBaseName - optionally specifies the new base name to use when the
  1287. catalog file is copied into the catalog store. If not specified,
  1288. the basename will be generated by CryptCATAdminAddCatalog.
  1289. NewCatalogFullPath - optionally receives the fully-qualified path of the
  1290. catalog file within the catalog store. This buffer should be at least
  1291. MAX_PATH bytes (ANSI version) or chars (Unicode version).
  1292. ** NOTE: If we're running in "minimal embedded" mode, then we don't **
  1293. ** actually call any of the Crypto APIs, and instead always simply **
  1294. ** report success. In this case, the caller had better not have **
  1295. ** specified an OUT buffer for NewCatalogFullPath, because we won't **
  1296. ** have a path to report. If we run into this case, we'll instead **
  1297. ** report failure. What this really says is that nobody other than **
  1298. ** setupapi should ever be passing a non-NULL value for this arg. **
  1299. Return Value:
  1300. If successful, the return value is NO_ERROR.
  1301. If failure, the return value is a Win32 error code indicating the cause of
  1302. the failure.
  1303. --*/
  1304. {
  1305. DWORD Err;
  1306. HCATADMIN hCatAdmin;
  1307. HCATINFO hCatInfo;
  1308. CATALOG_INFO CatalogInfo;
  1309. LPWSTR catalogFullPath;
  1310. LPWSTR newBaseName;
  1311. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1312. //
  1313. // If someone called us expecting the new catalog's full path to be
  1314. // returned, they're outta luck...
  1315. //
  1316. MYASSERT(!NewCatalogFullPath);
  1317. if(NewCatalogFullPath) {
  1318. //
  1319. // In minimal embedded mode, a non-NULL NewCatalogFullPath arg is
  1320. // an invalid parameter...
  1321. //
  1322. return ERROR_INVALID_PARAMETER;
  1323. } else {
  1324. //
  1325. // Simply report success.
  1326. //
  1327. return NO_ERROR;
  1328. }
  1329. }
  1330. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  1331. return TRUST_E_FAIL;
  1332. }
  1333. Err = NO_ERROR;
  1334. catalogFullPath = NULL;
  1335. newBaseName = NULL;
  1336. if(!CryptCATAdminAcquireContext(&hCatAdmin,&DriverVerifyGuid,0)) {
  1337. Err = GetLastError();
  1338. MYASSERT(Err != NO_ERROR);
  1339. if(Err == NO_ERROR) {
  1340. Err = ERROR_INVALID_DATA;
  1341. }
  1342. } else {
  1343. #ifdef UNICODE
  1344. //
  1345. // We do this even for the Unicode case because CryptCATAdminAddCatalog
  1346. // takes non-const strings and I have no idea whatsoever whether this
  1347. // was just sloppiness or a real requirement, and no desire to mess
  1348. // around trying to figure it out.
  1349. //
  1350. if(catalogFullPath = DuplicateString(CatalogFullPath)) {
  1351. if(NewBaseName) {
  1352. newBaseName = DuplicateString(NewBaseName);
  1353. if(!newBaseName) {
  1354. Err = ERROR_NOT_ENOUGH_MEMORY;
  1355. }
  1356. }
  1357. } else {
  1358. Err = ERROR_NOT_ENOUGH_MEMORY;
  1359. }
  1360. #else
  1361. if(catalogFullPath = pSetupAnsiToUnicode(CatalogFullPath)) {
  1362. if(NewBaseName) {
  1363. newBaseName = pSetupAnsiToUnicode(NewBaseName);
  1364. if(!newBaseName) {
  1365. Err = ERROR_NOT_ENOUGH_MEMORY;
  1366. }
  1367. }
  1368. } else {
  1369. Err = ERROR_NOT_ENOUGH_MEMORY;
  1370. }
  1371. #endif
  1372. if(Err == NO_ERROR) {
  1373. hCatInfo = CryptCATAdminAddCatalog(hCatAdmin,catalogFullPath,newBaseName,0);
  1374. if(!hCatInfo) {
  1375. Err = GetLastError();
  1376. MYASSERT(Err != NO_ERROR);
  1377. if(Err == NO_ERROR) {
  1378. Err = ERROR_INVALID_DATA;
  1379. }
  1380. //
  1381. // If the error we received is ERROR_ALREADY_EXISTS, then that
  1382. // indicates that the exact same catalog was already present
  1383. // (and installed under the same name). Treat this as a
  1384. // success (assuming we can get the full pathname of the
  1385. // existing catalog).
  1386. //
  1387. if(Err == ERROR_ALREADY_EXISTS) {
  1388. //
  1389. // We should never get this if we asked crypto to auto-
  1390. // generate a name for us...
  1391. //
  1392. MYASSERT(newBaseName);
  1393. if(NewCatalogFullPath) {
  1394. if(newBaseName) {
  1395. //
  1396. // Resolve the catalog base filename to a fully-
  1397. // qualified path.
  1398. //
  1399. CatalogInfo.cbStruct = sizeof(CATALOG_INFO);
  1400. if(CryptCATAdminResolveCatalogPath(hCatAdmin,
  1401. newBaseName,
  1402. &CatalogInfo,
  1403. 0)) {
  1404. //
  1405. // We successfully resolved the filename, so we
  1406. // can report success
  1407. //
  1408. Err = NO_ERROR;
  1409. }
  1410. }
  1411. } else {
  1412. //
  1413. // Caller isn't interested in finding out what pathname
  1414. // the catalog was installed under...
  1415. //
  1416. Err = NO_ERROR;
  1417. }
  1418. }
  1419. } else {
  1420. //
  1421. // If the caller wants to know the full path under which the
  1422. // catalog got installed, then find that out now.
  1423. //
  1424. if(NewCatalogFullPath) {
  1425. CatalogInfo.cbStruct = sizeof(CATALOG_INFO);
  1426. if(!CryptCATCatalogInfoFromContext(hCatInfo,&CatalogInfo,0)) {
  1427. Err = GetLastError();
  1428. MYASSERT(Err != NO_ERROR);
  1429. if(Err == NO_ERROR) {
  1430. Err = ERROR_INVALID_DATA;
  1431. }
  1432. }
  1433. }
  1434. CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0);
  1435. }
  1436. //
  1437. // If we succeeded in retrieving the installed catalog's full path
  1438. // (and the caller requested it), fill in the caller's buffer now.
  1439. //
  1440. if((Err == NO_ERROR) && NewCatalogFullPath) {
  1441. #ifdef UNICODE
  1442. lstrcpyn(NewCatalogFullPath, CatalogInfo.wszCatalogFile, MAX_PATH);
  1443. #else
  1444. WideCharToMultiByte(
  1445. CP_ACP,
  1446. 0,
  1447. CatalogInfo.wszCatalogFile,
  1448. -1,
  1449. NewCatalogFullPath,
  1450. MAX_PATH,
  1451. NULL,
  1452. NULL
  1453. );
  1454. #endif
  1455. }
  1456. }
  1457. CryptCATAdminReleaseContext(hCatAdmin, 0);
  1458. }
  1459. if(catalogFullPath) {
  1460. MyFree(catalogFullPath);
  1461. }
  1462. if(newBaseName) {
  1463. MyFree(newBaseName);
  1464. }
  1465. return Err;
  1466. }
  1467. DWORD
  1468. pSetupVerifyCatalogFile(
  1469. IN LPCTSTR CatalogFullPath
  1470. )
  1471. /*++
  1472. Routine Description:
  1473. This routine verifies a single catalog file. A catalog file is
  1474. "self-verifying" in that there is no additional file or data required
  1475. to verify it.
  1476. Arguments:
  1477. CatalogFullPath - supplies the fully-qualified Win32 path of
  1478. the catalog file to be verified.
  1479. Return Value:
  1480. If successful, the return value is ERROR_SUCCESS.
  1481. If failure, the return value is the error returned from WinVerifyTrust.
  1482. --*/
  1483. {
  1484. WINTRUST_DATA WintrustData;
  1485. WINTRUST_FILE_INFO WintrustFileInfo;
  1486. #ifndef UNICODE
  1487. WCHAR UnicodeBuffer[MAX_PATH];
  1488. #endif
  1489. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1490. return ERROR_SUCCESS;
  1491. }
  1492. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  1493. return TRUST_E_FAIL;
  1494. }
  1495. ZeroMemory(&WintrustData, sizeof(WINTRUST_DATA));
  1496. WintrustData.cbStruct = sizeof(WINTRUST_DATA);
  1497. WintrustData.dwUIChoice = WTD_UI_NONE;
  1498. WintrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
  1499. WintrustData.dwUnionChoice = WTD_CHOICE_FILE;
  1500. WintrustData.pFile = &WintrustFileInfo;
  1501. WintrustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
  1502. ZeroMemory(&WintrustFileInfo, sizeof(WINTRUST_FILE_INFO));
  1503. WintrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
  1504. #ifdef UNICODE
  1505. WintrustFileInfo.pcwszFilePath = CatalogFullPath;
  1506. #else
  1507. MultiByteToWideChar(CP_ACP, 0, CatalogFullPath, -1, UnicodeBuffer, MAX_PATH);
  1508. WintrustFileInfo.pcwszFilePath = UnicodeBuffer;
  1509. #endif
  1510. return (DWORD)WinVerifyTrust(NULL, &DriverVerifyGuid, &WintrustData);
  1511. }
  1512. DWORD
  1513. pSetupUninstallCatalog(
  1514. IN LPCTSTR CatalogFilename
  1515. )
  1516. /*++
  1517. Routine Description:
  1518. This routine uninstalls a catalog, so it can no longer be used to validate
  1519. digital signatures.
  1520. Arguments:
  1521. CatalogFilename - supplies the simple filename of the catalog to be
  1522. uninstalled.
  1523. Return Value:
  1524. If successful, the return value is NO_ERROR.
  1525. If failure, the return value is a Win32 error code indicating the cause of
  1526. the failure.
  1527. --*/
  1528. {
  1529. DWORD Err;
  1530. HCATADMIN hCatAdmin;
  1531. #ifdef UNICODE
  1532. //
  1533. // Presently, the crypto API CryptCATAdminRemoveCatalog defines its 2nd
  1534. // parameter as a PWSTR, even though it's an IN param that should be CONST.
  1535. // ReidK is going to fix this to be PCWSTR instead, so I'm safe in casting
  1536. // away the const-ness of my CatalogFilename arg here. (Once Reid's
  1537. // check-in happens, I can remove this cast.)
  1538. //
  1539. #define LocalCatName ((PWSTR)CatalogFilename)
  1540. #else
  1541. WCHAR LocalCatName[MAX_PATH];
  1542. //
  1543. // Crypto APIs are Unicode-only, so convert the catalog filename from
  1544. // ANSI to Unicode...
  1545. //
  1546. if(!MultiByteToWideChar(CP_ACP,
  1547. MB_PRECOMPOSED,
  1548. CatalogFilename,
  1549. -1,
  1550. LocalCatName,
  1551. SIZECHARS(LocalCatName))) {
  1552. return GetLastError();
  1553. }
  1554. #endif
  1555. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1556. return NO_ERROR;
  1557. }
  1558. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  1559. return TRUST_E_FAIL;
  1560. }
  1561. Err = NO_ERROR;
  1562. if(!CryptCATAdminAcquireContext(&hCatAdmin, &DriverVerifyGuid, 0)) {
  1563. Err = GetLastError();
  1564. MYASSERT(Err != NO_ERROR);
  1565. if(Err == NO_ERROR) {
  1566. Err = ERROR_INVALID_DATA;
  1567. }
  1568. } else {
  1569. if(!CryptCATAdminRemoveCatalog(hCatAdmin, LocalCatName, 0)) {
  1570. Err = GetLastError();
  1571. MYASSERT(Err != NO_ERROR);
  1572. if(Err == NO_ERROR) {
  1573. Err = ERROR_INVALID_DATA;
  1574. }
  1575. }
  1576. CryptCATAdminReleaseContext(hCatAdmin, 0);
  1577. }
  1578. return Err;
  1579. }
  1580. BOOL
  1581. pAnyDeviceUsingInf(
  1582. IN LPCTSTR InfFullPath,
  1583. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  1584. )
  1585. /*++
  1586. Routine Description:
  1587. This routine checks if any device, live or phantom, is using this INF file,
  1588. and logs if they are.
  1589. Arguments:
  1590. InfFullPath - supplies the full path of the INF.
  1591. LogContext - optionally, Supplies the log context to be used if
  1592. a device using this INF is encountered.
  1593. Return Value:
  1594. TRUE if any device is still using this INF, FALSE if no devices are using
  1595. this INF.
  1596. --*/
  1597. {
  1598. DWORD Err = NO_ERROR;
  1599. HDEVINFO DeviceInfoSet;
  1600. SP_DEVINFO_DATA DeviceInfoData;
  1601. DWORD MemberIndex = 0;
  1602. HKEY hkey;
  1603. TCHAR CurrentDeviceInfFile[MAX_PATH];
  1604. TCHAR DeviceId[MAX_DEVICE_ID_LEN];
  1605. DWORD cbSize, dwType;
  1606. PTSTR pInfFile;
  1607. //
  1608. // If we are passed a NULL InfFullPath or an enpty string then just
  1609. // return FALSE since nobody is using this.
  1610. //
  1611. if (!InfFullPath || (InfFullPath[0] == TEXT('\0'))) {
  1612. return FALSE;
  1613. }
  1614. pInfFile = (PTSTR)pSetupGetFileTitle(InfFullPath);
  1615. DeviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES);
  1616. if (DeviceInfoSet != INVALID_HANDLE_VALUE) {
  1617. DeviceInfoData.cbSize = sizeof(DeviceInfoData);
  1618. while (SetupDiEnumDeviceInfo(DeviceInfoSet,
  1619. MemberIndex++,
  1620. &DeviceInfoData)) {
  1621. //
  1622. // Open the 'driver' key for this device.
  1623. //
  1624. hkey = SetupDiOpenDevRegKey(DeviceInfoSet,
  1625. &DeviceInfoData,
  1626. DICS_FLAG_GLOBAL,
  1627. 0,
  1628. DIREG_DRV,
  1629. KEY_READ);
  1630. if (hkey != INVALID_HANDLE_VALUE) {
  1631. cbSize = sizeof(CurrentDeviceInfFile);
  1632. dwType = REG_SZ;
  1633. if ((RegQueryValueEx(hkey,
  1634. pszInfPath,
  1635. NULL,
  1636. &dwType,
  1637. (LPBYTE)CurrentDeviceInfFile,
  1638. &cbSize) == ERROR_SUCCESS) &&
  1639. (lstrcmpi(CurrentDeviceInfFile, pInfFile) == 0)) {
  1640. //
  1641. // This key is using this INF file so the INF can't be
  1642. // deleted.
  1643. //
  1644. Err = ERROR_SHARING_VIOLATION;
  1645. if (LogContext) {
  1646. if(CM_Get_Device_ID(DeviceInfoData.DevInst,
  1647. DeviceId,
  1648. SIZECHARS(DeviceId),
  1649. 0
  1650. ) != CR_SUCCESS ) {
  1651. DeviceId[0] = TEXT('\0');
  1652. }
  1653. WriteLogEntry(LogContext,
  1654. SETUP_LOG_WARNING,
  1655. MSG_LOG_INF_IN_USE,
  1656. NULL,
  1657. pInfFile,
  1658. DeviceId
  1659. );
  1660. }
  1661. }
  1662. RegCloseKey(hkey);
  1663. }
  1664. }
  1665. } else {
  1666. Err = ERROR_OUTOFMEMORY;
  1667. }
  1668. return (Err != ERROR_SUCCESS);
  1669. }
  1670. VOID
  1671. pSetupUninstallOEMInf(
  1672. IN LPCTSTR InfFullPath,
  1673. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1674. IN DWORD Flags,
  1675. OUT PDWORD InfDeleteErr OPTIONAL
  1676. )
  1677. /*++
  1678. Routine Description:
  1679. This routine uninstalls a 3rd-party INF, PNF, and CAT (if one exists).
  1680. By default this routine will first verify that there aren't any other
  1681. device's, live and phantom, that are pointing their InfPath to this
  1682. INF. This behavior can be overridden by the SUOI_FORCEDELETE flag.
  1683. Arguments:
  1684. InfFullPath - supplies the full path of the INF to be uninstalled.
  1685. LogContext - optionally, supplies the log context to be used if we
  1686. encounter an error when attempting to delete the catalog.
  1687. Flags - the following flags are supported:
  1688. SUOI_FORCEDELETE - delete the INF even if other driver keys are
  1689. have their InfPath pointing to it.
  1690. InfDeleteErr - optionally, supplies the address of a variable that receives
  1691. the error (if any) encountered when attempting to delete the INF.
  1692. Note that we delete the INF last (to avoid race conditions), so the
  1693. corresponding CAT and PNF may have already been deleted at this point.
  1694. Return Value:
  1695. None.
  1696. --*/
  1697. {
  1698. DWORD Err;
  1699. TCHAR FileNameBuffer[MAX_PATH+4]; // +4 in case filename is blahblah. not blahblah.inf
  1700. BOOL FreeLogContext = FALSE;
  1701. LPTSTR ExtPtr= NULL;
  1702. if(InfDeleteErr) {
  1703. *InfDeleteErr = NO_ERROR;
  1704. }
  1705. if(!LogContext) {
  1706. if(NO_ERROR == CreateLogContext(NULL, TRUE, &LogContext)) {
  1707. //
  1708. // Remember that we created this log context locally, so we can
  1709. // free it when we're done with this routine.
  1710. //
  1711. FreeLogContext = TRUE;
  1712. } else {
  1713. //
  1714. // Ensure LogContext is still NULL so we won't try to use it.
  1715. //
  1716. LogContext = NULL;
  1717. }
  1718. }
  1719. //
  1720. // Unless the caller passed in the SUOI_FORCEDELETE flag first check that
  1721. // no devices are using this INF file.
  1722. //
  1723. if (!(Flags & SUOI_FORCEDELETE) &&
  1724. pAnyDeviceUsingInf(InfFullPath, LogContext)) {
  1725. //
  1726. // Some device is still using this INF so we can't delete it. We don't
  1727. // need to log anything at this point since we log every device using
  1728. // this INF in pAnyDevicesUsingInf().
  1729. //
  1730. *InfDeleteErr = GetLastError();
  1731. goto clean0;
  1732. }
  1733. //
  1734. // Copy the caller-supplied INF name into a local buffer, so we can modify
  1735. // it when deleting the various files (INF, PNF, and CAT).
  1736. //
  1737. lstrcpyn(FileNameBuffer, InfFullPath, SIZECHARS(FileNameBuffer));
  1738. //
  1739. // Uninstall the catalog (if any) first, because as soon as we delete the
  1740. // INF, that slot is "open" for use by another INF, and we wouldn't want to
  1741. // inadvertently delete someone else's catalog due to a race condition.
  1742. //
  1743. ExtPtr = _tcsrchr(FileNameBuffer, TEXT('.'));
  1744. if(!ExtPtr) {
  1745. //
  1746. // not xxx.inf, so we know there is no catalog to delete
  1747. //
  1748. return;
  1749. }
  1750. lstrcpy(ExtPtr, pszCatSuffix);
  1751. Err = pSetupUninstallCatalog(pSetupGetFileTitle(FileNameBuffer));
  1752. if((Err != NO_ERROR) && LogContext) {
  1753. //
  1754. // It's kinda important that we were unable to delete the catalog, but
  1755. // not important enough to fail the routine. Log this fact to
  1756. // setupapi.log...
  1757. //
  1758. WriteLogEntry(LogContext,
  1759. DEL_ERR_LOG_LEVEL(Err) | SETUP_LOG_BUFFER,
  1760. MSG_LOG_CAT_UNINSTALL_FAILED,
  1761. NULL,
  1762. pSetupGetFileTitle(FileNameBuffer)
  1763. );
  1764. WriteLogError(LogContext,
  1765. DEL_ERR_LOG_LEVEL(Err),
  1766. Err
  1767. );
  1768. }
  1769. //
  1770. // Now delete the PNF (we don't care so much if this succeeds or fails)...
  1771. //
  1772. lstrcpy(_tcsrchr(FileNameBuffer, TEXT('.')), pszPnfSuffix);
  1773. DeleteFile(FileNameBuffer);
  1774. //
  1775. // and finally the INF itself...
  1776. //
  1777. lstrcpy(_tcsrchr(FileNameBuffer, TEXT('.')), pszInfSuffix);
  1778. if(!DeleteFile(FileNameBuffer) && InfDeleteErr) {
  1779. *InfDeleteErr = GetLastError();
  1780. }
  1781. clean0:
  1782. if(FreeLogContext) {
  1783. DeleteLogContext(LogContext);
  1784. }
  1785. }
  1786. DWORD
  1787. _VerifyFile(
  1788. IN PSETUP_LOG_CONTEXT LogContext,
  1789. IN OUT HCATADMIN *hCatAdmin, OPTIONAL
  1790. IN OUT HSDB *hSDBDrvMain, OPTIONAL
  1791. IN LPCTSTR Catalog, OPTIONAL
  1792. IN PVOID CatalogBaseAddress, OPTIONAL
  1793. IN DWORD CatalogImageSize,
  1794. IN LPCTSTR Key,
  1795. IN LPCTSTR FileFullPath,
  1796. OUT SetupapiVerifyProblem *Problem, OPTIONAL
  1797. OUT LPTSTR ProblemFile, OPTIONAL
  1798. IN BOOL CatalogAlreadyVerified,
  1799. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  1800. IN DWORD Flags, OPTIONAL
  1801. OUT LPTSTR CatalogFileUsed, OPTIONAL
  1802. OUT PDWORD NumCatalogsConsidered, OPTIONAL
  1803. OUT LPTSTR DigitalSigner, OPTIONAL
  1804. OUT LPTSTR SignerVersion OPTIONAL
  1805. )
  1806. /*++
  1807. Routine Description:
  1808. This routine verifies a single file against a particular catalog file, or
  1809. against any installed catalog file.
  1810. Arguments:
  1811. LogContext - supplies the context to be used when logging information about
  1812. the routine's activities.
  1813. hCatAdmin - optionally, supplies the address of an HCATADMIN handle. If
  1814. the handle pointed to is NULL, a handle will be acquired (if possible)
  1815. via CryptCATAdminAcquireContext and returned to the caller. If the
  1816. handle pointed to is non-NULL, then that handle will be used for any
  1817. validation done via this routine. If the pointer itself is NULL, then
  1818. an hCatAdmin will be acquired for the duration of this call, and
  1819. released before returning.
  1820. NOTE: it is the caller's responsibility to free the crypto context
  1821. handle returned by this routine by calling CryptCATAdminReleaseContext.
  1822. This handle may be opened in either success or failure cases, so the
  1823. caller must check for non-NULL returned handle in both cases.
  1824. hSDBDrvMain - optionally, supplies the address of a handle to the
  1825. drvmain.sdb database. If the handle pointed to is NULL, a handle will
  1826. be acquired (if possible) via SdbInitDatabase and returned to the
  1827. caller. If the handle pointed to is non-NULL, then that handle will be
  1828. used for bad driver database lookup (if requested) in this routine. If
  1829. the pointer itself is NULL, then an HSDB will be acquired for the
  1830. duration of this call (if needed), and released before returning.
  1831. NOTE: it is the caller's responsibility to free the handle returned by
  1832. this routine by calling SdbReleaseDatabase. This handle may be opened
  1833. in either success or failure cases, so the caller must check for
  1834. non-NULL returned handle in both cases.
  1835. Catalog - optionally, supplies the path of the catalog file to be used for
  1836. the verification. If this argument is not specified, then this routine
  1837. will attempt to find a catalog that can verify it from among all
  1838. catalogs installed in the system.
  1839. If this path is a simple filename (no path components), then we'll look
  1840. up that catalog file in the CatAdmin's list of installed catalogs, else
  1841. we'll use the name as-is.
  1842. CatalogBaseAddress - optionally, supplies the address of a buffer containing
  1843. the entire catalog image with which our enumerated catalog must match
  1844. before being considered a correct validation. This is used when copying
  1845. OEM INFs, for example, when there may be multiple installed catalogs
  1846. that can validate an INF, but we want to make sure that we pick _the_
  1847. catalog that matches the one we're contemplating installing before we'll
  1848. consider our INF/CAT files to be duplicates of the previously-existing
  1849. files.
  1850. This parameter (and its partner, CatalogImageSize) are only used when
  1851. Catalog doesn't specify a file path.
  1852. CatalogImageSize - if CatalogBaseAddress is specified, this parameter give
  1853. the size, in bytes, of that buffer.
  1854. Key - supplies a value that "indexes" the catalog, telling the verify APIs
  1855. which signature datum within the catalog it should use. Typically
  1856. the key is the (original) filename of a file.
  1857. FileFullPath - supplies the full path of the file to be verified.
  1858. Problem - if supplied, this parameter points to a variable that will be
  1859. filled in upon unsuccessful return with the cause of failure. If this
  1860. parameter is not supplied, then the ProblemFile parameter is ignored.
  1861. ProblemFile - if supplied, this parameter points to a character buffer of at
  1862. least MAX_PATH characters that receives the name of the file for which
  1863. a verification error occurred (the contents of this buffer are undefined
  1864. if verification succeeds.
  1865. If the Problem parameter is supplied, then the ProblemFile parameter
  1866. must also be specified.
  1867. CatalogAlreadyVerified - if TRUE, then verification won't be done on the
  1868. catalog--we'll just use that catalog to validate the file of interest.
  1869. If this is TRUE, then Catalog must be specified, must contain the path
  1870. to the catalog file (i.e., it can't be a simple filename).
  1871. AltPlatformInfo - optionally, supplies alternate platform information used
  1872. to fill in a DRIVER_VER_INFO structure (defined in sdk\inc\softpub.h)
  1873. that is passed to WinVerifyTrust.
  1874. ** NOTE: This structure _must_ have its cbSize field set to **
  1875. ** sizeof(SP_ALTPLATFORM_INFO_V2) -- validation on client-supplied **
  1876. ** buffer is the responsibility of the caller. **
  1877. Flags - supplies flags that alter that behavior of this routine. May be a
  1878. combination of the following values:
  1879. VERIFY_FILE_IGNORE_SELFSIGNED - if this bit is set, then this routine
  1880. will fail validation for self-signed
  1881. binaries.
  1882. VERIFY_FILE_USE_OEM_CATALOGS - if this bit is set, then all catalogs
  1883. installed in the system will be scanned
  1884. to verify the given file. Otherwise,
  1885. OEM (3rd party) catalogs will NOT be
  1886. scanned to verify the given file. This
  1887. is only applicable if a catalog is not
  1888. specified.
  1889. VERIFY_FILE_FAIL_COPIED_INFS - This flag is ignored. (It is only used
  1890. by the VerifySourceFile routine.)
  1891. VERIFY_FILE_DRIVERBLOCKED_ONLY - Only check if the file is in the bad
  1892. driver database, don't do any digital
  1893. sigature validation.
  1894. VERIFY_FILE_NO_DRIVERBLOCKED_CHECK - Don't check if the file is blocked
  1895. via the Bad Driver Database.
  1896. CatalogFileUsed - if supplied, this parameter points to a character buffer
  1897. at least MAX_PATH characters big that receives the name of the catalog
  1898. file used to verify the specified file. This is only filled in upon
  1899. successful return, or when the Problem is SetupapiVerifyFileProblem
  1900. (i.e., the catalog verified, but the file did not). If this buffer is
  1901. set to the empty string upon a SetupapiVerifyFileProblem failure, then
  1902. we didn't find any applicable catalogs to use for validation.
  1903. Also, this buffer will contain an empty string upon successful return
  1904. if the file was validated without using a catalog (i.e., the file
  1905. contains its own signature).
  1906. NumCatalogsConsidered - if supplied, this parameter receives a count of the
  1907. number of catalogs against which verification was attempted. Of course,
  1908. if Catalog is specified, this number will always be either zero or one.
  1909. DigitalSigner - if supplied, this parameter points to a character buffer of
  1910. at least MAX_PATH characters that receives the name of who digitally
  1911. signed the specified file. This value is only set if the Key is
  1912. correctly signed (i.e. the function returns NO_ERROR).
  1913. SignerVersion - if supplied, this parameter points to a character buffer of
  1914. at least MAX_PATH characters that receives the the signer version as
  1915. returned in the szwVerion field of the DRIVER_VER_INFO structure in
  1916. our call to WinVerifyTrust.
  1917. Return Value:
  1918. If successful, the return value is NO_ERROR.
  1919. If failure, the return value is a Win32 error code indicating the cause of
  1920. the failure.
  1921. --*/
  1922. {
  1923. LPBYTE Hash;
  1924. DWORD HashSize;
  1925. CATALOG_INFO CatInfo;
  1926. HANDLE hFile = INVALID_HANDLE_VALUE;
  1927. HCATINFO hCatInfo;
  1928. HCATINFO PrevCat;
  1929. DWORD Err;
  1930. WINTRUST_DATA WintrustData;
  1931. WINTRUST_CATALOG_INFO WintrustCatalogInfo;
  1932. WINTRUST_FILE_INFO WintrustFileInfo;
  1933. DRIVER_VER_INFO VersionInfo;
  1934. LPTSTR CatalogFullPath;
  1935. WCHAR UnicodeKey[MAX_PATH];
  1936. #ifndef UNICODE
  1937. CHAR AnsiBuffer[MAX_PATH];
  1938. #endif
  1939. WIN32_FILE_ATTRIBUTE_DATA FileAttribData;
  1940. BOOL FoundMatchingImage;
  1941. DWORD CurCatFileSize;
  1942. HANDLE CurCatFileHandle, CurCatMappingHandle;
  1943. PVOID CurCatBaseAddress;
  1944. BOOL LoggedWarning;
  1945. BOOL TrySelfSign;
  1946. DWORD AltPlatSlot;
  1947. TAGREF tagref = TAGREF_NULL;
  1948. HCATADMIN LocalhCatAdmin = NULL;
  1949. #ifdef UNICODE
  1950. HSDB LocalhSDBDrvMain = NULL;
  1951. #endif
  1952. //
  1953. // Initialize the CatalogFileUsed parameter to an empty string (i.e., no
  1954. // applicable catalog at this point).
  1955. //
  1956. if(CatalogFileUsed) {
  1957. *CatalogFileUsed = TEXT('\0');
  1958. }
  1959. //
  1960. // Initialize the output counter indicating the number of catalog files we
  1961. // processed during the attempted verification.
  1962. //
  1963. if(NumCatalogsConsidered) {
  1964. *NumCatalogsConsidered = 0;
  1965. }
  1966. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1967. //
  1968. // The existing behavior of this API in the ANSI case where the crypto
  1969. // APIs aren't available is to set the CatalogFileUsed OUT param to an
  1970. // empty string and report NO_ERROR. We'll do the same thing here (but
  1971. // we'll also assert, because no external callers should care, and if
  1972. // they do, an empty string probably isn't going to make them very
  1973. // happy).
  1974. //
  1975. MYASSERT(!CatalogFileUsed);
  1976. MYASSERT(!NumCatalogsConsidered);
  1977. //
  1978. // We'd better not be called in minimal embedded scenarios where we're
  1979. // asked to provide signer info...
  1980. //
  1981. MYASSERT(!DigitalSigner);
  1982. MYASSERT(!SignerVersion);
  1983. return NO_ERROR;
  1984. }
  1985. #ifdef ANSI_SETUPAPI
  1986. //
  1987. // If we are on a system that does not have crypt32.dll, then assume the
  1988. // file is valid.
  1989. //
  1990. if(Dyn_CryptCATAdminAcquireContext == Stub_CryptCATAdminAcquireContext) {
  1991. //
  1992. // Same asserts as above (minimal embedded) case apply here as well...
  1993. //
  1994. MYASSERT(!CatalogFileUsed);
  1995. MYASSERT(!NumCatalogsConsidered);
  1996. MYASSERT(!DigitalSigner);
  1997. MYASSERT(!SignerVersion);
  1998. return NO_ERROR;
  1999. }
  2000. #endif
  2001. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  2002. if(Problem) {
  2003. *Problem = SetupapiVerifyAutoFailProblem;
  2004. lstrcpy(ProblemFile, FileFullPath);
  2005. }
  2006. return TRUST_E_FAIL;
  2007. }
  2008. Hash = NULL;
  2009. LoggedWarning = FALSE;
  2010. TrySelfSign = FALSE;
  2011. AltPlatSlot = 0;
  2012. //
  2013. // Doesn't make sense to have both these flags set!
  2014. //
  2015. MYASSERT((Flags & (VERIFY_FILE_DRIVERBLOCKED_ONLY | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK))
  2016. != (VERIFY_FILE_DRIVERBLOCKED_ONLY | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK)
  2017. );
  2018. //
  2019. // If Problem is supplied, then ProblemFile must also be supplied.
  2020. //
  2021. MYASSERT(!Problem || ProblemFile);
  2022. //
  2023. // If the caller claims to have already verified the catalog file, make
  2024. // sure they passed us the full path to one.
  2025. //
  2026. MYASSERT(!CatalogAlreadyVerified || (Catalog && (Catalog != pSetupGetFileTitle(Catalog))));
  2027. //
  2028. // If a catalog image is specified, we'd better have been given a size.
  2029. //
  2030. MYASSERT((CatalogBaseAddress && CatalogImageSize) ||
  2031. !(CatalogBaseAddress || CatalogImageSize));
  2032. //
  2033. // If a catalog image was supplied for comparison, there shouldn't be a file
  2034. // path specified in the Catalog parameter.
  2035. //
  2036. MYASSERT(!CatalogBaseAddress || !(Catalog && (Catalog != pSetupGetFileTitle(Catalog))));
  2037. if(AltPlatformInfo) {
  2038. AltPlatSlot = AllocLogInfoSlotOrLevel(LogContext,SETUP_LOG_VERBOSE,FALSE);
  2039. WriteLogEntry(LogContext,
  2040. AltPlatSlot,
  2041. MSG_LOG_VERIFYFILE_ALTPLATFORM,
  2042. NULL, // text message
  2043. AltPlatformInfo->Platform,
  2044. AltPlatformInfo->MajorVersion,
  2045. AltPlatformInfo->MinorVersion,
  2046. AltPlatformInfo->FirstValidatedMajorVersion,
  2047. AltPlatformInfo->FirstValidatedMinorVersion
  2048. );
  2049. }
  2050. if(hCatAdmin) {
  2051. //
  2052. // Caller supplied us with a pointer to a crypto context handle. If
  2053. // it's NULL, we must acquire it now...
  2054. //
  2055. if(*hCatAdmin) {
  2056. LocalhCatAdmin = *hCatAdmin;
  2057. } else {
  2058. if(CryptCATAdminAcquireContext(&LocalhCatAdmin, &DriverVerifyGuid, 0)) {
  2059. //
  2060. // We successfully acquired a context handle. Store it in the
  2061. // caller-supplied buffer.
  2062. //
  2063. *hCatAdmin = LocalhCatAdmin;
  2064. } else {
  2065. LocalhCatAdmin = NULL;
  2066. }
  2067. }
  2068. } else {
  2069. //
  2070. // Acquire a temporary crypto context handle to be used only for the
  2071. // duration of this routine...
  2072. //
  2073. if(!CryptCATAdminAcquireContext(&LocalhCatAdmin, &DriverVerifyGuid, 0)) {
  2074. LocalhCatAdmin = NULL;
  2075. }
  2076. }
  2077. //
  2078. // Calculate the hash value for the inf.
  2079. //
  2080. if(LocalhCatAdmin) {
  2081. hFile = CreateFile(FileFullPath,
  2082. GENERIC_READ,
  2083. FILE_SHARE_READ,
  2084. NULL,
  2085. OPEN_EXISTING,
  2086. 0,
  2087. NULL
  2088. );
  2089. if(hFile == INVALID_HANDLE_VALUE) {
  2090. Err = GetLastError();
  2091. MYASSERT(Err != NO_ERROR);
  2092. if(Problem) {
  2093. *Problem = SetupapiVerifyFileProblem;
  2094. lstrcpy(ProblemFile, FileFullPath);
  2095. }
  2096. } else {
  2097. #ifdef UNICODE
  2098. //
  2099. // Only check if the driver is in the defective driver database if
  2100. // we are NOT in GUI setup, and the caller has NOT passed in the
  2101. // VERIFY_FILE_NO_DRIVERBLOCKED_CHECK flag.
  2102. //
  2103. if(!GuiSetupInProgress &&
  2104. !(Flags & VERIFY_FILE_NO_DRIVERBLOCKED_CHECK)) {
  2105. if(hSDBDrvMain) {
  2106. //
  2107. // Caller supplied us with a pointer to an SDB handle for
  2108. // the bad driver database. If it's NULL, we must acquire
  2109. // it now...
  2110. //
  2111. if(*hSDBDrvMain) {
  2112. LocalhSDBDrvMain = *hSDBDrvMain;
  2113. } else {
  2114. LocalhSDBDrvMain = SdbInitDatabase(SDB_DATABASE_MAIN_DRIVERS, NULL);
  2115. if(LocalhSDBDrvMain) {
  2116. *hSDBDrvMain = LocalhSDBDrvMain;
  2117. }
  2118. }
  2119. } else {
  2120. //
  2121. // Acquire a temporary handle to drvmain.sdb to be used
  2122. // only for our call to SdbGetDatabaseMatch.
  2123. //
  2124. LocalhSDBDrvMain = SdbInitDatabase(SDB_DATABASE_MAIN_DRIVERS, NULL);
  2125. }
  2126. //
  2127. // Check the bad driver database to see if this file is blocked.
  2128. //
  2129. if(LocalhSDBDrvMain) {
  2130. tagref = SdbGetDatabaseMatch(LocalhSDBDrvMain,
  2131. Key,
  2132. hFile,
  2133. NULL,
  2134. 0);
  2135. if(tagref != TAGREF_NULL) {
  2136. //
  2137. // Read the driver policy to see if this should be
  2138. // blocked by usermode or not.
  2139. // If the 1st bit is set then this should NOT be blocked
  2140. // by usermode.
  2141. //
  2142. ULONG type, size, policy;
  2143. size = sizeof(policy);
  2144. policy = 0;
  2145. type = REG_DWORD;
  2146. if (SdbQueryDriverInformation(LocalhSDBDrvMain,
  2147. tagref,
  2148. TEXT("Policy"),
  2149. &type,
  2150. &policy,
  2151. &size) != ERROR_SUCCESS) {
  2152. //
  2153. // If we can't read the policy then default to 0.
  2154. // This means we will block in usermode!
  2155. //
  2156. policy = 0;
  2157. }
  2158. if (!(policy & DDB_DRIVER_POLICY_SETUP_NO_BLOCK_BIT)) {
  2159. //
  2160. // This driver is in the database and needs to be blocked!
  2161. //
  2162. WriteLogEntry(LogContext,
  2163. SETUP_LOG_VERBOSE,
  2164. MSG_LOG_DRIVER_BLOCKED_ERROR,
  2165. NULL,
  2166. FileFullPath ? FileFullPath : TEXT("")
  2167. );
  2168. if(Problem) {
  2169. *Problem = SetupapiVerifyDriverBlocked;
  2170. lstrcpy(ProblemFile, FileFullPath);
  2171. }
  2172. LoggedWarning = TRUE;
  2173. Err = ERROR_DRIVER_BLOCKED;
  2174. goto clean0;
  2175. }
  2176. }
  2177. } else {
  2178. Err = GetLastError();
  2179. //
  2180. // Log an error that we couldn't access the bad driver
  2181. // database to check if this is a blocked driver. (We
  2182. // don't consider this a fatal error.)
  2183. //
  2184. WriteLogEntry(LogContext,
  2185. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  2186. MSG_LOG_CANT_ACCESS_BDD,
  2187. NULL,
  2188. FileFullPath
  2189. );
  2190. WriteLogError(LogContext, SETUP_LOG_ERROR, Err);
  2191. }
  2192. }
  2193. #endif
  2194. //
  2195. // If the caller only wanted to check if the file was in the bad
  2196. // driver database then we are done.
  2197. //
  2198. if (Flags & VERIFY_FILE_DRIVERBLOCKED_ONLY) {
  2199. Err = NO_ERROR;
  2200. goto clean0;
  2201. }
  2202. //
  2203. // Initialize some of the structures that will be used later on
  2204. // in calls to WinVerifyTrust. We don't know if we're verifying
  2205. // against a catalog or against a file yet.
  2206. //
  2207. ZeroMemory(&WintrustData, sizeof(WINTRUST_DATA));
  2208. WintrustData.cbStruct = sizeof(WINTRUST_DATA);
  2209. WintrustData.dwUIChoice = WTD_UI_NONE;
  2210. WintrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
  2211. WintrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE;
  2212. WintrustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
  2213. ZeroMemory(&VersionInfo, sizeof(DRIVER_VER_INFO));
  2214. VersionInfo.cbStruct = sizeof(DRIVER_VER_INFO);
  2215. if(AltPlatformInfo) {
  2216. MYASSERT(AltPlatformInfo->cbSize == sizeof(SP_ALTPLATFORM_INFO_V2));
  2217. //
  2218. // Caller wants the file validated for an alternate
  2219. // platform, so we must fill in a DRIVER_VER_INFO structure
  2220. // to be passed to the policy module.
  2221. //
  2222. VersionInfo.dwPlatform = AltPlatformInfo->Platform;
  2223. VersionInfo.dwVersion = AltPlatformInfo->MajorVersion;
  2224. VersionInfo.sOSVersionLow.dwMajor = AltPlatformInfo->FirstValidatedMajorVersion;
  2225. VersionInfo.sOSVersionLow.dwMinor = AltPlatformInfo->FirstValidatedMinorVersion;
  2226. VersionInfo.sOSVersionHigh.dwMajor = AltPlatformInfo->MajorVersion;
  2227. VersionInfo.sOSVersionHigh.dwMinor = AltPlatformInfo->MinorVersion;
  2228. } else {
  2229. //
  2230. // If an AltPlatformInfo was not passed in then set the
  2231. // WTD_USE_DEFAULT_OSVER_CHECK flag. This flag tells
  2232. // WinVerifyTrust to use its default osversion checking, even
  2233. // though a DRIVER_VER_INFO structure was passed in.
  2234. //
  2235. WintrustData.dwProvFlags |= WTD_USE_DEFAULT_OSVER_CHECK;
  2236. }
  2237. //
  2238. // Always specify a DRIVER_VER_INFO structure so we can get back
  2239. // who signed the file and the signer version information.
  2240. // If we don't have an AltPlatformInfo then set the
  2241. // WTD_USE_DEFAULT_OSVER_CHECK flag so that WinVerifyTrust will do
  2242. // its default checking, just as if a DRIVER_VER_INFO structure
  2243. // was not passed in.
  2244. //
  2245. WintrustData.pPolicyCallbackData = (PVOID)&VersionInfo;
  2246. //
  2247. // Start out with a hash buffer size that should be large enough for
  2248. // most requests.
  2249. //
  2250. HashSize = 100;
  2251. do {
  2252. Hash = MyMalloc(HashSize);
  2253. if(!Hash) {
  2254. Err = ERROR_NOT_ENOUGH_MEMORY;
  2255. break;
  2256. }
  2257. if(CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, Hash, 0)) {
  2258. Err = NO_ERROR;
  2259. } else {
  2260. Err = GetLastError();
  2261. MYASSERT(Err != NO_ERROR);
  2262. //
  2263. // If this API did mess up and not set last error, go ahead
  2264. // and set something.
  2265. //
  2266. if(Err == NO_ERROR) {
  2267. Err = ERROR_INVALID_DATA;
  2268. }
  2269. MyFree(Hash);
  2270. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  2271. //
  2272. // The API failed for some reason other than
  2273. // buffer-too-small. We will try to check if the file
  2274. // is self-signed.
  2275. //
  2276. Hash = NULL; // reset this so we won't try to free it
  2277. // later
  2278. hCatInfo = NULL;
  2279. TrySelfSign = TRUE;
  2280. WriteLogEntry(
  2281. (PSETUP_LOG_CONTEXT)LogContext,
  2282. SETUP_LOG_VERBOSE|SETUP_LOG_BUFFER,
  2283. MSG_LOG_HASH_ERROR,
  2284. NULL,
  2285. FileFullPath ? FileFullPath : TEXT(""),
  2286. Catalog ? Catalog : TEXT(""),
  2287. Key
  2288. );
  2289. WriteLogError(
  2290. (PSETUP_LOG_CONTEXT)LogContext,
  2291. SETUP_LOG_VERBOSE,
  2292. Err
  2293. );
  2294. LoggedWarning = TRUE;
  2295. break;
  2296. }
  2297. }
  2298. } while(Err != NO_ERROR);
  2299. if(!TrySelfSign) {
  2300. if(Err == NO_ERROR) {
  2301. //
  2302. // Now we have the file's hash. Initialize the structures that
  2303. // will be used later on in calls to WinVerifyTrust.
  2304. //
  2305. WintrustData.dwUnionChoice = WTD_CHOICE_CATALOG;
  2306. WintrustData.pCatalog = &WintrustCatalogInfo;
  2307. ZeroMemory(&WintrustCatalogInfo, sizeof(WINTRUST_CATALOG_INFO));
  2308. WintrustCatalogInfo.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
  2309. WintrustCatalogInfo.pbCalculatedFileHash = Hash;
  2310. WintrustCatalogInfo.cbCalculatedFileHash = HashSize;
  2311. //
  2312. // WinVerifyTrust is case-sensitive, so ensure that the key
  2313. // being used is all lower-case!
  2314. //
  2315. #ifdef UNICODE
  2316. //
  2317. // Copy the key to a writable Unicode character buffer so we
  2318. // can lower-case it.
  2319. //
  2320. lstrcpyn(UnicodeKey, Key, SIZECHARS(UnicodeKey));
  2321. CharLower(UnicodeKey);
  2322. #else
  2323. //
  2324. // Copy the key to a writable ANSI character buffer so we can
  2325. // lower-case it (prior to converting the string to Unicode).
  2326. //
  2327. lstrcpyn(AnsiBuffer, Key, SIZECHARS(AnsiBuffer));
  2328. CharLower(AnsiBuffer);
  2329. MultiByteToWideChar(CP_ACP, 0, AnsiBuffer, -1, UnicodeKey, SIZECHARS(UnicodeKey));
  2330. #endif
  2331. WintrustCatalogInfo.pcwszMemberTag = UnicodeKey;
  2332. if(Catalog && (Catalog != pSetupGetFileTitle(Catalog))) {
  2333. //
  2334. // We know in this case we're always going to examine
  2335. // exactly one catalog.
  2336. //
  2337. if(NumCatalogsConsidered) {
  2338. *NumCatalogsConsidered = 1;
  2339. }
  2340. //
  2341. // Fill in the catalog information since we know which
  2342. // catalog we're going to be using...
  2343. //
  2344. #ifdef UNICODE
  2345. WintrustCatalogInfo.pcwszCatalogFilePath = Catalog;
  2346. #else
  2347. //
  2348. // Use the handy-dandy unicode catalog filename buffer
  2349. // provided for us by the CatInfo.wszCatalogFile field.
  2350. //
  2351. MultiByteToWideChar(CP_ACP, 0, Catalog, -1, CatInfo.wszCatalogFile, SIZECHARS(CatInfo.wszCatalogFile));
  2352. WintrustCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
  2353. #endif
  2354. //
  2355. // The caller supplied the path to the catalog file to be
  2356. // used for verification--we're ready to go! First, verify
  2357. // the catalog (unless the caller already did it), and if
  2358. // that succeeds, then verify the file.
  2359. //
  2360. if(!CatalogAlreadyVerified) {
  2361. DWORD dwStateAction;
  2362. //
  2363. // Before validating the catalog, we'll flush the
  2364. // crypto cache. Otherwise, it can get fooled when
  2365. // validating against a catalog at a specific
  2366. // location, because that catalog can change
  2367. // "behind its back".
  2368. //
  2369. dwStateAction = WintrustData.dwStateAction;
  2370. WintrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE_FLUSH;
  2371. Err = (DWORD)WinVerifyTrust(NULL,
  2372. &DriverVerifyGuid,
  2373. &WintrustData
  2374. );
  2375. if(Err != NO_ERROR) {
  2376. //
  2377. // This shouldn't fail, but log a warning if it
  2378. // does...
  2379. //
  2380. WriteLogEntry(
  2381. (PSETUP_LOG_CONTEXT)LogContext,
  2382. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  2383. MSG_LOG_CRYPTO_CACHE_FLUSH_FAILURE,
  2384. NULL,
  2385. Catalog
  2386. );
  2387. WriteLogError(
  2388. (PSETUP_LOG_CONTEXT)LogContext,
  2389. SETUP_LOG_WARNING,
  2390. Err
  2391. );
  2392. //
  2393. // treat this error as non-fatal
  2394. //
  2395. }
  2396. //
  2397. // When flushing the cache, crypto isn't supposed
  2398. // to be allocating a pcSignerCertContext...
  2399. //
  2400. MYASSERT(!VersionInfo.pcSignerCertContext);
  2401. if(VersionInfo.pcSignerCertContext) {
  2402. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  2403. VersionInfo.pcSignerCertContext = NULL;
  2404. }
  2405. //
  2406. // Now back to our regularly-scheduled programming...
  2407. //
  2408. WintrustData.dwStateAction = dwStateAction;
  2409. Err = pSetupVerifyCatalogFile(Catalog);
  2410. }
  2411. if(Err != NO_ERROR) {
  2412. WriteLogEntry(
  2413. (PSETUP_LOG_CONTEXT)LogContext,
  2414. GetCatLogLevel(Err)|SETUP_LOG_BUFFER,
  2415. MSG_LOG_VERIFYCAT_ERROR,
  2416. NULL,
  2417. Catalog ? Catalog : TEXT("")
  2418. );
  2419. WriteLogError(
  2420. (PSETUP_LOG_CONTEXT)LogContext,
  2421. GetCatLogLevel(Err),
  2422. Err
  2423. );
  2424. LoggedWarning = TRUE;
  2425. if(Problem) {
  2426. *Problem = SetupapiVerifyCatalogProblem;
  2427. lstrcpy(ProblemFile, Catalog);
  2428. }
  2429. } else {
  2430. //
  2431. // Catalog was verified, now verify the file using that
  2432. // catalog.
  2433. //
  2434. if(CatalogFileUsed) {
  2435. lstrcpy(CatalogFileUsed, Catalog);
  2436. }
  2437. Err = (DWORD)WinVerifyTrust(NULL,
  2438. &DriverVerifyGuid,
  2439. &WintrustData
  2440. );
  2441. //
  2442. // Fill in the DigitalSigner and SignerVersion if
  2443. // they were passed in.
  2444. //
  2445. if (Err == NO_ERROR) {
  2446. if (DigitalSigner) {
  2447. #ifdef UNICODE
  2448. lstrcpy(DigitalSigner, VersionInfo.wszSignedBy);
  2449. #else
  2450. WideCharToMultiByte(
  2451. CP_ACP,
  2452. 0,
  2453. VersionInfo.wszSignedBy,
  2454. -1,
  2455. DigitalSigner,
  2456. MAX_PATH,
  2457. NULL,
  2458. NULL
  2459. );
  2460. #endif
  2461. }
  2462. if (SignerVersion) {
  2463. #ifdef UNICODE
  2464. lstrcpy(SignerVersion, VersionInfo.wszVersion);
  2465. #else
  2466. WideCharToMultiByte(
  2467. CP_ACP,
  2468. 0,
  2469. VersionInfo.wszVersion,
  2470. -1,
  2471. SignerVersion,
  2472. MAX_PATH,
  2473. NULL,
  2474. NULL
  2475. );
  2476. #endif
  2477. }
  2478. }
  2479. //
  2480. // The DRIVER_VER_INFO structure was filled in with
  2481. // a pointer that we must free!
  2482. //
  2483. if(VersionInfo.pcSignerCertContext) {
  2484. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  2485. VersionInfo.pcSignerCertContext = NULL;
  2486. }
  2487. if (Err != NO_ERROR) {
  2488. TrySelfSign = TRUE;
  2489. WriteLogEntry(
  2490. (PSETUP_LOG_CONTEXT)LogContext,
  2491. GetCatLogLevel(Err)|SETUP_LOG_BUFFER,
  2492. MSG_LOG_VERIFYFILE_ERROR,
  2493. NULL,
  2494. FileFullPath ? FileFullPath : TEXT(""),
  2495. Catalog ? Catalog : TEXT(""),
  2496. Key
  2497. );
  2498. WriteLogError(
  2499. (PSETUP_LOG_CONTEXT)LogContext,
  2500. GetCatLogLevel(Err),
  2501. Err
  2502. );
  2503. LoggedWarning = TRUE;
  2504. } else {
  2505. WriteLogEntry(
  2506. (PSETUP_LOG_CONTEXT)LogContext,
  2507. SETUP_LOG_VERBOSE,
  2508. MSG_LOG_VERIFYFILE_OK,
  2509. NULL,
  2510. FileFullPath ? FileFullPath : TEXT(""),
  2511. Catalog ? Catalog : TEXT(""),
  2512. Key
  2513. );
  2514. }
  2515. }
  2516. } else {
  2517. //
  2518. // Search through installed catalogs looking for those that
  2519. // contain data for a file with the hash we just calculated.
  2520. //
  2521. PrevCat = NULL;
  2522. hCatInfo = CryptCATAdminEnumCatalogFromHash(LocalhCatAdmin,
  2523. Hash,
  2524. HashSize,
  2525. 0,
  2526. &PrevCat
  2527. );
  2528. while(hCatInfo) {
  2529. CatInfo.cbStruct = sizeof(CATALOG_INFO);
  2530. if(CryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, 0)) {
  2531. #ifdef UNICODE
  2532. CatalogFullPath = CatInfo.wszCatalogFile;
  2533. #else
  2534. WideCharToMultiByte(
  2535. CP_ACP,
  2536. 0,
  2537. CatInfo.wszCatalogFile,
  2538. -1,
  2539. AnsiBuffer,
  2540. sizeof(AnsiBuffer),
  2541. NULL,
  2542. NULL
  2543. );
  2544. CatalogFullPath = AnsiBuffer;
  2545. #endif
  2546. //
  2547. // If we have a catalog name we're looking for,
  2548. // see if the current catalog matches. If the
  2549. // caller didn't specify a catalog, then just
  2550. // attempt to validate against each catalog we
  2551. // enumerate. Note that the catalog file info
  2552. // we get back gives us a fully qualified path.
  2553. //
  2554. if(Catalog) {
  2555. FoundMatchingImage = !lstrcmpi(
  2556. pSetupGetFileTitle(CatalogFullPath),
  2557. Catalog
  2558. );
  2559. } else {
  2560. if((Flags & VERIFY_FILE_USE_OEM_CATALOGS) ||
  2561. !IsInstalledCatalogFromOem(pSetupGetFileTitle(CatalogFullPath))) {
  2562. FoundMatchingImage = TRUE;
  2563. } else {
  2564. FoundMatchingImage = FALSE;
  2565. }
  2566. }
  2567. if(FoundMatchingImage) {
  2568. //
  2569. // Increment our counter of how many
  2570. // catalogs we've considered.
  2571. //
  2572. if(NumCatalogsConsidered) {
  2573. (*NumCatalogsConsidered)++;
  2574. }
  2575. //
  2576. // If the caller supplied a mapped-in image
  2577. // of the catalog we're looking for, then
  2578. // check to see if this catalog matches by
  2579. // doing a binary compare.
  2580. //
  2581. if(CatalogBaseAddress) {
  2582. FoundMatchingImage = GetFileAttributesEx(
  2583. CatalogFullPath,
  2584. GetFileExInfoStandard,
  2585. &FileAttribData
  2586. );
  2587. //
  2588. // Check to see if the catalog we're looking
  2589. // at is the same size as the one we're
  2590. // verifying.
  2591. //
  2592. if(FoundMatchingImage &&
  2593. (FileAttribData.nFileSizeLow != CatalogImageSize)) {
  2594. FoundMatchingImage = FALSE;
  2595. }
  2596. if(FoundMatchingImage) {
  2597. if(pSetupOpenAndMapFileForRead(CatalogFullPath,
  2598. &CurCatFileSize,
  2599. &CurCatFileHandle,
  2600. &CurCatMappingHandle,
  2601. &CurCatBaseAddress) == NO_ERROR) {
  2602. MYASSERT(CurCatFileSize == CatalogImageSize);
  2603. //
  2604. // Surround the following in try/except, in case we get an inpage error.
  2605. //
  2606. try {
  2607. //
  2608. // We've found a potential match.
  2609. //
  2610. FoundMatchingImage = !memcmp(
  2611. CatalogBaseAddress,
  2612. CurCatBaseAddress,
  2613. CatalogImageSize
  2614. );
  2615. } except(EXCEPTION_EXECUTE_HANDLER) {
  2616. FoundMatchingImage = FALSE;
  2617. }
  2618. pSetupUnmapAndCloseFile(CurCatFileHandle,
  2619. CurCatMappingHandle,
  2620. CurCatBaseAddress
  2621. );
  2622. } else {
  2623. FoundMatchingImage = FALSE;
  2624. }
  2625. }
  2626. } else {
  2627. //
  2628. // Since there was no catalog image supplied
  2629. // to match against, the catalog we're
  2630. // currently looking at is considered a
  2631. // valid match candidate.
  2632. //
  2633. FoundMatchingImage = TRUE;
  2634. }
  2635. if(FoundMatchingImage) {
  2636. //
  2637. // We found an applicable catalog, now
  2638. // validate the file against that catalog.
  2639. //
  2640. // NOTE: Because we're using cached
  2641. // catalog information (i.e., the
  2642. // WTD_STATEACTION_AUTO_CACHE flag), we
  2643. // don't need to explicitly validate the
  2644. // catalog itself first.
  2645. //
  2646. WintrustCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
  2647. Err = (DWORD)WinVerifyTrust(NULL,
  2648. &DriverVerifyGuid,
  2649. &WintrustData
  2650. );
  2651. //
  2652. // Fill in the DigitalSigner and SignerVersion if
  2653. // they were passed in.
  2654. //
  2655. if (Err == NO_ERROR) {
  2656. if (DigitalSigner) {
  2657. #ifdef UNICODE
  2658. lstrcpy(DigitalSigner, VersionInfo.wszSignedBy);
  2659. #else
  2660. WideCharToMultiByte(
  2661. CP_ACP,
  2662. 0,
  2663. VersionInfo.wszSignedBy,
  2664. -1,
  2665. DigitalSigner,
  2666. MAX_PATH,
  2667. NULL,
  2668. NULL
  2669. );
  2670. #endif
  2671. }
  2672. if (SignerVersion) {
  2673. #ifdef UNICODE
  2674. lstrcpy(SignerVersion, VersionInfo.wszVersion);
  2675. #else
  2676. WideCharToMultiByte(
  2677. CP_ACP,
  2678. 0,
  2679. VersionInfo.wszVersion,
  2680. -1,
  2681. SignerVersion,
  2682. MAX_PATH,
  2683. NULL,
  2684. NULL
  2685. );
  2686. #endif
  2687. }
  2688. }
  2689. //
  2690. // The DRIVER_VER_INFO structure was filled in with
  2691. // a pointer that we must free!
  2692. //
  2693. if(VersionInfo.pcSignerCertContext) {
  2694. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  2695. VersionInfo.pcSignerCertContext = NULL;
  2696. }
  2697. if (Err != NO_ERROR) {
  2698. WriteLogEntry(
  2699. (PSETUP_LOG_CONTEXT)LogContext,
  2700. GetCatLogLevel(Err)|SETUP_LOG_BUFFER,
  2701. MSG_LOG_VERIFYFILE_ERROR,
  2702. NULL,
  2703. FileFullPath ? FileFullPath : TEXT(""),
  2704. CatalogFullPath ? CatalogFullPath : TEXT(""),
  2705. Key
  2706. );
  2707. WriteLogError(
  2708. (PSETUP_LOG_CONTEXT)LogContext,
  2709. GetCatLogLevel(Err),
  2710. Err
  2711. );
  2712. LoggedWarning = TRUE;
  2713. } else {
  2714. WriteLogEntry(
  2715. (PSETUP_LOG_CONTEXT)LogContext,
  2716. SETUP_LOG_VERBOSE,
  2717. MSG_LOG_VERIFYFILE_OK,
  2718. NULL,
  2719. FileFullPath ? FileFullPath : TEXT(""),
  2720. CatalogFullPath ? CatalogFullPath : TEXT(""),
  2721. Key
  2722. );
  2723. }
  2724. if(Err == NO_ERROR) {
  2725. //
  2726. // We successfully verified the
  2727. // file--store the name of the
  2728. // catalog used, if the caller
  2729. // requested it.
  2730. //
  2731. if(CatalogFileUsed) {
  2732. lstrcpy(CatalogFileUsed, CatalogFullPath);
  2733. }
  2734. } else {
  2735. if(Catalog || CatalogBaseAddress) {
  2736. if(CatalogFileUsed) {
  2737. lstrcpy(CatalogFileUsed, CatalogFullPath);
  2738. }
  2739. if(Problem) {
  2740. *Problem = SetupapiVerifyFileProblem;
  2741. lstrcpy(ProblemFile, FileFullPath);
  2742. }
  2743. }
  2744. }
  2745. //
  2746. // If the result of the above validations is
  2747. // success, then we're done. If not, and we're
  2748. // looking for a relevant catalog file (i.e.,
  2749. // the INF didn't specify one), then we move
  2750. // on to the next catalog. Otherwise, we've
  2751. // failed.
  2752. //
  2753. if((Err == NO_ERROR) || Catalog || CatalogBaseAddress) {
  2754. CryptCATAdminReleaseCatalogContext(LocalhCatAdmin, hCatInfo, 0);
  2755. break;
  2756. }
  2757. }
  2758. }
  2759. }
  2760. PrevCat = hCatInfo;
  2761. hCatInfo = CryptCATAdminEnumCatalogFromHash(LocalhCatAdmin, Hash, HashSize, 0, &PrevCat);
  2762. }
  2763. if(!hCatInfo) {
  2764. //
  2765. // We exhausted all the applicable catalogs without
  2766. // finding the one we needed.
  2767. //
  2768. Err = GetLastError();
  2769. MYASSERT(Err != NO_ERROR);
  2770. //
  2771. // Make sure we have a valid error code.
  2772. //
  2773. if(Err == NO_ERROR) {
  2774. Err = ERROR_INVALID_DATA;
  2775. }
  2776. TrySelfSign = TRUE;
  2777. //
  2778. // report failure if we haven't already done so
  2779. //
  2780. if(!LoggedWarning) {
  2781. WriteLogEntry((PSETUP_LOG_CONTEXT)LogContext,
  2782. GetCatLogLevel(Err)|SETUP_LOG_BUFFER,
  2783. MSG_LOG_VERIFYFILE_ERROR,
  2784. NULL,
  2785. FileFullPath ? FileFullPath : TEXT(""),
  2786. Catalog ? Catalog : TEXT(""),
  2787. Key
  2788. );
  2789. WriteLogError((PSETUP_LOG_CONTEXT)LogContext,GetCatLogLevel(Err),Err);
  2790. }
  2791. }
  2792. }
  2793. } else {
  2794. if(Problem) {
  2795. *Problem = SetupapiVerifyFileProblem;
  2796. lstrcpy(ProblemFile, FileFullPath);
  2797. }
  2798. }
  2799. }
  2800. if (TrySelfSign) {
  2801. if(!(Flags & VERIFY_FILE_IGNORE_SELFSIGNED)) {
  2802. //
  2803. // The file failed to validate using any catalogs
  2804. // See if the file validates without a
  2805. // catalog (i.e., the file contains its own
  2806. // signature).
  2807. //
  2808. WintrustData.dwUnionChoice = WTD_CHOICE_FILE;
  2809. WintrustData.pFile = &WintrustFileInfo;
  2810. ZeroMemory(&WintrustFileInfo, sizeof(WINTRUST_FILE_INFO));
  2811. WintrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
  2812. #ifdef UNICODE
  2813. WintrustFileInfo.pcwszFilePath = FileFullPath;
  2814. #else
  2815. //
  2816. // Use the UnicodeKey buffer to hold the unicode
  2817. // version of the full pathname of the file to be
  2818. // verified.
  2819. //
  2820. MultiByteToWideChar(CP_ACP, 0, FileFullPath, -1, UnicodeKey, SIZECHARS(UnicodeKey));
  2821. WintrustFileInfo.pcwszFilePath = UnicodeKey;
  2822. #endif
  2823. Err = (DWORD)WinVerifyTrust(NULL,
  2824. &DriverVerifyGuid,
  2825. &WintrustData
  2826. );
  2827. //
  2828. // Fill in the DigitalSigner and SignerVersion if
  2829. // they were passed in.
  2830. //
  2831. if (Err == NO_ERROR) {
  2832. if (DigitalSigner) {
  2833. #ifdef UNICODE
  2834. lstrcpy(DigitalSigner, VersionInfo.wszSignedBy);
  2835. #else
  2836. WideCharToMultiByte(
  2837. CP_ACP,
  2838. 0,
  2839. VersionInfo.wszSignedBy,
  2840. -1,
  2841. DigitalSigner,
  2842. MAX_PATH,
  2843. NULL,
  2844. NULL
  2845. );
  2846. #endif
  2847. }
  2848. if (SignerVersion) {
  2849. #ifdef UNICODE
  2850. lstrcpy(SignerVersion, VersionInfo.wszVersion);
  2851. #else
  2852. WideCharToMultiByte(
  2853. CP_ACP,
  2854. 0,
  2855. VersionInfo.wszVersion,
  2856. -1,
  2857. SignerVersion,
  2858. MAX_PATH,
  2859. NULL,
  2860. NULL
  2861. );
  2862. #endif
  2863. }
  2864. }
  2865. //
  2866. // The DRIVER_VER_INFO structure was filled in with
  2867. // a pointer that we must free!
  2868. //
  2869. if(VersionInfo.pcSignerCertContext) {
  2870. CertFreeCertificateContext(VersionInfo.pcSignerCertContext);
  2871. VersionInfo.pcSignerCertContext = NULL;
  2872. }
  2873. if (Err != NO_ERROR) {
  2874. WriteLogEntry(
  2875. (PSETUP_LOG_CONTEXT)LogContext,
  2876. SETUP_LOG_VERBOSE|SETUP_LOG_BUFFER,
  2877. MSG_LOG_SELFSIGN_ERROR,
  2878. NULL,
  2879. FileFullPath ? FileFullPath : TEXT(""),
  2880. Key
  2881. );
  2882. WriteLogError(
  2883. (PSETUP_LOG_CONTEXT)LogContext,
  2884. SETUP_LOG_VERBOSE,
  2885. Err
  2886. );
  2887. LoggedWarning = TRUE;
  2888. } else {
  2889. WriteLogEntry(
  2890. (PSETUP_LOG_CONTEXT)LogContext,
  2891. SETUP_LOG_VERBOSE,
  2892. MSG_LOG_SELFSIGN_OK,
  2893. NULL,
  2894. FileFullPath ? FileFullPath : TEXT(""),
  2895. Key
  2896. );
  2897. }
  2898. }
  2899. if(Err == NO_ERROR) {
  2900. //
  2901. // The file validated without a catalog. Store an empty
  2902. // string in the CatalogFileUsed buffer (if supplied).
  2903. //
  2904. if(CatalogFileUsed) {
  2905. *CatalogFileUsed = TEXT('\0');
  2906. }
  2907. } else {
  2908. //
  2909. // report error prior to Self-Sign check
  2910. //
  2911. if(Problem) {
  2912. *Problem = SetupapiVerifyFileProblem;
  2913. lstrcpy(ProblemFile, FileFullPath);
  2914. }
  2915. }
  2916. }
  2917. if (Hash) {
  2918. MyFree(Hash);
  2919. }
  2920. }
  2921. } else {
  2922. Err = GetLastError();
  2923. MYASSERT(Err != NO_ERROR);
  2924. //
  2925. // Make sure we have a valid error code.
  2926. //
  2927. if(Err == NO_ERROR) {
  2928. Err = ERROR_INVALID_DATA;
  2929. }
  2930. if(Problem) {
  2931. //
  2932. // We failed too early to blame the file as the problem, but it's
  2933. // the only filename we currently have to return as the problematic
  2934. // file.
  2935. //
  2936. *Problem = SetupapiVerifyFileProblem;
  2937. lstrcpy(ProblemFile, FileFullPath);
  2938. }
  2939. }
  2940. if (Err != NO_ERROR) {
  2941. //
  2942. // report failure if we haven't already done so
  2943. //
  2944. if(!LoggedWarning) {
  2945. WriteLogEntry(LogContext,
  2946. GetCatLogLevel(Err)|SETUP_LOG_BUFFER,
  2947. MSG_LOG_VERIFYFILE_ERROR,
  2948. NULL,
  2949. FileFullPath ? FileFullPath : TEXT(""),
  2950. Catalog ? Catalog : TEXT(""),
  2951. Key
  2952. );
  2953. WriteLogError((PSETUP_LOG_CONTEXT)LogContext,GetCatLogLevel(Err),Err);
  2954. }
  2955. }
  2956. clean0:
  2957. #ifdef UNICODE
  2958. if(!hSDBDrvMain && LocalhSDBDrvMain) {
  2959. //
  2960. // Don't need to return our HSDB to the caller, so free
  2961. // it now.
  2962. //
  2963. SdbReleaseDatabase(LocalhSDBDrvMain);
  2964. }
  2965. #endif
  2966. if(hFile != INVALID_HANDLE_VALUE) {
  2967. CloseHandle(hFile);
  2968. }
  2969. if(AltPlatSlot) {
  2970. ReleaseLogInfoSlot(LogContext,AltPlatSlot);
  2971. }
  2972. if(!hCatAdmin && LocalhCatAdmin) {
  2973. CryptCATAdminReleaseContext(LocalhCatAdmin, 0);
  2974. }
  2975. SetLastError(Err);
  2976. return Err;
  2977. }
  2978. DWORD
  2979. pSetupVerifyFile(
  2980. IN PSETUP_LOG_CONTEXT LogContext,
  2981. IN LPCTSTR Catalog, OPTIONAL
  2982. IN PVOID CatalogBaseAddress, OPTIONAL
  2983. IN DWORD CatalogImageSize,
  2984. IN LPCTSTR Key,
  2985. IN LPCTSTR FileFullPath,
  2986. OUT SetupapiVerifyProblem *Problem, OPTIONAL
  2987. OUT LPTSTR ProblemFile, OPTIONAL
  2988. IN BOOL CatalogAlreadyVerified,
  2989. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  2990. OUT LPTSTR CatalogFileUsed, OPTIONAL
  2991. OUT PDWORD NumCatalogsConsidered OPTIONAL
  2992. )
  2993. /*++
  2994. Routine Description:
  2995. See _VerifyFile
  2996. Since this private API is exported for use by other system components
  2997. (e.g., syssetup), we make a check to ensure that the AltPlatformInfo, if
  2998. specified, is of the correct version.
  2999. --*/
  3000. {
  3001. if(AltPlatformInfo) {
  3002. if(AltPlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V2)) {
  3003. return ERROR_INVALID_PARAMETER;
  3004. }
  3005. if(!(AltPlatformInfo->Flags & SP_ALTPLATFORM_FLAGS_VERSION_RANGE)) {
  3006. //
  3007. // this flag must be set to indicate the version range fields are valid
  3008. //
  3009. return ERROR_INVALID_PARAMETER;
  3010. }
  3011. }
  3012. return _VerifyFile(LogContext,
  3013. NULL,
  3014. NULL,
  3015. Catalog,
  3016. CatalogBaseAddress,
  3017. CatalogImageSize,
  3018. Key,
  3019. FileFullPath,
  3020. Problem,
  3021. ProblemFile,
  3022. CatalogAlreadyVerified,
  3023. AltPlatformInfo,
  3024. VERIFY_FILE_USE_OEM_CATALOGS,
  3025. CatalogFileUsed,
  3026. NumCatalogsConsidered,
  3027. NULL,
  3028. NULL
  3029. );
  3030. }
  3031. BOOL
  3032. IsInfForDeviceInstall(
  3033. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  3034. IN CONST GUID *DeviceSetupClassGuid, OPTIONAL
  3035. IN PLOADED_INF LoadedInf, OPTIONAL
  3036. OUT PTSTR *DeviceDesc, OPTIONAL
  3037. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform, OPTIONAL
  3038. OUT PDWORD PolicyToUse, OPTIONAL
  3039. OUT PBOOL UseOriginalInfName OPTIONAL
  3040. )
  3041. /*++
  3042. Routine Description:
  3043. This routine determines whether the specified INF is a device INF. If so,
  3044. it returns a generic string to use in identifying the device installation
  3045. when there is no device description available (e.g., installing a printer).
  3046. It can also return the appropriate platform parameters to be used in
  3047. digital signature verification for this INF, as well as the codesigning
  3048. policy to employ should a digital signature validation failure occur.
  3049. Finally, this routine can indicate whether the INF should be installed
  3050. under its original name (i.e., because it's an exception package INF).
  3051. Arguments:
  3052. LogContext - Optionally, supplies the log context for any log entries that
  3053. might be generated by this routine.
  3054. DeviceSetupClassGuid - Optionally, supplies the address of a GUID that
  3055. indicates which device setup class is to be used in determining
  3056. information such as description, validation platform, and policy to
  3057. use. If this parameter is NULL, then the GUID is retrieved from the
  3058. INF list supplied via the LoadedInf parameter.
  3059. LoadedInf - Optionally, supplies the address of a loaded INF list we need
  3060. to examine to see if any of the members therein are device INFs. An
  3061. INF is a device INF if it specifies a class association (via either
  3062. Class= or ClassGUID= entries) in its [Version] section. If the
  3063. DeviceSetupClassGuid parameter is supplied (i.e., non-NULL), then this
  3064. parameter is ignored. If this parameter is also NULL, then it is
  3065. assumed the installation is not device-related.
  3066. The presence of a device INF anywhere in this list will cause us to
  3067. consider this a device installation. However, the _first_ INF we
  3068. encounter having a class association is what will be used in determining
  3069. the device description (see below).
  3070. ** NOTE: The caller is responsible for locking the loaded INF **
  3071. ** list prior to calling this routine! **
  3072. DeviceDesc - Optionally, supplies the address of a string pointer that will
  3073. be filled in upon return with a (newly-allocated) descriptive string to
  3074. be used when referring to this installation (e.g., for doing driver
  3075. signing failure popups). We will first try to retrieve the friendly
  3076. name for this INF's class (whose determination is described above). If
  3077. that's not possible (e.g., the class isn't yet installed), then we'll
  3078. return the class name. If that's not possible, then we'll return a
  3079. (localized) generic string such as "Unknown driver software package".
  3080. This output parameter (if supplied) will only ever be set to a non-NULL
  3081. value when the routine returns TRUE. The caller is responsible for
  3082. freeing this character buffer. If an out-of-memory failure is
  3083. encountered when trying to allocate memory for this buffer, the
  3084. DeviceDesc pointer will simply be set to NULL. It will also be set to
  3085. NULL if we're dealing with an exception package (since we don't want
  3086. to treat this like a "hardware install" for purposes of codesigning
  3087. blocking UI).
  3088. ValidationPlatform - Optionally, supplies the address of a (version 2)
  3089. altplatform info pointer that is filled in upon return with a newly-
  3090. allocated structure specifying the appropriate parameters to be passed
  3091. to WinVerifyTrust when validating this INF. These parameters are
  3092. retrieved from certclas.inf for the relevant device setup class GUID.
  3093. If no special parameters are specified for this class (or if the INF
  3094. has no class at all), then this pointer is returned as NULL, which
  3095. causes us to use WinVerifyTrust's default validation. Note that if
  3096. we fail to allocate this structure due to low-memory, the pointer will
  3097. be returned as NULL in that case as well. This is OK, because this
  3098. simply means we'll do default validation in that case.
  3099. By this mechanism, we can easily deal with the different validation
  3100. policies in effect for the various device classes we have in the system.
  3101. The caller is responsible for freeing the memory allocated for this
  3102. structure.
  3103. PolicyToUse - Optionally, supplies the address of a dword variable that is
  3104. set upon return to indicate what codesigning policy (i.e., Ignore, Warn,
  3105. or Block) should be used for this INF. This determination is made based
  3106. on whether any INF in the list is of a class that WHQL has a
  3107. certification program for (as specified in %windir%\Inf\certclas.inf).
  3108. Additionally, if any INF in the list is of the exception class, then
  3109. the policy is automatically set to Block (i.e., it's not configurable
  3110. via driver signing or non-driver-signing policy/preference settings).
  3111. UseOriginalInfName - Optionally, supplies the address of a boolean variable
  3112. that is set upon return to indicate whether the INF should be installed
  3113. into %windir%\Inf under its original name. This will only be true if
  3114. the INF is an exception INF.
  3115. Return Value:
  3116. If the INF is a device INF, the return value is TRUE. Otherwise, it is
  3117. FALSE.
  3118. --*/
  3119. {
  3120. PLOADED_INF CurInf, NextInf;
  3121. GUID ClassGuid;
  3122. BOOL DeviceInfFound, ClassInDrvSignList;
  3123. TCHAR ClassDescBuffer[LINE_LEN];
  3124. PCTSTR ClassDesc;
  3125. DWORD Err;
  3126. if(DeviceDesc) {
  3127. *DeviceDesc = NULL;
  3128. }
  3129. if(ValidationPlatform) {
  3130. *ValidationPlatform = NULL;
  3131. }
  3132. if(UseOriginalInfName) {
  3133. *UseOriginalInfName = FALSE;
  3134. }
  3135. if(!DeviceSetupClassGuid && !LoadedInf) {
  3136. //
  3137. // Not a whole lot to do here. Assume non-driver-signing policy and
  3138. // return.
  3139. //
  3140. if(PolicyToUse) {
  3141. *PolicyToUse = pSetupGetCurrentDriverSigningPolicy(FALSE);
  3142. }
  3143. return FALSE;
  3144. }
  3145. if(PolicyToUse || ValidationPlatform) {
  3146. if(PolicyToUse) {
  3147. //
  3148. // Initialize policy to "Ignore"
  3149. //
  3150. *PolicyToUse = DRIVERSIGN_NONE;
  3151. }
  3152. ClassInDrvSignList = FALSE;
  3153. }
  3154. //
  3155. // If DeviceSetupClassGuid was specified, then retrieve information
  3156. // pertaining to that class. Otherwise, traverse the individual INFs in
  3157. // the LOADED_INF list, examining each one to see if it's a device INF.
  3158. //
  3159. DeviceInfFound = FALSE;
  3160. for(CurInf = LoadedInf; CurInf || DeviceSetupClassGuid; CurInf = NextInf) {
  3161. //
  3162. // Setup a "NextInf" pointer so we won't dereference NULL when we go
  3163. // back through the loop in the case where we have a
  3164. // DeviceSetupClassGuid instead of a LoadedInf list.
  3165. //
  3166. NextInf = CurInf ? CurInf->Next : NULL;
  3167. if(!DeviceSetupClassGuid) {
  3168. if(ClassGuidFromInfVersionNode(&(CurInf->VersionBlock), &ClassGuid)) {
  3169. DeviceSetupClassGuid = &ClassGuid;
  3170. } else {
  3171. //
  3172. // This INF doesn't have an associated device setup class GUID,
  3173. // so skip it and continue on with our search for a device INF.
  3174. //
  3175. continue;
  3176. }
  3177. }
  3178. //
  3179. // NOTE: From this point forward, you must reset the
  3180. // DeviceSetupClasGuid pointer to NULL before making another pass
  3181. // through the loop. Otherwise, we'll enter an infinite loop, since
  3182. // we can enter the loop if that pointer is non-NULL.
  3183. //
  3184. if(IsEqualGUID(DeviceSetupClassGuid, &GUID_NULL)) {
  3185. //
  3186. // The INF specified a ClassGUID of GUID_NULL (e.g., like some of
  3187. // our non-device system INFs such as layout.inf do). Skip it, and
  3188. // continue on with our search for a device INF.
  3189. //
  3190. DeviceSetupClassGuid = NULL;
  3191. continue;
  3192. }
  3193. //
  3194. // If we get to this point, we have a device setup class GUID. If this
  3195. // is the first device INF we've encountered (or our first and only
  3196. // time through the loop when the caller passed us in a
  3197. // DeviceSetupClassGuid), then do our best to retrieve a description
  3198. // for it (if we've been asked to do so). We do not do this for
  3199. // exception packages, because we don't want them to be referred to as
  3200. // "hardware installs" in the Block dialog if a signature verification
  3201. // failure occurs.
  3202. //
  3203. if(!DeviceInfFound) {
  3204. DeviceInfFound = TRUE;
  3205. if(DeviceDesc) {
  3206. if(!IsEqualGUID(DeviceSetupClassGuid, &GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER)) {
  3207. //
  3208. // First, try to retrieve the class's friendly name.
  3209. //
  3210. if(SetupDiGetClassDescription(DeviceSetupClassGuid,
  3211. ClassDescBuffer,
  3212. SIZECHARS(ClassDescBuffer),
  3213. NULL)) {
  3214. ClassDesc = ClassDescBuffer;
  3215. } else if(CurInf) {
  3216. //
  3217. // OK, so the class isn't installed yet. Retrieve the
  3218. // class name from the INF itself.
  3219. //
  3220. ClassDesc = pSetupGetVersionDatum(&(CurInf->VersionBlock),
  3221. pszClass
  3222. );
  3223. } else {
  3224. //
  3225. // The caller passed us in a device setup class GUID
  3226. // instead of an INF. The class hasn't been installed yet,
  3227. // so we have no idea what to call it.
  3228. //
  3229. ClassDesc = NULL;
  3230. }
  3231. if(!ClassDesc) {
  3232. //
  3233. // We have a non-installed class, either with no INF, or
  3234. // with an INF that specifies a ClassGUID= entry, but no
  3235. // Class= entry in its [Version] section. If we tried
  3236. // to actually install a device from such an INF, we'd
  3237. // get a failure in SetupDiInstallClass because the
  3238. // class name is required when installing the class.
  3239. // However, this INF might never be used in a device
  3240. // installation, but it definitely is a device INF.
  3241. // Therefore, we just give it a generic description.
  3242. //
  3243. if(LoadString(MyDllModuleHandle,
  3244. IDS_UNKNOWN_DRIVER,
  3245. ClassDescBuffer,
  3246. SIZECHARS(ClassDescBuffer))) {
  3247. ClassDesc = ClassDescBuffer;
  3248. } else {
  3249. ClassDesc = NULL;
  3250. }
  3251. }
  3252. //
  3253. // OK, we have a description for this device (unless we hit
  3254. // some weird error).
  3255. //
  3256. if(ClassDesc) {
  3257. *DeviceDesc = DuplicateString(ClassDesc);
  3258. }
  3259. }
  3260. }
  3261. }
  3262. //
  3263. // If we get to this point, we know that: (a) we have a device setup
  3264. // class GUID and (b) we've retrieved a device description, if
  3265. // necessary.
  3266. //
  3267. if(PolicyToUse || ValidationPlatform) {
  3268. //
  3269. // First, check to see if this is an exception class--if it is,
  3270. // then policy is Block, and we want to install the INF and CAT
  3271. // files using their original names.
  3272. //
  3273. if(IsEqualGUID(DeviceSetupClassGuid, &GUID_DEVCLASS_WINDOWS_COMPONENT_PUBLISHER)) {
  3274. if(PolicyToUse) {
  3275. *PolicyToUse = DRIVERSIGN_BLOCKING;
  3276. }
  3277. if(UseOriginalInfName) {
  3278. *UseOriginalInfName = TRUE;
  3279. }
  3280. }
  3281. //
  3282. // Now check to see if this class is in our list of classes that
  3283. // WHQL has certification programs for (hence should be subject to
  3284. // driver signing policy).
  3285. //
  3286. // NOTE: We may also find the exception class GUID in this list.
  3287. // This may be used as an override mechanism, in case we decide to
  3288. // allow 5.0-signed exception packages install on 5.1, for example.
  3289. //
  3290. ClassInDrvSignList = ClassGuidInDrvSignPolicyList(
  3291. LogContext,
  3292. DeviceSetupClassGuid,
  3293. ValidationPlatform
  3294. );
  3295. if(ClassInDrvSignList) {
  3296. //
  3297. // Once we encounter a device INF whose class is in our driver
  3298. // signing policy list, we can stop looking...
  3299. //
  3300. break;
  3301. }
  3302. } else {
  3303. //
  3304. // The caller doesn't care about whether this class is subject to
  3305. // driver signing policy. Since we've already retrieved the info
  3306. // they care about, we can get out of this loop.
  3307. //
  3308. break;
  3309. }
  3310. DeviceSetupClassGuid = NULL; // break out in no-INF case
  3311. }
  3312. if(PolicyToUse) {
  3313. //
  3314. // Unless we've already established that the policy to use is "Block"
  3315. // (because we found an exception INF), we should retrieve the
  3316. // applicable policy now...
  3317. //
  3318. if(*PolicyToUse != DRIVERSIGN_BLOCKING) {
  3319. *PolicyToUse =
  3320. pSetupGetCurrentDriverSigningPolicy(DeviceInfFound && ClassInDrvSignList);
  3321. }
  3322. }
  3323. return DeviceInfFound;
  3324. }
  3325. DWORD
  3326. GetCodeSigningPolicyForInf(
  3327. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  3328. IN HINF InfHandle,
  3329. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform, OPTIONAL
  3330. OUT PBOOL UseOriginalInfName OPTIONAL
  3331. )
  3332. /*++
  3333. Routine Description:
  3334. This routine returns a value indicating the appropriate policy to be
  3335. employed should a digital signature verification failure arise from some
  3336. operation initiated by that INF. It figures out whether the INF is subject
  3337. to driver signing or non-driver signing policy (based on the INF's class
  3338. affiliation, and the presence of an applicable WHQL program). It also can
  3339. return an altplatform info structure indicating how validation should be
  3340. done (i.e., if certclas.inf indicates that a range of OSATTR versions should
  3341. be considered valid).
  3342. Arguments:
  3343. LogContext - Optionally, supplies the log context for any log entries that
  3344. might be generated by this routine.
  3345. InfHandle - Supplies the handle of the INF for which policy is to be
  3346. retrieved.
  3347. ValidationPlatform - See preamble of IsInfForDeviceInstall routine for
  3348. details.
  3349. UseOriginalInfName - Optionally, supplies the address of a boolean variable
  3350. that is set upon return to indicate whether the INF should be installed
  3351. into %windir%\Inf under its original name. This will only be true if
  3352. the INF is an exception INF.
  3353. Return Value:
  3354. If the INF is a device INF, the return value is TRUE. Otherwise, it is
  3355. FALSE.
  3356. --*/
  3357. {
  3358. DWORD Policy;
  3359. if(!LockInf((PLOADED_INF)InfHandle)) {
  3360. //
  3361. // This is an internal-only routine, and all callers should be
  3362. // passing in valid INF handles.
  3363. //
  3364. MYASSERT(FALSE);
  3365. //
  3366. // If this does happen, just assume this isn't a device INF.
  3367. //
  3368. if(UseOriginalInfName) {
  3369. *UseOriginalInfName = FALSE;
  3370. }
  3371. if(ValidationPlatform) {
  3372. *ValidationPlatform = NULL;
  3373. }
  3374. return pSetupGetCurrentDriverSigningPolicy(FALSE);
  3375. }
  3376. IsInfForDeviceInstall(LogContext,
  3377. NULL,
  3378. (PLOADED_INF)InfHandle,
  3379. NULL,
  3380. ValidationPlatform,
  3381. &Policy,
  3382. UseOriginalInfName
  3383. );
  3384. UnlockInf((PLOADED_INF)InfHandle);
  3385. return Policy;
  3386. }
  3387. VOID
  3388. pSetupGetRealSystemTime(
  3389. OUT LPSYSTEMTIME RealSystemTime
  3390. );
  3391. DWORD
  3392. pSetupGetCurrentDriverSigningPolicy(
  3393. IN BOOL IsDeviceInstallation
  3394. )
  3395. /*++
  3396. Routine Description:
  3397. (The following description describes the strategy behind the selection of
  3398. policy. The implementation, however, follows a few twists and turns due to
  3399. unscupulous individuals who would subvert digital signature UI in order to
  3400. avoid having to get their packages signed...)
  3401. This routine returns a value indicating what action should be taken when a
  3402. digital signature verification failure is encountered. Separate "policies"
  3403. are maintained for "DriverSigning" (i.e., device installer activities) and
  3404. "NonDriverSigning" (i.e., everything else).
  3405. For driver signing, there are actually 3 sources of policy:
  3406. 1. HKLM\Software\Microsoft\Driver Signing : Policy : REG_BINARY (REG_DWORD also supported)
  3407. This is a Windows 98-compatible value that specifies the default
  3408. behavior which applies to all users of the machine.
  3409. 2. HKCU\Software\Microsoft\Driver Signing : Policy : REG_DWORD
  3410. This specifies the user's preference for what behavior to employ
  3411. upon verification failure.
  3412. 3. HKCU\Software\Policies\Microsoft\Windows NT\Driver Signing : BehaviorOnFailedVerify : REG_DWORD
  3413. This specifies the administrator-mandated policy on what behavior
  3414. to employ upon verification failure. This policy, if specified,
  3415. overrides the user's preference.
  3416. The algorithm for deciding on the behavior to employ is as follows:
  3417. if (3) is specified {
  3418. policy = (3)
  3419. } else {
  3420. policy = (2)
  3421. }
  3422. policy = MAX(policy, (1))
  3423. For non-driver signing, the algorithm is the same, except that values (1),
  3424. (2), and (3) come from the following registry locations:
  3425. 1. HKLM\Software\Microsoft\Non-Driver Signing : Policy : REG_BINARY (REG_DWORD also supported)
  3426. 2. HKCU\Software\Microsoft\Non-Driver Signing : Policy : REG_DWORD
  3427. 3. HKCU\Software\Policies\Microsoft\Windows NT\Non-Driver Signing : BehaviorOnFailedVerify : REG_DWORD
  3428. NOTE: If we're in non-interactive mode, policy is always Block, so we
  3429. don't even bother trying to retrieve any of these registry settings.
  3430. Another reason to avoid doing so is to keep from jumping to the
  3431. wrong conclusion that someone has tampered with policy when in
  3432. reality, we're in a service that loaded in GUI setup prior to the
  3433. time when the policy values were fully initialized.
  3434. Arguments:
  3435. IsDeviceInstallation - If non-zero, then driver signing policy should be
  3436. retrieved. Otherwise, non-driver signing policy should be used.
  3437. Return Value:
  3438. Value indicating the policy in effect. May be one of the following three
  3439. values:
  3440. DRIVERSIGN_NONE - silently succeed installation of unsigned/
  3441. incorrectly-signed files. A PSS log entry will
  3442. be generated, however (as it will for all 3 types)
  3443. DRIVERSIGN_WARNING - warn the user, but let them choose whether or not
  3444. they still want to install the problematic file
  3445. DRIVERSIGN_BLOCKING - do not allow the file to be installed
  3446. (If policy can't be retrieved from any of the sources described above, the
  3447. default is DRIVERSIGN_NONE.)
  3448. --*/
  3449. {
  3450. SYSTEMTIME RealSystemTime;
  3451. DWORD PolicyFromReg, PolicyFromDS, RegDataType, RegDataSize;
  3452. HKEY hKey;
  3453. BOOL UserPolicyRetrieved = FALSE;
  3454. WORD w;
  3455. if(GlobalSetupFlags & PSPGF_NONINTERACTIVE) {
  3456. return DRIVERSIGN_BLOCKING;
  3457. }
  3458. w = IsDeviceInstallation?1:0;
  3459. RealSystemTime.wDayOfWeek = (LOWORD(&hKey)&~4)|(w<<2);
  3460. pSetupGetRealSystemTime(&RealSystemTime);
  3461. PolicyFromReg = (((RealSystemTime.wMilliseconds+2)&15)^8)/4;
  3462. MYASSERT(PolicyFromReg <= DRIVERSIGN_BLOCKING);
  3463. //
  3464. // Retrieve the user policy. If policy isn't set for this user, then
  3465. // retrieve the user's preference, instead.
  3466. //
  3467. PolicyFromDS = DRIVERSIGN_NONE;
  3468. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
  3469. (IsDeviceInstallation ? pszDrvSignPolicyPath
  3470. : pszNonDrvSignPolicyPath),
  3471. 0,
  3472. KEY_READ,
  3473. &hKey))
  3474. {
  3475. RegDataSize = sizeof(PolicyFromDS);
  3476. if(ERROR_SUCCESS == RegQueryValueEx(hKey,
  3477. pszDrvSignBehaviorOnFailedVerifyDS,
  3478. NULL,
  3479. &RegDataType,
  3480. (PBYTE)&PolicyFromDS,
  3481. &RegDataSize))
  3482. {
  3483. if((RegDataType == REG_DWORD) &&
  3484. (RegDataSize == sizeof(DWORD)) &&
  3485. ((PolicyFromDS == DRIVERSIGN_NONE) || (PolicyFromDS == DRIVERSIGN_WARNING) || (PolicyFromDS == DRIVERSIGN_BLOCKING)))
  3486. {
  3487. //
  3488. // We successfully retrieved user policy, so we won't need to
  3489. // retrieve user preference.
  3490. //
  3491. UserPolicyRetrieved = TRUE;
  3492. }
  3493. }
  3494. RegCloseKey(hKey);
  3495. }
  3496. //
  3497. // If we didn't find a user policy, then retrieve the user preference.
  3498. //
  3499. if(!UserPolicyRetrieved) {
  3500. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
  3501. (IsDeviceInstallation ? pszDrvSignPath
  3502. : pszNonDrvSignPath),
  3503. 0,
  3504. KEY_READ,
  3505. &hKey))
  3506. {
  3507. RegDataSize = sizeof(PolicyFromDS);
  3508. if(ERROR_SUCCESS == RegQueryValueEx(hKey,
  3509. pszDrvSignPolicyValue,
  3510. NULL,
  3511. &RegDataType,
  3512. (PBYTE)&PolicyFromDS,
  3513. &RegDataSize))
  3514. {
  3515. if((RegDataType != REG_DWORD) ||
  3516. (RegDataSize != sizeof(DWORD)) ||
  3517. !((PolicyFromDS == DRIVERSIGN_NONE) || (PolicyFromDS == DRIVERSIGN_WARNING) || (PolicyFromDS == DRIVERSIGN_BLOCKING)))
  3518. {
  3519. //
  3520. // Bogus entry for user preference--ignore it.
  3521. //
  3522. PolicyFromDS = DRIVERSIGN_NONE;
  3523. }
  3524. }
  3525. RegCloseKey(hKey);
  3526. }
  3527. }
  3528. //
  3529. // Now return the more restrictive of the two policies.
  3530. //
  3531. if(PolicyFromDS > PolicyFromReg) {
  3532. return PolicyFromDS;
  3533. } else {
  3534. return PolicyFromReg;
  3535. }
  3536. }
  3537. DWORD
  3538. VerifySourceFile(
  3539. IN PSETUP_LOG_CONTEXT LogContext,
  3540. IN PSP_FILE_QUEUE Queue, OPTIONAL
  3541. IN PSP_FILE_QUEUE_NODE QueueNode, OPTIONAL
  3542. IN PCTSTR Key,
  3543. IN PCTSTR FileToVerifyFullPath,
  3544. IN PCTSTR OriginalSourceFileFullPath, OPTIONAL
  3545. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  3546. IN DWORD Flags,
  3547. OUT SetupapiVerifyProblem *Problem,
  3548. OUT LPTSTR ProblemFile,
  3549. OUT LPTSTR CatalogFileUsed, OPTIONAL
  3550. OUT LPTSTR DigitalSigner, OPTIONAL
  3551. OUT LPTSTR SignerVersion OPTIONAL
  3552. )
  3553. /*++
  3554. Routine Description:
  3555. This routine verifies the digital signature of the specified file either
  3556. globally (i.e., using all catalogs), or based on the catalog file specified
  3557. in the supplied queue node.
  3558. Arguments:
  3559. LogContext - supplies a context for logging the verify
  3560. Queue - supplies pointer to the queue structure. This contains information
  3561. about the default verification method to use when the file isn't
  3562. associated with a particular catalog.
  3563. QueueNode - Optionally, supplies the queue node containing catalog
  3564. information to be used when verifying the file's signature. If not
  3565. supplied, then the file will be verified using all applicable installed
  3566. catalogs. If this pointer is supplied, then so must the Queue
  3567. parameter.
  3568. Key - Supplies a value that "indexes" the catalog, telling the verify APIs
  3569. which signature datum within the catalog it should use. Typically
  3570. the key is the name of the destination file (sans path) that the source
  3571. file is to be copied to.
  3572. FileToVerifyFullPath - Supplies the full path of the file to be verified.
  3573. OriginalSourceFileFullPath - Optionally, supplies the original source file's
  3574. name, to be returned in the ProblemFile buffer when an error occurs. If
  3575. this parameter is not specified, then the source file's original name is
  3576. assumed to be the same as the filename we're verifying, and the path
  3577. supplied in FileToVerifyFullPath will be returned in the ProblemFile
  3578. buffer in case of error.
  3579. AltPlatformInfo - optionally, supplies alternate platform information used
  3580. to fill in a DRIVER_VER_INFO structure (defined in sdk\inc\softpub.h)
  3581. that is passed to WinVerifyTrust.
  3582. ** NOTE: This structure _must_ have its cbSize field set to **
  3583. ** sizeof(SP_ALTPLATFORM_INFO_V2) -- validation on client-supplied **
  3584. ** buffer is the responsibility of the caller. **
  3585. Flags - supplies flags that alter that behavior of this routine. May be a
  3586. combination of the following values:
  3587. VERIFY_FILE_IGNORE_SELFSIGNED - if this bit is set, then this routine
  3588. will fail validation for self-signed
  3589. binaries.
  3590. VERIFY_FILE_USE_OEM_CATALOGS - if this bit is set, then all catalogs
  3591. installed in the system will be scanned
  3592. to verify the given file. Otherwise,
  3593. OEM (3rd party) catalogs will NOT be
  3594. scanned to verify the given file. This
  3595. is only applicable if a QueueNode
  3596. specifying a specific catalog is not
  3597. given.
  3598. VERIFY_FILE_FAIL_COPIED_INFS - if this bit is set, then INFs destined
  3599. for %windir%\Inf will automatically
  3600. fail verification.
  3601. VERIFY_FILE_DRIVERBLOCKED_ONLY - Only check if the file is in the bad
  3602. driver database, don't do any digital
  3603. sigature validation.
  3604. Problem - Points to a variable that will be filled in upon unsuccessful
  3605. return with the cause of failure.
  3606. ProblemFile - Supplies the address of a character buffer that will be filled
  3607. in upon unsuccessful return to indicate the file that failed verification.
  3608. This may be the name of the file we're verifying (or it's original name,
  3609. if supplied), or it may be the name of the catalog used for verification,
  3610. if the catalog itself isn't properly signed. (The type of file can be
  3611. ascertained from the value returned in the Problem output parameter.)
  3612. CatalogFileUsed - if supplied, this parameter points to a character buffer
  3613. at least MAX_PATH characters big that receives the name of the catalog
  3614. file used to verify the specified file. This is only filled in upon
  3615. successful return, or when the Problem is SetupapiVerifyFileProblem
  3616. (i.e., the catalog verified, but the file did not). If this buffer is
  3617. set to the empty string upon a SetupapiVerifyFileProblem failure, then
  3618. we didn't find any applicable catalogs to use for validation.
  3619. Also, this buffer will contain an empty string upon successful return
  3620. if the file was validated without using a catalog (i.e., the file
  3621. contains its own signature).
  3622. DigitalSigner - if supplied, this parameter points to a character buffer of
  3623. at least MAX_PATH characters that receives the name of who digitally
  3624. signed the specified file. This value is only set if the Key is
  3625. correctly signed (i.e. the function returns NO_ERROR).
  3626. SignerVersion - if supplied, this parameter points to a character buffer of
  3627. at least MAX_PATH characters that receives the the signer version as
  3628. returned in the szwVerion field of the DRIVER_VER_INFO structure in
  3629. our call to WinVerifyTrust.
  3630. Return Value:
  3631. If successful, the return value is NO_ERROR;
  3632. If unsuccessful, the return value is the Win32 error code indicating the
  3633. cause of the failure.
  3634. --*/
  3635. {
  3636. DWORD rc;
  3637. PCTSTR AltCatalogFile;
  3638. LPCTSTR InfFullPath;
  3639. MYASSERT(!QueueNode || Queue);
  3640. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  3641. //
  3642. // Nobody had better be calling this expecting to get back any info
  3643. // about a successful verification!
  3644. //
  3645. MYASSERT(!CatalogFileUsed);
  3646. MYASSERT(!DigitalSigner);
  3647. MYASSERT(!SignerVersion);
  3648. return NO_ERROR;
  3649. }
  3650. //
  3651. // If we know the file's destination (i.e., we have a QueueNode), and we've
  3652. // been asked to fail any INFs headed for %windir%\Inf, we check for that
  3653. // up-front. We don't do this for exception packages, since it's assumed
  3654. // (whether correctly or incorrectly) that they're "part of the OS", and as
  3655. // such, they know what they're doing.
  3656. //
  3657. if(QueueNode && (Flags & VERIFY_FILE_FAIL_COPIED_INFS) &&
  3658. !(Queue->Flags & FQF_KEEP_INF_AND_CAT_ORIGINAL_NAMES)) {
  3659. TCHAR TargetPath[MAX_PATH];
  3660. LPCTSTR TargetFilename, p;
  3661. //
  3662. // Is the target file an INF?
  3663. //
  3664. TargetFilename = pSetupStringTableStringFromId(Queue->StringTable,
  3665. QueueNode->TargetFilename
  3666. );
  3667. p = _tcsrchr(TargetFilename, TEXT('.'));
  3668. if(p && !lstrcmpi(p, pszInfSuffix)) {
  3669. //
  3670. // It's an INF. Construct the full target path to see where it's
  3671. // going.
  3672. //
  3673. lstrcpyn(
  3674. TargetPath,
  3675. pSetupStringTableStringFromId(Queue->StringTable, QueueNode->TargetDirectory),
  3676. SIZECHARS(TargetPath)
  3677. );
  3678. pSetupConcatenatePaths(TargetPath,
  3679. TargetFilename,
  3680. SIZECHARS(TargetPath),
  3681. NULL
  3682. );
  3683. if(!pSetupInfIsFromOemLocation(TargetPath, TRUE)) {
  3684. //
  3685. // It is invalid to copy an INF into %windir%\Inf via a file
  3686. // queue. Report this file as unsigned...
  3687. //
  3688. *Problem = SetupapiVerifyIncorrectlyCopiedInf;
  3689. lstrcpy(ProblemFile, FileToVerifyFullPath);
  3690. return ERROR_INCORRECTLY_COPIED_INF;
  3691. }
  3692. }
  3693. }
  3694. //
  3695. // Check to see if the source file is signed.
  3696. //
  3697. if(QueueNode && QueueNode->CatalogInfo) {
  3698. //
  3699. // We should never have the IQF_FROM_BAD_OEM_INF internal flag set in
  3700. // this case.
  3701. //
  3702. MYASSERT(!(QueueNode->InternalFlags & IQF_FROM_BAD_OEM_INF));
  3703. if(*(QueueNode->CatalogInfo->CatalogFilenameOnSystem)) {
  3704. //
  3705. // The fact that our catalog info node has a filename filled in
  3706. // means we successfully verfied this catalog previously. So
  3707. // all we need _VerifyFile to do is just verify the temporary
  3708. // (source) file against that catalog.
  3709. //
  3710. rc = _VerifyFile(LogContext,
  3711. &(Queue->hCatAdmin),
  3712. &(Queue->hSDBDrvMain),
  3713. QueueNode->CatalogInfo->CatalogFilenameOnSystem,
  3714. NULL,
  3715. 0,
  3716. Key,
  3717. FileToVerifyFullPath,
  3718. Problem,
  3719. ProblemFile,
  3720. TRUE,
  3721. AltPlatformInfo,
  3722. Flags,
  3723. CatalogFileUsed,
  3724. NULL,
  3725. DigitalSigner,
  3726. SignerVersion
  3727. );
  3728. } else {
  3729. //
  3730. // If there's no error associated with this catalog info node, then
  3731. // that simply means that the INF didn't specify a CatalogFile=
  3732. // entry, thus we should do global validation. If there is an
  3733. // error then we still need to check if the driver is in the bad
  3734. // driver database.
  3735. //
  3736. // If the queue has an alternate default catalog file associated
  3737. // with it, then retrieve that catalog's name for use later.
  3738. //
  3739. AltCatalogFile = (Queue->AltCatalogFile != -1)
  3740. ? pSetupStringTableStringFromId(Queue->StringTable, Queue->AltCatalogFile)
  3741. : NULL;
  3742. rc = _VerifyFile(LogContext,
  3743. &(Queue->hCatAdmin),
  3744. &(Queue->hSDBDrvMain),
  3745. AltCatalogFile,
  3746. NULL,
  3747. 0,
  3748. Key,
  3749. FileToVerifyFullPath,
  3750. Problem,
  3751. ProblemFile,
  3752. FALSE,
  3753. AltPlatformInfo,
  3754. Flags |
  3755. ((QueueNode->CatalogInfo->VerificationFailureError == NO_ERROR)
  3756. ? 0
  3757. : VERIFY_FILE_DRIVERBLOCKED_ONLY),
  3758. CatalogFileUsed,
  3759. NULL,
  3760. DigitalSigner,
  3761. SignerVersion
  3762. );
  3763. if ((rc == NO_ERROR) &&
  3764. (QueueNode->CatalogInfo->VerificationFailureError != NO_ERROR)) {
  3765. //
  3766. // If there is an error associated with this catalog info node
  3767. // and the file was not in the bad driver database then return
  3768. // the error.
  3769. //
  3770. rc = QueueNode->CatalogInfo->VerificationFailureError;
  3771. if(rc == ERROR_NO_CATALOG_FOR_OEM_INF) {
  3772. //
  3773. // The failure is the INF's fault (it's an OEM INF that
  3774. // copies files without specifying a catalog). Blame the
  3775. // INF, not the file being copied.
  3776. //
  3777. *Problem = SetupapiVerifyInfProblem;
  3778. MYASSERT(QueueNode->CatalogInfo->InfFullPath != -1);
  3779. InfFullPath = pSetupStringTableStringFromId(
  3780. Queue->StringTable,
  3781. QueueNode->CatalogInfo->InfFullPath
  3782. );
  3783. lstrcpy(ProblemFile, InfFullPath);
  3784. } else {
  3785. //
  3786. // We previously failed to validate the catalog file
  3787. // associated with this queue node.
  3788. //
  3789. *Problem = SetupapiVerifyFileNotSigned;
  3790. //
  3791. // If the caller didn't supply us with an original source filepath
  3792. // (which will be taken care of later), go ahead and copy the path
  3793. // of the file that was to be verified.
  3794. //
  3795. if(!OriginalSourceFileFullPath) {
  3796. lstrcpy(ProblemFile, FileToVerifyFullPath);
  3797. }
  3798. }
  3799. }
  3800. }
  3801. } else {
  3802. //
  3803. // We have no queue, or we couldn't associate this source file back
  3804. // to a catalog info node that tells us exactly which catalog to use
  3805. // for verification. Thus, we'll have to settle for global
  3806. // validation.
  3807. //
  3808. BOOL InfIsBad = FALSE;
  3809. rc = NO_ERROR;
  3810. if(Queue) {
  3811. if(Queue->AltCatalogFile == -1) {
  3812. if(QueueNode && (QueueNode->InternalFlags & IQF_FROM_BAD_OEM_INF)) {
  3813. InfIsBad = TRUE;
  3814. }
  3815. AltCatalogFile = NULL;
  3816. } else {
  3817. //
  3818. // We have an alternate catalog file to use instead of global
  3819. // validation.
  3820. //
  3821. AltCatalogFile = pSetupStringTableStringFromId(Queue->StringTable, Queue->AltCatalogFile);
  3822. }
  3823. } else {
  3824. AltCatalogFile = NULL;
  3825. }
  3826. rc = _VerifyFile(LogContext,
  3827. Queue ? &(Queue->hCatAdmin) : NULL,
  3828. Queue ? &(Queue->hSDBDrvMain) : NULL,
  3829. AltCatalogFile,
  3830. NULL,
  3831. 0,
  3832. Key,
  3833. FileToVerifyFullPath,
  3834. Problem,
  3835. ProblemFile,
  3836. FALSE,
  3837. AltPlatformInfo,
  3838. Flags |
  3839. (InfIsBad ? VERIFY_FILE_DRIVERBLOCKED_ONLY : 0),
  3840. CatalogFileUsed,
  3841. NULL,
  3842. DigitalSigner,
  3843. SignerVersion
  3844. );
  3845. if (rc == NO_ERROR) {
  3846. if(InfIsBad) {
  3847. //
  3848. // The driver file was not blocked, but the INF was bad so set
  3849. // the appropriate error and problem values.
  3850. //
  3851. rc = ERROR_NO_CATALOG_FOR_OEM_INF;
  3852. *Problem = SetupapiVerifyFileProblem;
  3853. lstrcpy(ProblemFile, FileToVerifyFullPath);
  3854. }
  3855. }
  3856. }
  3857. //
  3858. // If the problem was with the file (as opposed to with the catalog), then
  3859. // use the real source name, if supplied, as opposed to the temporary
  3860. // filename we passed into _VerifyFile.
  3861. //
  3862. if((rc != NO_ERROR) && OriginalSourceFileFullPath &&
  3863. ((*Problem == SetupapiVerifyFileNotSigned) || (*Problem == SetupapiVerifyFileProblem))) {
  3864. lstrcpy(ProblemFile, OriginalSourceFileFullPath);
  3865. }
  3866. return rc;
  3867. }
  3868. BOOL
  3869. VerifyDeviceInfFile(
  3870. IN PSETUP_LOG_CONTEXT LogContext,
  3871. IN OUT HCATADMIN *hCatAdmin, OPTIONAL
  3872. IN LPCTSTR CurrentInfName,
  3873. IN PLOADED_INF pInf,
  3874. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  3875. OUT LPTSTR CatalogFileUsed, OPTIONAL
  3876. OUT LPTSTR DigitalSigner, OPTIONAL
  3877. OUT LPTSTR SignerVersion OPTIONAL
  3878. )
  3879. /*++
  3880. Routine Description:
  3881. This routine performs a digital signature verification on the specified
  3882. INF file.
  3883. Arguments:
  3884. LogContext - supplies the log context to be used in logging an error if
  3885. we encounter an error.
  3886. hCatAdmin - optionally, supplies the address of an HCATADMIN handle. If
  3887. the handle pointed to is NULL, a handle will be acquired (if possible)
  3888. via CryptCATAdminAcquireContext and returned to the caller. If the
  3889. handle pointed to is non-NULL, then that handle will be used for any
  3890. validation done via this routine. If the pointer itself is NULL, then
  3891. an hCatAdmin will be acquired for the duration of this call, and
  3892. released before returning.
  3893. NOTE: it is the caller's responsibility to free the crypto context
  3894. handle returned by this routine by calling CryptCATAdminReleaseContext.
  3895. This handle may be opened in either success or failure cases, so the
  3896. caller must check for non-NULL returned handle in both cases.
  3897. CurrentInfName - supplies the full path to the INF to be validated
  3898. pInf - supplies a pointer to the LOADED_INF structure corresponding to this
  3899. INF.
  3900. AltPlatformInfo - optionally, supplies alternate platform information to
  3901. be used when validating this INF.
  3902. CatalogFileUsed - optionally, supplies a character buffer that must be at
  3903. least MAX_PATH characters in size. Upon successful return, this buffer
  3904. will be filled in with the catalog file used to validate the INF.
  3905. DigitalSigner - optionally, supplies a character buffer that must be at
  3906. least MAX_PATH characters in size. Upon successful return, this buffer
  3907. will be filled in with the name of the signer.
  3908. SignerVersion - optionally, supplies a character buffer that must be at
  3909. least MAX_PATH characters in size. Upon successful return, this buffer
  3910. will be filled in with the signer version information.
  3911. Return Value:
  3912. If the INF's signature is successfully verified, the return value is
  3913. non-zero (TRUE).
  3914. Otherwise, the return value is FALSE. GetLastError can be used to obtain
  3915. the Win32 error code indicating the cause of failure.
  3916. --*/
  3917. {
  3918. BOOL DifferentOriginalName;
  3919. TCHAR OriginalCatalogName[MAX_PATH];
  3920. TCHAR CatalogPath[MAX_PATH];
  3921. TCHAR OriginalInfFileName[MAX_PATH];
  3922. DWORD Err;
  3923. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform;
  3924. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  3925. //
  3926. // Nobody had better be calling this expecting to get back any info
  3927. // about a successful verification!
  3928. //
  3929. MYASSERT(!CatalogFileUsed);
  3930. MYASSERT(!DigitalSigner);
  3931. MYASSERT(!SignerVersion);
  3932. return TRUE;
  3933. }
  3934. if(GlobalSetupFlags & PSPGF_AUTOFAIL_VERIFIES) {
  3935. SetLastError(TRUST_E_FAIL);
  3936. return FALSE;
  3937. }
  3938. CatalogPath[0] = TEXT('\0');
  3939. Err = pGetInfOriginalNameAndCatalogFile(pInf,
  3940. NULL,
  3941. &DifferentOriginalName,
  3942. OriginalInfFileName,
  3943. SIZECHARS(OriginalInfFileName),
  3944. OriginalCatalogName,
  3945. SIZECHARS(OriginalCatalogName),
  3946. AltPlatformInfo
  3947. );
  3948. if(Err != NO_ERROR) {
  3949. SetLastError(Err);
  3950. return FALSE;
  3951. }
  3952. if(pSetupInfIsFromOemLocation(CurrentInfName, TRUE)) {
  3953. //
  3954. // INF isn't in %windir%\Inf (i.e., it's 3rd-party), so it had better
  3955. // specify a catalog file...
  3956. //
  3957. if(!*OriginalCatalogName) {
  3958. SetLastError(ERROR_NO_CATALOG_FOR_OEM_INF);
  3959. return FALSE;
  3960. }
  3961. //
  3962. // ...and the CAT must reside in the same directory as the INF.
  3963. //
  3964. lstrcpy(CatalogPath, CurrentInfName);
  3965. lstrcpy((PTSTR)pSetupGetFileTitle(CatalogPath), OriginalCatalogName);
  3966. } else {
  3967. //
  3968. // The INF lives in %windir%\Inf.
  3969. // If it is a 3rd party INF then we want to set the CatalogPath to
  3970. // the current INF name with .CAT at the end instead of .INF (e.g
  3971. // oem1.cat). If this is not an OEM catalog then we won't set the
  3972. // CatalogPath so we can search all of the catalogs in the system.
  3973. //
  3974. // We will assume that if the INF had a different original name.
  3975. //
  3976. if (DifferentOriginalName) {
  3977. lstrcpy(CatalogPath, pSetupGetFileTitle(CurrentInfName));
  3978. lstrcpy(_tcsrchr(CatalogPath, TEXT('.')), pszCatSuffix);
  3979. }
  3980. }
  3981. if(DifferentOriginalName) {
  3982. MYASSERT(*OriginalInfFileName);
  3983. } else {
  3984. //
  3985. // INF's current name is the same as its original name, so store the
  3986. // simple filename (sans path) for use as the validation key in the
  3987. // upcoming call to _VerifyFile.
  3988. //
  3989. lstrcpy(OriginalInfFileName, pSetupGetFileTitle(CurrentInfName));
  3990. }
  3991. //
  3992. // If the caller didn't supply alternate platform information, we need to
  3993. // check and see whether a range of OSATTR versions should be considered
  3994. // valid for this INF's class.
  3995. //
  3996. if(!AltPlatformInfo) {
  3997. IsInfForDeviceInstall(LogContext,
  3998. NULL,
  3999. pInf,
  4000. NULL,
  4001. &ValidationPlatform,
  4002. NULL,
  4003. NULL
  4004. );
  4005. } else {
  4006. ValidationPlatform = NULL;
  4007. }
  4008. Err = _VerifyFile(LogContext,
  4009. hCatAdmin,
  4010. NULL,
  4011. (*CatalogPath ? CatalogPath : NULL),
  4012. NULL,
  4013. 0,
  4014. OriginalInfFileName,
  4015. CurrentInfName,
  4016. NULL,
  4017. NULL,
  4018. FALSE,
  4019. (AltPlatformInfo ? AltPlatformInfo : ValidationPlatform),
  4020. (VERIFY_FILE_IGNORE_SELFSIGNED
  4021. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4022. CatalogFileUsed,
  4023. NULL,
  4024. DigitalSigner,
  4025. SignerVersion);
  4026. if(ValidationPlatform) {
  4027. MyFree(ValidationPlatform);
  4028. }
  4029. SetLastError(Err);
  4030. return (Err == NO_ERROR);
  4031. }
  4032. BOOL
  4033. IsFileProtected(
  4034. IN LPCTSTR FileFullPath,
  4035. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  4036. OUT PHANDLE phSfp OPTIONAL
  4037. )
  4038. /*++
  4039. Routine Description:
  4040. This routine determines whether the specified file is a protected system
  4041. file.
  4042. Arguments:
  4043. FileFullPath - supplies the full path to the file of interest
  4044. LogContext - supplies the log context to be used in logging an error if
  4045. we're unable to open an SFC handle.
  4046. phSfp - optionally, supplies the address of a handle variable that will be
  4047. filled in with a handle to the SFC server. This will only be supplied
  4048. when the routine returns TRUE (i.e., the file is SFP-protected).
  4049. Return Value:
  4050. If the file is protected, the return value is TRUE, otherwise it is FALSE.
  4051. --*/
  4052. {
  4053. BOOL ret;
  4054. #ifdef UNICODE
  4055. HANDLE hSfp;
  4056. hSfp = SfcConnectToServer(NULL);
  4057. if(!hSfp) {
  4058. //
  4059. // This ain't good...
  4060. //
  4061. WriteLogEntry(LogContext,
  4062. SETUP_LOG_ERROR,
  4063. MSG_LOG_SFC_CONNECT_FAILED,
  4064. NULL
  4065. );
  4066. return FALSE;
  4067. }
  4068. try {
  4069. ret = SfcIsFileProtected(hSfp, FileFullPath);
  4070. } except(EXCEPTION_EXECUTE_HANDLER) {
  4071. ret = FALSE;
  4072. }
  4073. //
  4074. // If the file _is_ protected, and the caller wants the SFP handle (e.g.,
  4075. // to subsequently exempt an unsigned replacement operation), then save
  4076. // the handle in the caller-supplied buffer. Otherwise, close the handle.
  4077. //
  4078. if(ret && phSfp) {
  4079. *phSfp = hSfp;
  4080. } else {
  4081. SfcClose(hSfp);
  4082. }
  4083. #else // no file protection on Win9x
  4084. ret = FALSE;
  4085. #endif
  4086. return ret;
  4087. }
  4088. PSTR
  4089. GetAnsiMuiSafePathname(
  4090. IN PCTSTR FilePath
  4091. )
  4092. /*++
  4093. Routine Description:
  4094. Remove filename portion of FilePath
  4095. and convert rest of path to be MUI parse safe
  4096. Note that the returned pathname is such that the FileName can be cat'd
  4097. so for "E:\i386\myfile.dl_" FilePath = "E:\i386\" and FileName = "myfile.dl_"
  4098. *This is required* (it also happens to make this code easier)
  4099. Arguments:
  4100. FilePath - path+filename to convert
  4101. Return Value:
  4102. If successful, the return value is pointer to ANSI filepath (memory allocated by pSetupMalloc)
  4103. If unsuccessful, the return value is NULL and GetLastError returns error
  4104. --*/
  4105. {
  4106. TCHAR Buffer[MAX_PATH];
  4107. LPTSTR FilePart;
  4108. DWORD actsz;
  4109. actsz = GetFullPathName(FilePath,MAX_PATH,Buffer,&FilePart);
  4110. if(actsz == 0) {
  4111. //
  4112. // GetLastError has error
  4113. //
  4114. return NULL;
  4115. }
  4116. if(actsz >= MAX_PATH) {
  4117. //
  4118. // can't do anything with this path
  4119. //
  4120. SetLastError(ERROR_INVALID_DATA);
  4121. return NULL;
  4122. }
  4123. if(FilePart==NULL) {
  4124. Buffer[0] = TEXT('\0');
  4125. } else {
  4126. FilePart[0] = TEXT('\0');
  4127. }
  4128. return GetAnsiMuiSafeFilename(Buffer);
  4129. }
  4130. #ifdef UNICODE
  4131. PSTR
  4132. GetAnsiMuiSafeFilename(
  4133. IN PCTSTR FilePath
  4134. )
  4135. /*++
  4136. Routine Description:
  4137. Convert FilePath, which is a native file path to one that is safe to parse
  4138. by ansi API's in an MUI environment.
  4139. returned pointer is allocated and should be free'd
  4140. Arguments:
  4141. FilePath - path to convert
  4142. Return Value:
  4143. If successful, the return value is pointer to ANSI filepath (memory allocated by pSetupMalloc)
  4144. If unsuccessful, the return value is NULL and GetLastError returns error
  4145. --*/
  4146. {
  4147. TCHAR Buffer[MAX_PATH];
  4148. PTSTR p;
  4149. PSTR ansiPath;
  4150. DWORD actsz;
  4151. DWORD err;
  4152. actsz = GetShortPathName(FilePath,Buffer,MAX_PATH);
  4153. if(actsz >= MAX_PATH) {
  4154. //
  4155. // file path too big
  4156. //
  4157. SetLastError(ERROR_INVALID_DATA);
  4158. return NULL;
  4159. }
  4160. if(!actsz)
  4161. {
  4162. //
  4163. // some other error - resort back to current path name
  4164. //
  4165. lstrcpyn(Buffer,FilePath,MAX_PATH);
  4166. }
  4167. //
  4168. // convert to ansi now we've (if we can) converted to short path name
  4169. //
  4170. ansiPath = pSetupUnicodeToAnsi(Buffer);
  4171. if(!ansiPath) {
  4172. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  4173. return NULL;
  4174. }
  4175. return ansiPath;
  4176. }
  4177. #else
  4178. PSTR
  4179. GetAnsiMuiSafeFilename(
  4180. IN PCTSTR FilePath
  4181. )
  4182. /*++
  4183. Routine Description:
  4184. See above, this is almost a no-op in ANSI
  4185. Arguments:
  4186. FilePath - supplies a context for logging the verify
  4187. Return Value:
  4188. If successful, the return value is pointer to ANSI filepath (memory allocated by pSetupMalloc)
  4189. If unsuccessful, the return value is NULL and GetLastError returns error
  4190. --*/
  4191. {
  4192. PSTR res = DuplicateString(FilePath);
  4193. if(!res) {
  4194. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  4195. }
  4196. return res;
  4197. }
  4198. #endif
  4199. BOOL
  4200. pSetupAppendPath(
  4201. IN PCTSTR Path1,
  4202. IN PCTSTR Path2,
  4203. OUT PTSTR* Combined
  4204. )
  4205. /*++
  4206. Routine Description:
  4207. Call pSetupConcatenatePaths
  4208. dynamically modifying memory/pointer
  4209. Arguments:
  4210. Path1/Path2 - to concatenate
  4211. Combined - resultant path
  4212. Return Value:
  4213. TRUE if the full path fit in Target buffer. Otherwise the path
  4214. not created.
  4215. --*/
  4216. {
  4217. PTSTR FinalPath;
  4218. UINT Len;
  4219. if(!Path1 && !Path2) {
  4220. *Combined = NULL;
  4221. return TRUE;
  4222. }
  4223. if(!Path1) {
  4224. *Combined = DuplicateString(Path2);
  4225. return *Combined ? TRUE : FALSE;
  4226. }
  4227. if(!Path2) {
  4228. *Combined = DuplicateString(Path1);
  4229. return *Combined ? TRUE : FALSE;
  4230. }
  4231. Len = lstrlen(Path1)+lstrlen(Path2)+2; // slash and null
  4232. FinalPath = MyMalloc(Len*sizeof(TCHAR));
  4233. if(!FinalPath) {
  4234. *Combined = NULL;
  4235. return FALSE;
  4236. }
  4237. lstrcpy(FinalPath,Path1);
  4238. if(!pSetupConcatenatePaths(FinalPath,Path2,Len,NULL)) {
  4239. MyFree(FinalPath);
  4240. *Combined = NULL;
  4241. return FALSE;
  4242. }
  4243. *Combined = FinalPath;
  4244. return TRUE;
  4245. }
  4246. BOOL
  4247. pSetupApplyExtension(
  4248. IN PCTSTR Original,
  4249. IN PCTSTR Extension,
  4250. OUT PTSTR* NewName
  4251. )
  4252. /*++
  4253. Routine Description:
  4254. Apply Extension onto Original to obtain NewName
  4255. Arguments:
  4256. Original - original name with old extension
  4257. Extension - new extension to apply (with or without dot)
  4258. NewName - allocated buffer containing new filename
  4259. Return Value:
  4260. TRUE if the full path fit in Target buffer. Otherwise the path
  4261. not created.
  4262. --*/
  4263. {
  4264. PCTSTR End = Original+lstrlen(Original);
  4265. PCTSTR OldExt = End;
  4266. PTSTR NewString = NULL;
  4267. TCHAR c;
  4268. UINT len;
  4269. UINT sublen;
  4270. if(Extension && (Extension[0] == TEXT('.'))) {
  4271. Extension++;
  4272. }
  4273. while(End!= Original) {
  4274. End = CharPrev(Original,End);
  4275. if((*End == TEXT('/')) || (*End == TEXT('\\'))) {
  4276. break;
  4277. }
  4278. if(*End == TEXT('.')) {
  4279. OldExt = End;
  4280. break;
  4281. }
  4282. }
  4283. sublen = (UINT)(OldExt-Original);
  4284. len = sublen + lstrlen(Extension) + 2;
  4285. NewString = MyMalloc(len*sizeof(TCHAR));
  4286. if(!NewString) {
  4287. *NewName = NULL;
  4288. return FALSE;
  4289. }
  4290. memcpy(NewString,Original,(sublen)*sizeof(TCHAR));
  4291. NewString[sublen++] = Extension ? TEXT('.') : TEXT('\0');
  4292. if(Extension) {
  4293. lstrcpy(NewString+sublen,Extension);
  4294. }
  4295. *NewName = NewString;
  4296. return TRUE;
  4297. }
  4298. BOOL
  4299. ClassGuidInDrvSignPolicyList(
  4300. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  4301. IN CONST GUID *DeviceSetupClassGuid,
  4302. OUT PSP_ALTPLATFORM_INFO_V2 *ValidationPlatform OPTIONAL
  4303. )
  4304. /*++
  4305. Routine Description:
  4306. This routine determines whether the specified device setup class is among
  4307. the list of classes for which driver signing policy is applicable (i.e., as
  4308. indicated by the class's inclusion in the [DriverSigningClasses] section of
  4309. %windir%\Inf\certclas.inf). Additionally, if an non-native signature
  4310. validation lower-bound is applicable, a newly-allocated alternate platform
  4311. info structure is returned to the caller (if requested) to be used in
  4312. subsequent validation attempts associated with this class.
  4313. Arguments:
  4314. LogContext - Optionally, supplies the log context for any log entries that
  4315. might be generated by this routine.
  4316. DeviceSetupClassGuid - Supplies the address of the GUID we're attempting to
  4317. find in our driver signing policy list.
  4318. ValidationPlatform - Optionally, supplies the address of a (version 2)
  4319. altplatform info pointer (initialized to NULL) that is filled in upon
  4320. return with a newly-allocated structure specifying the appropriate
  4321. parameters to be passed to WinVerifyTrust when validating this INF.
  4322. These parameters are retrieved from certclas.inf for the relevant
  4323. device setup class GUID. If no special parameters are specified for
  4324. this class (or if the INF has no class at all), then this pointer is
  4325. not modified (i.e., left as NULL) causes us to use WinVerifyTrust's
  4326. default validation. Note that if we fail to allocate this structure
  4327. due to low-memory, the pointer will be left as NULL in that case as
  4328. well. This is OK, because this simply means we'll do default
  4329. validation in that case.
  4330. The caller is responsible for freeing the memory allocated for this
  4331. structure.
  4332. Return Value:
  4333. If the device setup class is in our driver signing policy list, the return
  4334. value is non-zero (TRUE). Otherwise, it is FALSE.
  4335. --*/
  4336. {
  4337. DWORD Err;
  4338. BOOL UseDrvSignPolicy;
  4339. INT i;
  4340. TCHAR CertClassInfPath[MAX_PATH];
  4341. HINF hCertClassInf = INVALID_HANDLE_VALUE;
  4342. INFCONTEXT InfContext;
  4343. UINT ErrorLine;
  4344. LONG LineCount;
  4345. PCTSTR GuidString;
  4346. //
  4347. // Default is to lump all device installs under driver signing policy
  4348. //
  4349. UseDrvSignPolicy = TRUE;
  4350. //
  4351. // If the caller supplied the ValidationPlatform parameter it must be
  4352. // pointing to a NULL pointer...
  4353. //
  4354. MYASSERT(!ValidationPlatform || !*ValidationPlatform);
  4355. if(LockDrvSignPolicyList(&GlobalDrvSignPolicyList)) {
  4356. if(GlobalDrvSignPolicyList.NumMembers == -1) {
  4357. //
  4358. // We've not yet retrieved the list from certclas.inf. First,
  4359. // verify the INF to make sure no one has tampered with it...
  4360. //
  4361. lstrcpyn(CertClassInfPath, InfDirectory,SIZECHARS(CertClassInfPath)-13);
  4362. lstrcat(CertClassInfPath, TEXT("\\certclas.inf"));
  4363. Err = _VerifyFile(LogContext,
  4364. NULL,
  4365. NULL,
  4366. NULL,
  4367. NULL,
  4368. 0,
  4369. pSetupGetFileTitle(CertClassInfPath),
  4370. CertClassInfPath,
  4371. NULL,
  4372. NULL,
  4373. FALSE,
  4374. NULL,
  4375. (VERIFY_FILE_IGNORE_SELFSIGNED | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4376. NULL,
  4377. NULL,
  4378. NULL,
  4379. NULL
  4380. );
  4381. if(Err == NO_ERROR) {
  4382. //
  4383. // Open up driver signing class list INF for use when examining
  4384. // the individual INFs in the LOADED_INF list below.
  4385. //
  4386. hCertClassInf = SetupOpenInfFile(CertClassInfPath,
  4387. NULL,
  4388. INF_STYLE_WIN4,
  4389. &ErrorLine
  4390. );
  4391. if(hCertClassInf == INVALID_HANDLE_VALUE) {
  4392. //
  4393. // This failure is highly unlikely to occur, since we just got
  4394. // through validating the INF.
  4395. //
  4396. Err = GetLastError();
  4397. WriteLogEntry(LogContext,
  4398. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  4399. MSG_LOG_CERTCLASS_LOAD_FAILED,
  4400. NULL,
  4401. CertClassInfPath,
  4402. ErrorLine
  4403. );
  4404. }
  4405. } else {
  4406. WriteLogEntry(LogContext,
  4407. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  4408. MSG_LOG_CERTCLASS_INVALID,
  4409. NULL,
  4410. CertClassInfPath
  4411. );
  4412. }
  4413. if(Err != NO_ERROR) {
  4414. //
  4415. // Somebody mucked with/deleted certclas.inf! (Or, much less
  4416. // likely, we encountered some other failure whilst trying to
  4417. // load the INF.) Since we don't know which classes are
  4418. // subject to driver signing policy, we assume they all are.
  4419. //
  4420. WriteLogError(LogContext,
  4421. SETUP_LOG_WARNING | SETUP_LOG_BUFFER,
  4422. Err
  4423. );
  4424. WriteLogEntry(LogContext,
  4425. SETUP_LOG_WARNING,
  4426. MSG_LOG_DRIVER_SIGNING_FOR_ALL_CLASSES,
  4427. NULL
  4428. );
  4429. //
  4430. // Set the NumMembers field to zero, so we'll know we
  4431. // previously attempted (and failed) to retrieve the list. We
  4432. // do this so we don't keep re-trying to get this list.
  4433. //
  4434. GlobalDrvSignPolicyList.NumMembers = 0;
  4435. } else {
  4436. //
  4437. // Certclas.inf validated, and we successfully opened it. Now
  4438. // retrieve the list contained therein.
  4439. //
  4440. LineCount = SetupGetLineCount(hCertClassInf,
  4441. pszDriverSigningClasses
  4442. );
  4443. if((LineCount > 0) &&
  4444. (NULL != (GlobalDrvSignPolicyList.Members = MyMalloc(LineCount * sizeof(DRVSIGN_CLASS_LIST_NODE))))) {
  4445. if(SetupFindFirstLine(hCertClassInf,
  4446. pszDriverSigningClasses,
  4447. NULL,
  4448. &InfContext)) {
  4449. i = 0;
  4450. do {
  4451. MYASSERT(i < LineCount);
  4452. //
  4453. // The format of a line in the [DriverSigningClasses]
  4454. // section is as follows:
  4455. //
  4456. // {GUID} [= FirstValidatedMajorVersion, FirstValidatedMinorVersion]
  4457. //
  4458. GuidString = pSetupGetField(&InfContext, 0);
  4459. if(GuidString &&
  4460. (NO_ERROR == pSetupGuidFromString(GuidString, &(GlobalDrvSignPolicyList.Members[i].DeviceSetupClassGuid)))) {
  4461. if(SetupGetIntField(&InfContext, 1, &(GlobalDrvSignPolicyList.Members[i].MajorVerLB)) &&
  4462. SetupGetIntField(&InfContext, 2, &(GlobalDrvSignPolicyList.Members[i].MinorVerLB))) {
  4463. //
  4464. // We successfully retrieved major/minor
  4465. // version info for validation lower-bound.
  4466. // Do a sanity-check on these.
  4467. //
  4468. if(GlobalDrvSignPolicyList.Members[i].MajorVerLB <= 0) {
  4469. GlobalDrvSignPolicyList.Members[i].MajorVerLB = -1;
  4470. GlobalDrvSignPolicyList.Members[i].MinorVerLB = -1;
  4471. }
  4472. } else {
  4473. //
  4474. // Set major/minor version info to -1 to
  4475. // indicate there's no validation platform
  4476. // override.
  4477. //
  4478. GlobalDrvSignPolicyList.Members[i].MajorVerLB = -1;
  4479. GlobalDrvSignPolicyList.Members[i].MinorVerLB = -1;
  4480. }
  4481. i++;
  4482. }
  4483. } while(SetupFindNextLine(&InfContext, &InfContext));
  4484. //
  4485. // Update NumMembers field in our list to indicate the
  4486. // number of class GUID entries we actually found.
  4487. //
  4488. GlobalDrvSignPolicyList.NumMembers = i;
  4489. }
  4490. }
  4491. SetupCloseInfFile(hCertClassInf);
  4492. }
  4493. }
  4494. //
  4495. // We now have a list. If the list is empty, this means we
  4496. // encountered some problem retrieving the list, thus all device
  4497. // classes should be subject to driver signing policy. Otherwise,
  4498. // try to find the caller-specified class in our list.
  4499. //
  4500. if(GlobalDrvSignPolicyList.NumMembers) {
  4501. //
  4502. // OK, we know we have a valid list--now default to non-driver
  4503. // signing policy unless our list search proves fruitful.
  4504. //
  4505. UseDrvSignPolicy = FALSE;
  4506. for(i = 0; i < GlobalDrvSignPolicyList.NumMembers; i++) {
  4507. if(!memcmp(DeviceSetupClassGuid,
  4508. &(GlobalDrvSignPolicyList.Members[i].DeviceSetupClassGuid),
  4509. sizeof(GUID))) {
  4510. //
  4511. // We found a match!
  4512. //
  4513. UseDrvSignPolicy = TRUE;
  4514. //
  4515. // Now, check to see if we have any validation platform
  4516. // override info...
  4517. //
  4518. if(ValidationPlatform &&
  4519. (GlobalDrvSignPolicyList.Members[i].MajorVerLB != -1)) {
  4520. MYASSERT(GlobalDrvSignPolicyList.Members[i].MinorVerLB != -1);
  4521. *ValidationPlatform = MyMalloc(sizeof(SP_ALTPLATFORM_INFO_V2));
  4522. //
  4523. // If the memory allocation fails, we just won't report
  4524. // the altplatform info, so the validation will be done
  4525. // based on the current OS version (instead of widening
  4526. // it up to allow a range of valid versions).
  4527. //
  4528. if(*ValidationPlatform) {
  4529. ZeroMemory(*ValidationPlatform, sizeof(SP_ALTPLATFORM_INFO_V2));
  4530. (*ValidationPlatform)->cbSize = sizeof(SP_ALTPLATFORM_INFO_V2);
  4531. (*ValidationPlatform)->Platform = VER_PLATFORM_WIN32_NT;
  4532. (*ValidationPlatform)->Flags = SP_ALTPLATFORM_FLAGS_VERSION_RANGE;
  4533. (*ValidationPlatform)->MajorVersion = VER_PRODUCTMAJORVERSION;
  4534. (*ValidationPlatform)->MinorVersion = VER_PRODUCTMINORVERSION;
  4535. (*ValidationPlatform)->ProcessorArchitecture =
  4536. #if defined(_AXP64_)
  4537. PROCESSOR_ARCHITECTURE_ALPHA64;
  4538. #elif defined(_ALPHA_)
  4539. PROCESSOR_ARCHITECTURE_ALPHA;
  4540. #elif defined(_MIPS_)
  4541. PROCESSOR_ARCHITECTURE_MIPS;
  4542. #elif defined(_PPC_)
  4543. PROCESSOR_ARCHITECTURE_PPC;
  4544. #elif defined(_X86_)
  4545. PROCESSOR_ARCHITECTURE_INTEL;
  4546. #elif defined(_IA64_)
  4547. PROCESSOR_ARCHITECTURE_IA64;
  4548. #elif defined(_AMD64_)
  4549. PROCESSOR_ARCHITECTURE_AMD64;
  4550. #else
  4551. #error "no target architecture"
  4552. #endif
  4553. (*ValidationPlatform)->FirstValidatedMajorVersion
  4554. = (DWORD)(GlobalDrvSignPolicyList.Members[i].MajorVerLB);
  4555. (*ValidationPlatform)->FirstValidatedMinorVersion
  4556. = (DWORD)(GlobalDrvSignPolicyList.Members[i].MinorVerLB);
  4557. }
  4558. }
  4559. //
  4560. // Since we've found a match, we can break out of the loop.
  4561. //
  4562. break;
  4563. }
  4564. }
  4565. }
  4566. UnlockDrvSignPolicyList(&GlobalDrvSignPolicyList);
  4567. }
  4568. return UseDrvSignPolicy;
  4569. }
  4570. BOOL
  4571. InitDrvSignPolicyList(
  4572. VOID
  4573. )
  4574. /*++
  4575. Routine Description:
  4576. This routine initializes the global "Driver Signing Policy" list that is
  4577. retrieved (on first use) from %windir%\Inf\certclas.inf.
  4578. Arguments:
  4579. None
  4580. Return Value:
  4581. If success, the return value is TRUE, otherwise, it is FALSE.
  4582. --*/
  4583. {
  4584. ZeroMemory(&GlobalDrvSignPolicyList, sizeof(DRVSIGN_POLICY_LIST));
  4585. GlobalDrvSignPolicyList.NumMembers = -1;
  4586. return InitializeSynchronizedAccess(&GlobalDrvSignPolicyList.Lock);
  4587. }
  4588. VOID
  4589. DestroyDrvSignPolicyList(
  4590. VOID
  4591. )
  4592. /*++
  4593. Routine Description:
  4594. This routine destroys the global "Driver Signing Policy" list that is
  4595. retrieved (on first use) from %windir%\Inf\certclas.inf.
  4596. Arguments:
  4597. None
  4598. Return Value:
  4599. None
  4600. --*/
  4601. {
  4602. if(LockDrvSignPolicyList(&GlobalDrvSignPolicyList)) {
  4603. if(GlobalDrvSignPolicyList.Members) {
  4604. MyFree(GlobalDrvSignPolicyList.Members);
  4605. }
  4606. DestroySynchronizedAccess(&GlobalDrvSignPolicyList.Lock);
  4607. }
  4608. }