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

805 lines
23 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: crobu.cpp
  7. //
  8. // Contents: CryptRetrieveObjectByUrl
  9. //
  10. // History: 23-Jul-97 kirtd Created
  11. // 01-Jan-02 philh Changed to internally use UNICODE Urls
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <global.hxx>
  15. #include <dbgdef.h>
  16. #ifndef INTERNET_MAX_PATH_LENGTH
  17. #define INTERNET_MAX_PATH_LENGTH 2048
  18. #endif
  19. // Initial commit size of the stack, in bytes. Estimate of 20K needed for
  20. // wininet.
  21. #define URL_WITH_TIMEOUT_THREAD_STACK_SIZE 0x5000
  22. //
  23. // CryptRetrieveObjectByUrl Entry
  24. //
  25. // Passed to the thread that does the real URL retrieval. The creator
  26. // thread waits for either the URL retrieval to complete or a timeout.
  27. //
  28. typedef struct _CROBU_ENTRY CROBU_ENTRY, *PCROBU_ENTRY;
  29. struct _CROBU_ENTRY {
  30. LPWSTR pwszUrl;
  31. LPCSTR pszObjectOid;
  32. DWORD dwRetrievalFlags;
  33. DWORD dwTimeout;
  34. LPVOID pvObject;
  35. CRYPT_RETRIEVE_AUX_INFO AuxInfo;
  36. FILETIME LastSyncTime;
  37. BOOL fResult;
  38. DWORD dwErr;
  39. HMODULE hModule;
  40. HANDLE hWaitEvent;
  41. DWORD dwState;
  42. PCROBU_ENTRY pNext;
  43. PCROBU_ENTRY pPrev;
  44. };
  45. #define CROBU_RUN_STATE 1
  46. #define CROBU_DONE_STATE 2
  47. #define CROBU_PENDING_STATE 3
  48. CRITICAL_SECTION CrobuCriticalSection;
  49. HMODULE hCrobuModule;
  50. // Linked list of pending URL retrievals
  51. PCROBU_ENTRY pCrobuPendingHead;
  52. VOID
  53. WINAPI
  54. InitializeCryptRetrieveObjectByUrl(
  55. HMODULE hModule
  56. )
  57. {
  58. Pki_InitializeCriticalSection(&CrobuCriticalSection);
  59. hCrobuModule = hModule;
  60. }
  61. VOID
  62. WINAPI
  63. DeleteCryptRetrieveObjectByUrl()
  64. {
  65. DeleteCriticalSection(&CrobuCriticalSection);
  66. }
  67. //
  68. // Local Functions (Forward Reference)
  69. //
  70. BOOL WINAPI IsPendingCryptRetrieveObjectByUrl (
  71. IN LPCWSTR pwszUrl
  72. );
  73. BOOL WINAPI CryptRetrieveObjectByUrlWithTimeout (
  74. IN LPCWSTR pwszUrl,
  75. IN LPCSTR pszObjectOid,
  76. IN DWORD dwRetrievalFlags,
  77. IN DWORD dwTimeout,
  78. OUT LPVOID* ppvObject,
  79. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  80. );
  81. void
  82. DebugPrintUrlRetrievalError(
  83. IN LPCWSTR pwszUrl,
  84. IN DWORD dwTimeout,
  85. IN DWORD dwErr
  86. );
  87. //+---------------------------------------------------------------------------
  88. //
  89. // Function: CryptRetrieveObjectByUrlA
  90. //
  91. // Synopsis: retrieve PKI object given an URL
  92. //
  93. //----------------------------------------------------------------------------
  94. BOOL WINAPI CryptRetrieveObjectByUrlA (
  95. IN LPCSTR pszUrl,
  96. IN LPCSTR pszObjectOid,
  97. IN DWORD dwRetrievalFlags,
  98. IN DWORD dwTimeout,
  99. OUT LPVOID* ppvObject,
  100. IN HCRYPTASYNC hAsyncRetrieve,
  101. IN PCRYPT_CREDENTIALS pCredentials,
  102. IN LPVOID pvVerify,
  103. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  104. )
  105. {
  106. WCHAR pwszUrl[INTERNET_MAX_PATH_LENGTH+1];
  107. if ( !MultiByteToWideChar(
  108. CP_ACP,
  109. 0,
  110. pszUrl,
  111. -1,
  112. pwszUrl,
  113. INTERNET_MAX_PATH_LENGTH+1
  114. ))
  115. {
  116. return( FALSE );
  117. }
  118. return( CryptRetrieveObjectByUrlW(
  119. pwszUrl,
  120. pszObjectOid,
  121. dwRetrievalFlags,
  122. dwTimeout,
  123. ppvObject,
  124. hAsyncRetrieve,
  125. pCredentials,
  126. pvVerify,
  127. pAuxInfo
  128. ) );
  129. }
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Function: CryptRetrieveObjectByUrlW
  133. //
  134. // Synopsis: retrieve PKI object given an URL
  135. //
  136. //----------------------------------------------------------------------------
  137. BOOL WINAPI CryptRetrieveObjectByUrlW (
  138. IN LPCWSTR pwszUrl,
  139. IN LPCSTR pszObjectOid,
  140. IN DWORD dwRetrievalFlags,
  141. IN DWORD dwTimeout,
  142. OUT LPVOID* ppvObject,
  143. IN HCRYPTASYNC hAsyncRetrieve,
  144. IN PCRYPT_CREDENTIALS pCredentials,
  145. IN LPVOID pvVerify,
  146. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  147. )
  148. {
  149. BOOL fResult;
  150. CObjectRetrievalManager* porm = NULL;
  151. // Remove any leading spaces
  152. while (L' ' == *pwszUrl)
  153. pwszUrl++;
  154. I_CryptNetDebugTracePrintfA(
  155. "CRYPTNET.DLL --> %s URL to retrieve: %S\n",
  156. 0 != (dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) ?
  157. "Cached" : "Wire", pwszUrl);
  158. // For a nonCache retrieval with timeout, do the retrieval in another
  159. // thread. wininet and winldap don't always honor the timeout value.
  160. //
  161. // Check for parameters not supported by doing in another thread.
  162. //
  163. // Also, check that a cancel callback hasn't been registered via
  164. // CryptInstallCancelRetrieval()
  165. if (0 != dwTimeout && !(dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) &&
  166. 0xFFFF >= (DWORD_PTR) pszObjectOid &&
  167. NULL == hAsyncRetrieve && NULL == pCredentials &&
  168. NULL == pvVerify &&
  169. NULL == I_CryptGetTls(hCryptNetCancelTls) )
  170. {
  171. if (IsPendingCryptRetrieveObjectByUrl( pwszUrl ))
  172. {
  173. I_CryptNetDebugErrorPrintfA(
  174. "CRYPTNET.DLL --> CryptRetrieveObjectByUrl, already pending for : %S\n",
  175. pwszUrl);
  176. SetLastError( (DWORD) ERROR_BAD_NET_RESP );
  177. return( FALSE );
  178. }
  179. else
  180. {
  181. return CryptRetrieveObjectByUrlWithTimeout (
  182. pwszUrl,
  183. pszObjectOid,
  184. dwRetrievalFlags,
  185. dwTimeout,
  186. ppvObject,
  187. pAuxInfo
  188. );
  189. }
  190. }
  191. porm = new CObjectRetrievalManager;
  192. if ( porm == NULL )
  193. {
  194. SetLastError( (DWORD) E_OUTOFMEMORY );
  195. return( FALSE );
  196. }
  197. fResult = porm->RetrieveObjectByUrl(
  198. pwszUrl,
  199. pszObjectOid,
  200. dwRetrievalFlags,
  201. dwTimeout,
  202. ppvObject,
  203. NULL,
  204. NULL,
  205. hAsyncRetrieve,
  206. pCredentials,
  207. pvVerify,
  208. pAuxInfo
  209. );
  210. porm->Release();
  211. if (!fResult)
  212. {
  213. DWORD dwLastErr = GetLastError();
  214. I_CryptNetDebugErrorPrintfA(
  215. "CRYPTNET.DLL --> %s URL to retrieve: %S, failed: %d (0x%x)\n",
  216. 0 != (dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) ?
  217. "Cached" : "Wire", pwszUrl, dwLastErr, dwLastErr);
  218. SetLastError(dwLastErr);
  219. }
  220. return( fResult );
  221. }
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Function: CryptCancelAsyncRetrieval
  225. //
  226. // Synopsis: cancel asynchronous object retrieval
  227. //
  228. //----------------------------------------------------------------------------
  229. BOOL WINAPI CryptCancelAsyncRetrieval (HCRYPTASYNC hAsyncRetrieval)
  230. {
  231. SetLastError( (DWORD) E_NOTIMPL );
  232. return( FALSE );
  233. }
  234. //+===========================================================================
  235. //
  236. // Functions supporting URL retrieval with timeout. The actual retrieval
  237. // is done in another, created thread.
  238. //
  239. //============================================================================
  240. //+---------------------------------------------------------------------------
  241. // Returns TRUE if the previously initiated URL retrieval hasn't completed.
  242. //----------------------------------------------------------------------------
  243. BOOL WINAPI IsPendingCryptRetrieveObjectByUrl (
  244. IN LPCWSTR pwszUrl
  245. )
  246. {
  247. BOOL fPending = FALSE;
  248. PCROBU_ENTRY pEntry;
  249. EnterCriticalSection(&CrobuCriticalSection);
  250. for (pEntry = pCrobuPendingHead; NULL != pEntry; pEntry = pEntry->pNext) {
  251. assert(CROBU_PENDING_STATE == pEntry->dwState);
  252. if (0 == wcscmp(pwszUrl, pEntry->pwszUrl)) {
  253. fPending = TRUE;
  254. break;
  255. }
  256. }
  257. LeaveCriticalSection(&CrobuCriticalSection);
  258. return fPending;
  259. }
  260. //+-------------------------------------------------------------------------
  261. // Duplicate the Dll library's handle
  262. //--------------------------------------------------------------------------
  263. static HMODULE DuplicateLibrary(
  264. IN HMODULE hDll
  265. )
  266. {
  267. if (hDll) {
  268. WCHAR wszModule[_MAX_PATH + 1];
  269. if (0 == GetModuleFileNameU(hDll, wszModule, _MAX_PATH))
  270. goto GetModuleFileNameError;
  271. wszModule[_MAX_PATH] = L'\0';
  272. if (NULL == (hDll = LoadLibraryExU(wszModule, NULL, 0)))
  273. goto LoadLibraryError;
  274. }
  275. CommonReturn:
  276. return hDll;
  277. ErrorReturn:
  278. hDll = NULL;
  279. goto CommonReturn;
  280. TRACE_ERROR(GetModuleFileNameError)
  281. TRACE_ERROR(LoadLibraryError)
  282. }
  283. //+---------------------------------------------------------------------------
  284. // Thread procedure that does the actual URL retrieval.
  285. //
  286. // Note, even if the creator thread times out, this thread will continue to
  287. // execute until the underlying URL retrieval returns.
  288. //----------------------------------------------------------------------------
  289. DWORD WINAPI CryptRetrieveObjectByUrlWithTimeoutThreadProc (
  290. LPVOID lpThreadParameter
  291. )
  292. {
  293. PCROBU_ENTRY pEntry = (PCROBU_ENTRY) lpThreadParameter;
  294. CObjectRetrievalManager* porm = NULL;
  295. HMODULE hModule;
  296. // Do the actual URL retrieval using the parameters passed to this
  297. // thread by the creator thread.
  298. porm = new CObjectRetrievalManager;
  299. if (NULL == porm ) {
  300. pEntry->dwErr = (DWORD) E_OUTOFMEMORY;
  301. pEntry->fResult = FALSE;
  302. } else {
  303. pEntry->fResult = porm->RetrieveObjectByUrl(
  304. pEntry->pwszUrl,
  305. pEntry->pszObjectOid,
  306. pEntry->dwRetrievalFlags,
  307. pEntry->dwTimeout,
  308. &pEntry->pvObject,
  309. NULL, // ppfnFreeObject
  310. NULL, // ppvFreeContext
  311. NULL, // hAsyncRetrieve
  312. NULL, // pCredentials
  313. NULL, // pvVerify
  314. &pEntry->AuxInfo
  315. );
  316. pEntry->dwErr = GetLastError();
  317. porm->Release();
  318. }
  319. EnterCriticalSection(&CrobuCriticalSection);
  320. // The creator thread incremented cryptnet's ref count to prevent us
  321. // from being unloaded until this thread exits.
  322. hModule = pEntry->hModule;
  323. pEntry->hModule = NULL;
  324. if (CROBU_RUN_STATE == pEntry->dwState) {
  325. // The creator thread didn't timeout. Wake it up and set the
  326. // state to indicate we completed.
  327. assert(pEntry->hWaitEvent);
  328. SetEvent(pEntry->hWaitEvent);
  329. pEntry->dwState = CROBU_DONE_STATE;
  330. LeaveCriticalSection(&CrobuCriticalSection);
  331. } else {
  332. // The creator thread timed out. We were added to the pending
  333. // list when it timed out.
  334. LPVOID pv = pEntry->pvObject;
  335. LPCSTR pOID = pEntry->pszObjectOid;
  336. assert(CROBU_PENDING_STATE == pEntry->dwState);
  337. assert(NULL == pEntry->hWaitEvent);
  338. // Remove from pending list
  339. if (pEntry->pNext)
  340. pEntry->pNext->pPrev = pEntry->pPrev;
  341. if (pEntry->pPrev)
  342. pEntry->pPrev->pNext = pEntry->pNext;
  343. else {
  344. assert(pCrobuPendingHead == pEntry);
  345. pCrobuPendingHead = pEntry->pNext;
  346. }
  347. LeaveCriticalSection(&CrobuCriticalSection);
  348. I_CryptNetDebugErrorPrintfA(
  349. "CRYPTNET.DLL --> CryptRetrieveObjectByUrl, pending completed for : %S\n",
  350. pEntry->pwszUrl);
  351. if (pv) {
  352. // Free the returned object
  353. if (NULL == pOID)
  354. CryptMemFree( pv );
  355. else if (pEntry->dwRetrievalFlags &
  356. CRYPT_RETRIEVE_MULTIPLE_OBJECTS)
  357. CertCloseStore((HCERTSTORE) pv, 0);
  358. else if (CONTEXT_OID_CERTIFICATE == pOID)
  359. CertFreeCertificateContext((PCCERT_CONTEXT) pv);
  360. else if (CONTEXT_OID_CTL == pOID)
  361. CertFreeCTLContext((PCCTL_CONTEXT) pv);
  362. else if (CONTEXT_OID_CRL == pOID)
  363. CertFreeCRLContext((PCCRL_CONTEXT) pv);
  364. else {
  365. assert(CONTEXT_OID_CAPI2_ANY == pOID ||
  366. CONTEXT_OID_PKCS7 == pOID);
  367. if (CONTEXT_OID_CAPI2_ANY == pOID ||
  368. CONTEXT_OID_PKCS7 == pOID)
  369. CertCloseStore((HCERTSTORE) pv, 0);
  370. }
  371. }
  372. // Finally free the entry
  373. PkiFree(pEntry);
  374. }
  375. if (hModule)
  376. FreeLibraryAndExitThread(hModule, 0);
  377. else
  378. ExitThread(0);
  379. }
  380. //+---------------------------------------------------------------------------
  381. // Creates another thread to do the URL retrieval. Waits for either the
  382. // URL retrieval to complete or the timeout. For a timeout, the URL retrieval
  383. // entry is added to a pending list and the URL retrieval is allowed to
  384. // complete. However, for a timeout, this procedure returns.
  385. //
  386. // This function guarantees the timeout value is honored.
  387. //----------------------------------------------------------------------------
  388. BOOL WINAPI CryptRetrieveObjectByUrlWithTimeout (
  389. IN LPCWSTR pwszUrl,
  390. IN LPCSTR pszObjectOid,
  391. IN DWORD dwRetrievalFlags,
  392. IN DWORD dwTimeout,
  393. OUT LPVOID* ppvObject,
  394. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  395. )
  396. {
  397. BOOL fResult;
  398. DWORD dwErr = 0;
  399. PCROBU_ENTRY pEntry = NULL;
  400. HANDLE hThread = NULL;
  401. HANDLE hToken = NULL;
  402. DWORD dwThreadId;
  403. DWORD cchUrl;
  404. // Allocate and initialize the entry to be passed to the created
  405. // thread for doing the URL retrieval.
  406. cchUrl = wcslen(pwszUrl) + 1;
  407. pEntry = (PCROBU_ENTRY) PkiZeroAlloc(sizeof(CROBU_ENTRY) +
  408. cchUrl * sizeof(WCHAR));
  409. if (NULL == pEntry)
  410. goto OutOfMemory;
  411. pEntry->pwszUrl = (LPWSTR) &pEntry[1];
  412. memcpy(pEntry->pwszUrl, pwszUrl, cchUrl * sizeof(WCHAR));
  413. assert(0xFFFF >= (DWORD_PTR) pszObjectOid);
  414. pEntry->pszObjectOid = pszObjectOid;
  415. pEntry->dwRetrievalFlags = dwRetrievalFlags;
  416. pEntry->dwTimeout = dwTimeout;
  417. // pEntry->pvObject
  418. pEntry->AuxInfo.cbSize = sizeof(pEntry->AuxInfo);
  419. pEntry->AuxInfo.pLastSyncTime = &pEntry->LastSyncTime;
  420. if ( pAuxInfo &&
  421. offsetof(CRYPT_RETRIEVE_AUX_INFO, dwMaxUrlRetrievalByteCount) <
  422. pAuxInfo->cbSize ) {
  423. pEntry->AuxInfo.dwMaxUrlRetrievalByteCount =
  424. pAuxInfo->dwMaxUrlRetrievalByteCount;
  425. }
  426. // else
  427. // pEntry->AuxInfo = zero'ed via PkiZeroAlloc
  428. // pEntry->LastSyncTime
  429. // pEntry->fResult
  430. // pEntry->dwErr
  431. // pEntry->hModule
  432. // pEntry->hWaitEvent
  433. // pEntry->dwState
  434. // pEntry->pNext
  435. // pEntry->pPrev
  436. if (NULL == (pEntry->hWaitEvent =
  437. CreateEvent(
  438. NULL, // lpsa
  439. FALSE, // fManualReset
  440. FALSE, // fInitialState
  441. NULL))) // lpszEventName
  442. goto CreateWaitEventError;
  443. // Inhibit cryptnet.dll from being unloaded until the created thread
  444. // exits.
  445. pEntry->hModule = DuplicateLibrary(hCrobuModule);
  446. pEntry->dwState = CROBU_RUN_STATE;
  447. // Create the thread to do the Url retrieval
  448. if (NULL == (hThread = CreateThread(
  449. NULL, // lpThreadAttributes
  450. URL_WITH_TIMEOUT_THREAD_STACK_SIZE,
  451. CryptRetrieveObjectByUrlWithTimeoutThreadProc,
  452. pEntry,
  453. CREATE_SUSPENDED,
  454. &dwThreadId
  455. )))
  456. goto CreateThreadError;
  457. // If we are impersonating, then, the created thread should also impersonate
  458. if (OpenThreadToken(
  459. GetCurrentThread(),
  460. TOKEN_QUERY | TOKEN_IMPERSONATE,
  461. TRUE,
  462. &hToken
  463. )) {
  464. // There isn't any security problem if the following fails.
  465. // If it fails will do the retrieval using the process's identity.
  466. if (!SetThreadToken(&hThread, hToken)) {
  467. DWORD dwLastErr = GetLastError();
  468. I_CryptNetDebugErrorPrintfA(
  469. "CRYPTNET.DLL --> SetThreadToken failed: %d (0x%x)\n",
  470. dwLastErr, dwLastErr);
  471. }
  472. CloseHandle(hToken);
  473. hToken = NULL;
  474. }
  475. ResumeThread(hThread);
  476. CloseHandle(hThread);
  477. hThread = NULL;
  478. // Wait for either the Url retrieval to complete or a timeout
  479. WaitForSingleObjectEx(
  480. pEntry->hWaitEvent,
  481. dwTimeout,
  482. FALSE // bAlertable
  483. );
  484. EnterCriticalSection(&CrobuCriticalSection);
  485. if (CROBU_DONE_STATE == pEntry->dwState) {
  486. // The URL retrieval completed in the created thread. Copy the
  487. // results from the entry block shared by this and the created
  488. // thread.
  489. fResult = pEntry->fResult;
  490. dwErr = pEntry->dwErr;
  491. *ppvObject = pEntry->pvObject;
  492. if ( pAuxInfo &&
  493. offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
  494. pAuxInfo->cbSize &&
  495. pAuxInfo->pLastSyncTime )
  496. {
  497. *pAuxInfo->pLastSyncTime = pEntry->LastSyncTime;
  498. }
  499. LeaveCriticalSection(&CrobuCriticalSection);
  500. } else {
  501. // The URL retrieval didn't complete in the created thread.
  502. // Add to the pending queue and return URL retrieval failure status.
  503. // Note, the created thread will be allowed to complete the initiated
  504. // retrieval.
  505. assert(CROBU_RUN_STATE == pEntry->dwState);
  506. CloseHandle(pEntry->hWaitEvent);
  507. pEntry->hWaitEvent = NULL;
  508. pEntry->dwState = CROBU_PENDING_STATE;
  509. // Add to the pending queue
  510. if (pCrobuPendingHead) {
  511. pCrobuPendingHead->pPrev = pEntry;
  512. pEntry->pNext = pCrobuPendingHead;
  513. }
  514. pCrobuPendingHead = pEntry;
  515. I_CryptNetDebugErrorPrintfA(
  516. "CRYPTNET.DLL --> CryptRetrieveObjectByUrl, %d timeout for : %S\n",
  517. pEntry->dwTimeout, pEntry->pwszUrl);
  518. pEntry = NULL;
  519. LeaveCriticalSection(&CrobuCriticalSection);
  520. goto RetrieveObjectByUrlTimeout;
  521. }
  522. CommonReturn:
  523. if (!fResult)
  524. DebugPrintUrlRetrievalError(
  525. pwszUrl,
  526. dwTimeout,
  527. dwErr
  528. );
  529. if (pEntry) {
  530. if (pEntry->hWaitEvent)
  531. CloseHandle(pEntry->hWaitEvent);
  532. if (pEntry->hModule)
  533. FreeLibrary(pEntry->hModule);
  534. PkiFree(pEntry);
  535. }
  536. SetLastError(dwErr);
  537. return fResult;
  538. ErrorReturn:
  539. dwErr = GetLastError();
  540. fResult = FALSE;
  541. goto CommonReturn;
  542. TRACE_ERROR(OutOfMemory)
  543. TRACE_ERROR(CreateWaitEventError)
  544. TRACE_ERROR(CreateThreadError)
  545. SET_ERROR(RetrieveObjectByUrlTimeout, ERROR_TIMEOUT)
  546. }
  547. DWORD
  548. GetCryptNetDebugFlags()
  549. {
  550. HKEY hKey = NULL;
  551. DWORD dwType = 0;
  552. DWORD dwValue = 0;
  553. DWORD cbValue = sizeof(dwValue);
  554. DWORD dwLastErr = GetLastError();
  555. if (ERROR_SUCCESS != RegOpenKeyExA(
  556. HKEY_LOCAL_MACHINE,
  557. "SYSTEM\\CurrentControlSet\\Services\\crypt32",
  558. 0, // dwReserved
  559. KEY_READ,
  560. &hKey
  561. ))
  562. goto ErrorReturn;
  563. if (ERROR_SUCCESS != RegQueryValueExA(
  564. hKey,
  565. "DebugFlags",
  566. NULL, // pdwReserved
  567. &dwType,
  568. (BYTE *) &dwValue,
  569. &cbValue
  570. ))
  571. goto ErrorReturn;
  572. if (dwType != REG_DWORD || cbValue != sizeof(dwValue))
  573. goto ErrorReturn;
  574. CommonReturn:
  575. if (NULL != hKey)
  576. RegCloseKey(hKey);
  577. SetLastError(dwLastErr);
  578. return dwValue;
  579. ErrorReturn:
  580. dwValue = 0;
  581. goto CommonReturn;
  582. }
  583. BOOL
  584. I_CryptNetIsDebugErrorPrintEnabled()
  585. {
  586. return 0 != (GetCryptNetDebugFlags() & 0x1);
  587. }
  588. BOOL
  589. I_CryptNetIsDebugTracePrintEnabled()
  590. {
  591. static BOOL fIKnow = FALSE;
  592. static BOOL fIsDebugTracePrintEnabled = FALSE;
  593. if (!fIKnow) {
  594. fIsDebugTracePrintEnabled =
  595. (0 != (GetCryptNetDebugFlags() & 0x2));
  596. fIKnow = TRUE;
  597. }
  598. return fIsDebugTracePrintEnabled;
  599. }
  600. void
  601. I_CryptNetDebugPrintfA(
  602. LPCSTR szFormat,
  603. ...
  604. )
  605. {
  606. char szBuffer[1024];
  607. va_list arglist;
  608. DWORD dwLastErr = GetLastError();
  609. _try
  610. {
  611. va_start(arglist, szFormat);
  612. _vsnprintf(szBuffer, sizeof(szBuffer), szFormat, arglist);
  613. szBuffer[sizeof(szBuffer) - 1] = '\0';
  614. va_end(arglist);
  615. OutputDebugStringA(szBuffer);
  616. } _except( EXCEPTION_EXECUTE_HANDLER) {
  617. }
  618. SetLastError(dwLastErr);
  619. }
  620. void
  621. I_CryptNetDebugErrorPrintfA(
  622. LPCSTR szFormat,
  623. ...
  624. )
  625. {
  626. if (!I_CryptNetIsDebugErrorPrintEnabled())
  627. return;
  628. else {
  629. char szBuffer[1024];
  630. va_list arglist;
  631. DWORD dwLastErr = GetLastError();
  632. _try
  633. {
  634. va_start(arglist, szFormat);
  635. _vsnprintf(szBuffer, sizeof(szBuffer), szFormat, arglist);
  636. szBuffer[sizeof(szBuffer) - 1] = '\0';
  637. va_end(arglist);
  638. OutputDebugStringA(szBuffer);
  639. } _except( EXCEPTION_EXECUTE_HANDLER) {
  640. }
  641. SetLastError(dwLastErr);
  642. }
  643. }
  644. void
  645. I_CryptNetDebugTracePrintfA(
  646. LPCSTR szFormat,
  647. ...
  648. )
  649. {
  650. if (!I_CryptNetIsDebugTracePrintEnabled())
  651. return;
  652. else {
  653. char szBuffer[1024];
  654. va_list arglist;
  655. DWORD dwLastErr = GetLastError();
  656. _try
  657. {
  658. va_start(arglist, szFormat);
  659. _vsnprintf(szBuffer, sizeof(szBuffer), szFormat, arglist);
  660. szBuffer[sizeof(szBuffer) - 1] = '\0';
  661. va_end(arglist);
  662. OutputDebugStringA(szBuffer);
  663. } _except( EXCEPTION_EXECUTE_HANDLER) {
  664. }
  665. SetLastError(dwLastErr);
  666. }
  667. }
  668. void
  669. DebugPrintUrlRetrievalError(
  670. IN LPCWSTR pwszUrl,
  671. IN DWORD dwTimeout,
  672. IN DWORD dwErr
  673. )
  674. {
  675. I_CryptNetDebugErrorPrintfA("CRYPTNET.DLL --> Url retrieval timeout: %d error: %d (0x%x) for::\n %S\n",
  676. dwTimeout, dwErr, dwErr, pwszUrl);
  677. }