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.

2617 lines
79 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: oidfunc.cpp
  8. //
  9. // Contents: Cryptographic Object ID (OID) Functions
  10. //
  11. // Functions: I_CryptOIDFuncDllMain
  12. // CryptInitOIDFunctionSet
  13. // CryptInstallOIDFunctionAddress
  14. //
  15. // CryptSetOIDFunctionValue
  16. // CryptGetOIDFunctionValue
  17. // CryptRegisterOIDFunction
  18. // CryptUnregisterOIDFunction
  19. // CryptRegisterDefaultOIDFunction
  20. // CryptUnregisterDefaultOIDFunction
  21. // CryptEnumOIDFunction
  22. //
  23. // CryptGetOIDFunctionAddress
  24. // CryptGetDefaultOIDDllList
  25. // CryptGetDefaultOIDFunctionAddress
  26. // CryptFreeOIDFunctionAddress
  27. //
  28. // Comments:
  29. // For the CryptGetOIDFunctionAddress we search the installed
  30. // const and str lists without
  31. // entering the critical section. The adds which are within
  32. // the critical section update the list pointers in the proper
  33. // order to allow list searching without locking.
  34. //
  35. // However, registry loads are done with OIDFunc
  36. // locked.
  37. //
  38. // HOLDING OID LOCK WHILE DOING A LoadLibrary() or FreeLibrary()
  39. // MAY LEAD TO DEADLOCK !!!
  40. //
  41. //
  42. // History: 07-Nov-96 philh created
  43. // 09-Aug-98 philh changed to NOT hold OID lock when calling
  44. // LoadLibrary() or FreeLibrary().
  45. //--------------------------------------------------------------------------
  46. #include "global.hxx"
  47. #include <dbgdef.h>
  48. #ifdef STATIC
  49. #undef STATIC
  50. #endif
  51. #define STATIC
  52. #define LEN_ALIGN(Len) ((Len + 7) & ~7)
  53. #define CONST_OID_STR_PREFIX_CHAR '#'
  54. //+-------------------------------------------------------------------------
  55. // OID Element Type Definitions
  56. //--------------------------------------------------------------------------
  57. #define CONST_OID_TYPE 1
  58. #define STR_OID_TYPE 2
  59. #define DLL_OID_TYPE 3
  60. //+-------------------------------------------------------------------------
  61. // Dll and Procedure Element Definitions
  62. //--------------------------------------------------------------------------
  63. typedef struct _DLL_ELEMENT DLL_ELEMENT, *PDLL_ELEMENT;
  64. typedef struct _DLL_PROC_ELEMENT DLL_PROC_ELEMENT, *PDLL_PROC_ELEMENT;
  65. struct _DLL_ELEMENT {
  66. DWORD dwOIDType;
  67. PDLL_ELEMENT pNext;
  68. LPWSTR pwszDll; // expanded
  69. HMODULE hDll;
  70. DWORD dwRefCnt;
  71. BOOL fLoaded;
  72. PDLL_PROC_ELEMENT pProcHead;
  73. LPFNCANUNLOADNOW pfnDllCanUnloadNow;
  74. // The following are used to defer the freeing of Dlls until after waiting
  75. // at least one FREE_DLL_TIMEOUT.
  76. DWORD dwFreeCnt; // 0, 1 or 2.
  77. PDLL_ELEMENT pFreeNext;
  78. PDLL_ELEMENT pFreePrev;
  79. };
  80. struct _DLL_PROC_ELEMENT {
  81. PDLL_PROC_ELEMENT pNext;
  82. PDLL_ELEMENT pDll;
  83. LPSTR pszName;
  84. void *pvAddr; // NULL'ed when Dll is unloaded
  85. };
  86. // Linked list of all the Dlls. All proc elements are on one of the Dll
  87. // element's proc list.
  88. static PDLL_ELEMENT pDllHead;
  89. // Linked list of Dlls waiting to be freed.
  90. static PDLL_ELEMENT pFreeDllHead;
  91. // Count of elements in the above list
  92. static DWORD dwFreeDllCnt;
  93. // When nonzero, a FreeDll callback has been registered.
  94. static LONG lFreeDll;
  95. static HANDLE hFreeDllRegWaitFor;
  96. static HMODULE hFreeDllLibModule;
  97. // Crypt32.dll hInst
  98. static HMODULE hOidInfoInst;
  99. // 15 seconds
  100. #define FREE_DLL_TIMEOUT 15000
  101. //+-------------------------------------------------------------------------
  102. // Installed OID Element Definitions
  103. //--------------------------------------------------------------------------
  104. typedef struct _CONST_OID_FUNC_ELEMENT
  105. CONST_OID_FUNC_ELEMENT, *PCONST_OID_FUNC_ELEMENT;
  106. struct _CONST_OID_FUNC_ELEMENT {
  107. DWORD dwOIDType;
  108. DWORD dwEncodingType;
  109. PCONST_OID_FUNC_ELEMENT pNext;
  110. DWORD_PTR dwLowOID;
  111. DWORD_PTR dwHighOID;
  112. HMODULE hDll;
  113. void **rgpvFuncAddr;
  114. };
  115. typedef struct _STR_OID_FUNC_ELEMENT
  116. STR_OID_FUNC_ELEMENT, *PSTR_OID_FUNC_ELEMENT;
  117. struct _STR_OID_FUNC_ELEMENT {
  118. DWORD dwOIDType;
  119. DWORD dwEncodingType;
  120. PSTR_OID_FUNC_ELEMENT pNext;
  121. LPSTR pszOID;
  122. HMODULE hDll;
  123. void *pvFuncAddr;
  124. };
  125. //+-------------------------------------------------------------------------
  126. // Registry OID Element Definitions
  127. //--------------------------------------------------------------------------
  128. typedef struct _REG_OID_FUNC_ELEMENT
  129. REG_OID_FUNC_ELEMENT, *PREG_OID_FUNC_ELEMENT;
  130. struct _REG_OID_FUNC_ELEMENT {
  131. DWORD dwEncodingType;
  132. PREG_OID_FUNC_ELEMENT pNext;
  133. union {
  134. DWORD_PTR dwOID;
  135. LPSTR pszOID;
  136. };
  137. PDLL_PROC_ELEMENT pDllProc;
  138. };
  139. //+-------------------------------------------------------------------------
  140. // Default registry DLL list Element Definitions
  141. //--------------------------------------------------------------------------
  142. typedef struct _DEFAULT_REG_ELEMENT
  143. DEFAULT_REG_ELEMENT, *PDEFAULT_REG_ELEMENT;
  144. struct _DEFAULT_REG_ELEMENT {
  145. DWORD dwEncodingType;
  146. PDEFAULT_REG_ELEMENT pNext;
  147. LPWSTR pwszDllList;
  148. DWORD cchDllList;
  149. DWORD cDll;
  150. LPWSTR *rgpwszDll;
  151. PDLL_PROC_ELEMENT *rgpDllProc;
  152. };
  153. //+-------------------------------------------------------------------------
  154. // Function Set Definition
  155. //--------------------------------------------------------------------------
  156. typedef struct _FUNC_SET FUNC_SET, *PFUNC_SET;
  157. struct _FUNC_SET {
  158. PFUNC_SET pNext;
  159. LPSTR pszFuncName;
  160. PCONST_OID_FUNC_ELEMENT pConstOIDFuncHead;
  161. PCONST_OID_FUNC_ELEMENT pConstOIDFuncTail;
  162. PSTR_OID_FUNC_ELEMENT pStrOIDFuncHead;
  163. PSTR_OID_FUNC_ELEMENT pStrOIDFuncTail;
  164. // Following are updated with OIDFunc locked
  165. BOOL fRegLoaded;
  166. PREG_OID_FUNC_ELEMENT pRegBeforeOIDFuncHead;
  167. PREG_OID_FUNC_ELEMENT pRegAfterOIDFuncHead;
  168. PDEFAULT_REG_ELEMENT pDefaultRegHead;
  169. };
  170. // Linked list of all the function sets
  171. static PFUNC_SET pFuncSetHead;
  172. // Used to protect the adding of function sets and elements to function sets.
  173. // Protects the pDllHead list and registry loads.
  174. static CRITICAL_SECTION OIDFuncCriticalSection;
  175. //+-------------------------------------------------------------------------
  176. // OIDFunc lock and unlock functions
  177. //--------------------------------------------------------------------------
  178. static inline void LockOIDFunc()
  179. {
  180. EnterCriticalSection(&OIDFuncCriticalSection);
  181. }
  182. static inline void UnlockOIDFunc()
  183. {
  184. LeaveCriticalSection(&OIDFuncCriticalSection);
  185. }
  186. //+-------------------------------------------------------------------------
  187. // First try to get the EncodingType from the lower 16 bits. If 0, get
  188. // from the upper 16 bits.
  189. //--------------------------------------------------------------------------
  190. static inline DWORD GetEncodingType(
  191. IN DWORD dwEncodingType
  192. )
  193. {
  194. return (dwEncodingType & CERT_ENCODING_TYPE_MASK) ?
  195. (dwEncodingType & CERT_ENCODING_TYPE_MASK) :
  196. (dwEncodingType & CMSG_ENCODING_TYPE_MASK) >> 16;
  197. }
  198. //+-------------------------------------------------------------------------
  199. // Duplicate the Dll library's handle
  200. //
  201. // Upon entry/exit OIDFunc must NOT be locked!!
  202. //--------------------------------------------------------------------------
  203. static HMODULE DuplicateLibrary(
  204. IN HMODULE hDll
  205. )
  206. {
  207. if (hDll) {
  208. WCHAR wszModule[_MAX_PATH + 1];
  209. if (0 == GetModuleFileNameU(hDll, wszModule, _MAX_PATH))
  210. goto GetModuleFileNameError;
  211. wszModule[_MAX_PATH] = L'\0';
  212. if (NULL == (hDll = LoadLibraryExU(wszModule, NULL, 0)))
  213. goto LoadLibraryError;
  214. }
  215. CommonReturn:
  216. return hDll;
  217. ErrorReturn:
  218. hDll = NULL;
  219. goto CommonReturn;
  220. TRACE_ERROR(GetModuleFileNameError)
  221. TRACE_ERROR(LoadLibraryError)
  222. }
  223. //+-------------------------------------------------------------------------
  224. // Add one or more functions with a constant OID. The constant OIDs are
  225. // monotonically increasing.
  226. //
  227. // Upon entry, pFuncSet hasn't been added to the searched pFuncSetHead list.
  228. //
  229. // Upon entry/exit OIDFunc must NOT be locked!!
  230. //--------------------------------------------------------------------------
  231. STATIC BOOL AddConstOIDFunc(
  232. IN HMODULE hDll,
  233. IN DWORD dwEncodingType,
  234. IN OUT PFUNC_SET pFuncSet,
  235. IN DWORD cFuncEntry,
  236. IN const CRYPT_OID_FUNC_ENTRY rgFuncEntry[]
  237. )
  238. {
  239. PCONST_OID_FUNC_ELEMENT pEle;
  240. DWORD cbEle;
  241. void **ppvFuncAddr;
  242. cbEle = sizeof(CONST_OID_FUNC_ELEMENT) + cFuncEntry * sizeof(void *);
  243. if (NULL == (pEle = (PCONST_OID_FUNC_ELEMENT) PkiZeroAlloc(cbEle)))
  244. return FALSE;
  245. pEle->dwOIDType = CONST_OID_TYPE;
  246. pEle->dwEncodingType = dwEncodingType;
  247. pEle->pNext = NULL;
  248. pEle->dwLowOID = (DWORD_PTR) rgFuncEntry[0].pszOID;
  249. pEle->dwHighOID = pEle->dwLowOID + cFuncEntry - 1;
  250. pEle->hDll = DuplicateLibrary(hDll);
  251. ppvFuncAddr =
  252. (void **) (((BYTE *) pEle) + sizeof(CONST_OID_FUNC_ELEMENT));
  253. pEle->rgpvFuncAddr = ppvFuncAddr;
  254. for (DWORD i = 0; i < cFuncEntry; i++, ppvFuncAddr++)
  255. *ppvFuncAddr = rgFuncEntry[i].pvFuncAddr;
  256. if (pFuncSet->pConstOIDFuncTail)
  257. pFuncSet->pConstOIDFuncTail->pNext = pEle;
  258. else
  259. pFuncSet->pConstOIDFuncHead = pEle;
  260. pFuncSet->pConstOIDFuncTail = pEle;
  261. return TRUE;
  262. }
  263. //+-------------------------------------------------------------------------
  264. // Add single function with a string OID.
  265. //
  266. // Upon entry, pFuncSet hasn't been added to the searched pFuncSetHead list.
  267. //
  268. // Upon entry/exit OIDFunc must NOT be locked!!
  269. //--------------------------------------------------------------------------
  270. STATIC BOOL AddStrOIDFunc(
  271. IN HMODULE hDll,
  272. IN DWORD dwEncodingType,
  273. IN OUT PFUNC_SET pFuncSet,
  274. IN const CRYPT_OID_FUNC_ENTRY *pFuncEntry
  275. )
  276. {
  277. PSTR_OID_FUNC_ELEMENT pEle;
  278. DWORD cbEle;
  279. DWORD cchOID;
  280. LPSTR psz;
  281. cchOID = strlen(pFuncEntry->pszOID) + 1;
  282. cbEle = sizeof(STR_OID_FUNC_ELEMENT) + cchOID;
  283. if (NULL == (pEle = (PSTR_OID_FUNC_ELEMENT) PkiZeroAlloc(cbEle)))
  284. return FALSE;
  285. pEle->dwOIDType = STR_OID_TYPE;
  286. pEle->dwEncodingType = dwEncodingType;
  287. pEle->pNext = NULL;
  288. psz = (LPSTR) (((BYTE *) pEle) + sizeof(STR_OID_FUNC_ELEMENT));
  289. pEle->pszOID = psz;
  290. memcpy(psz, pFuncEntry->pszOID, cchOID);
  291. pEle->hDll = DuplicateLibrary(hDll);
  292. pEle->pvFuncAddr = pFuncEntry->pvFuncAddr;
  293. if (pFuncSet->pStrOIDFuncTail)
  294. pFuncSet->pStrOIDFuncTail->pNext = pEle;
  295. else
  296. pFuncSet->pStrOIDFuncHead = pEle;
  297. pFuncSet->pStrOIDFuncTail = pEle;
  298. return TRUE;
  299. }
  300. //+-------------------------------------------------------------------------
  301. // Free the constant or string function elements
  302. //
  303. // Upon entry/exit OIDFunc must NOT be locked!!
  304. //--------------------------------------------------------------------------
  305. STATIC void FreeFuncSetConstAndStrElements(
  306. IN OUT PFUNC_SET pFuncSet
  307. )
  308. {
  309. PCONST_OID_FUNC_ELEMENT pConstEle;
  310. PSTR_OID_FUNC_ELEMENT pStrEle;
  311. pConstEle = pFuncSet->pConstOIDFuncHead;
  312. while (pConstEle) {
  313. PCONST_OID_FUNC_ELEMENT pNextEle = pConstEle->pNext;
  314. if (pConstEle->hDll)
  315. FreeLibrary(pConstEle->hDll);
  316. PkiFree(pConstEle);
  317. pConstEle = pNextEle;
  318. }
  319. pStrEle = pFuncSet->pStrOIDFuncHead;
  320. while (pStrEle) {
  321. PSTR_OID_FUNC_ELEMENT pNextEle = pStrEle->pNext;
  322. if (pStrEle->hDll)
  323. FreeLibrary(pStrEle->hDll);
  324. PkiFree(pStrEle);
  325. pStrEle = pNextEle;
  326. }
  327. }
  328. //+-------------------------------------------------------------------------
  329. // Free the function set and its elements
  330. //
  331. // Upon entry/exit OIDFunc must NOT be locked!!
  332. //--------------------------------------------------------------------------
  333. STATIC void FreeFuncSet(
  334. IN OUT PFUNC_SET pFuncSet
  335. )
  336. {
  337. PREG_OID_FUNC_ELEMENT pRegEle;
  338. PDEFAULT_REG_ELEMENT pDefaultReg;
  339. FreeFuncSetConstAndStrElements(pFuncSet);
  340. pRegEle = pFuncSet->pRegBeforeOIDFuncHead;
  341. while (pRegEle) {
  342. PREG_OID_FUNC_ELEMENT pNextEle = pRegEle->pNext;
  343. PkiFree(pRegEle);
  344. pRegEle = pNextEle;
  345. }
  346. pRegEle = pFuncSet->pRegAfterOIDFuncHead;
  347. while (pRegEle) {
  348. PREG_OID_FUNC_ELEMENT pNextEle = pRegEle->pNext;
  349. PkiFree(pRegEle);
  350. pRegEle = pNextEle;
  351. }
  352. pDefaultReg = pFuncSet->pDefaultRegHead;
  353. while (pDefaultReg) {
  354. PDEFAULT_REG_ELEMENT pNext = pDefaultReg->pNext;
  355. PkiFree(pDefaultReg);
  356. pDefaultReg = pNext;
  357. }
  358. PkiFree(pFuncSet);
  359. }
  360. //+-------------------------------------------------------------------------
  361. // Free the Dll and its proc elements
  362. //
  363. // Upon entry/exit OIDFunc must NOT be locked!!
  364. //--------------------------------------------------------------------------
  365. STATIC void FreeDll(
  366. IN OUT PDLL_ELEMENT pDll
  367. )
  368. {
  369. PDLL_PROC_ELEMENT pProcEle;
  370. pProcEle = pDll->pProcHead;
  371. while (pProcEle) {
  372. PDLL_PROC_ELEMENT pNextEle = pProcEle->pNext;
  373. PkiFree(pProcEle);
  374. pProcEle = pNextEle;
  375. }
  376. if (pDll->fLoaded) {
  377. assert(pDll->hDll);
  378. FreeLibrary(pDll->hDll);
  379. }
  380. PkiFree(pDll);
  381. }
  382. //+-------------------------------------------------------------------------
  383. // Dll initialization
  384. //--------------------------------------------------------------------------
  385. BOOL
  386. WINAPI
  387. I_CryptOIDFuncDllMain(
  388. HMODULE hInst,
  389. ULONG ulReason,
  390. LPVOID lpReserved)
  391. {
  392. BOOL fRet = TRUE;
  393. switch (ulReason) {
  394. case DLL_PROCESS_ATTACH:
  395. fRet = Pki_InitializeCriticalSection(&OIDFuncCriticalSection);
  396. hOidInfoInst = hInst;
  397. break;
  398. case DLL_PROCESS_DETACH:
  399. // Do interlock to guard against a potential race condition with
  400. // the RegWaitFor callback thread. We doing this without doing
  401. // a LockOIDFunc().
  402. if (InterlockedExchange(&lFreeDll, 0)) {
  403. assert(hFreeDllRegWaitFor);
  404. hFreeDllLibModule = NULL;
  405. ILS_UnregisterWait(hFreeDllRegWaitFor);
  406. hFreeDllRegWaitFor = NULL;
  407. }
  408. while (pFuncSetHead) {
  409. PFUNC_SET pFuncSet = pFuncSetHead;
  410. pFuncSetHead = pFuncSet->pNext;
  411. FreeFuncSet(pFuncSet);
  412. }
  413. while (pDllHead) {
  414. PDLL_ELEMENT pDll = pDllHead;
  415. pDllHead = pDll->pNext;
  416. FreeDll(pDll);
  417. }
  418. DeleteCriticalSection(&OIDFuncCriticalSection);
  419. break;
  420. case DLL_THREAD_DETACH:
  421. default:
  422. break;
  423. }
  424. return fRet;
  425. }
  426. //+-------------------------------------------------------------------------
  427. // Initialize and return handle to the OID function set identified by its
  428. // function name.
  429. //
  430. // If the set already exists, a handle to the existing set is returned.
  431. //--------------------------------------------------------------------------
  432. HCRYPTOIDFUNCSET
  433. WINAPI
  434. CryptInitOIDFunctionSet(
  435. IN LPCSTR pszFuncName,
  436. IN DWORD dwFlags
  437. )
  438. {
  439. PFUNC_SET pFuncSet;
  440. LockOIDFunc();
  441. // See if the set already exists
  442. for (pFuncSet = pFuncSetHead; pFuncSet; pFuncSet = pFuncSet->pNext) {
  443. if (0 == strcmp(pszFuncName, pFuncSet->pszFuncName))
  444. break;
  445. }
  446. if (NULL == pFuncSet) {
  447. // Allocate and initialize a new set
  448. DWORD cchFuncName = strlen(pszFuncName) + 1;
  449. if (pFuncSet = (PFUNC_SET) PkiZeroAlloc(
  450. sizeof(FUNC_SET) + cchFuncName)) {
  451. LPSTR psz = (LPSTR) (((BYTE *) pFuncSet) + sizeof(FUNC_SET));
  452. pFuncSet->pszFuncName = psz;
  453. memcpy(psz, pszFuncName, cchFuncName);
  454. pFuncSet->pNext = pFuncSetHead;
  455. pFuncSetHead = pFuncSet;
  456. }
  457. }
  458. UnlockOIDFunc();
  459. return (HCRYPTOIDFUNCSET) pFuncSet;
  460. }
  461. //+-------------------------------------------------------------------------
  462. // Install a set of callable OID function addresses.
  463. //
  464. // By default the functions are installed at end of the list.
  465. // Set CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG to install at beginning of list.
  466. //
  467. // hModule should be updated with the hModule passed to DllMain to prevent
  468. // the Dll containing the function addresses from being unloaded by
  469. // CryptGetOIDFuncAddress/CryptFreeOIDFunctionAddress. This would be the
  470. // case when the Dll has also regsvr32'ed OID functions via
  471. // CryptRegisterOIDFunction.
  472. //
  473. // DEFAULT functions are installed by setting rgFuncEntry[].pszOID =
  474. // CRYPT_DEFAULT_OID.
  475. //--------------------------------------------------------------------------
  476. BOOL
  477. WINAPI
  478. CryptInstallOIDFunctionAddress(
  479. IN HMODULE hModule, // hModule passed to DllMain
  480. IN DWORD dwEncodingType,
  481. IN LPCSTR pszFuncName,
  482. IN DWORD cFuncEntry,
  483. IN const CRYPT_OID_FUNC_ENTRY rgFuncEntry[],
  484. IN DWORD dwFlags
  485. )
  486. {
  487. BOOL fResult;
  488. PFUNC_SET pFuncSet;
  489. FUNC_SET AddFuncSet;
  490. memset(&AddFuncSet, 0, sizeof(AddFuncSet));
  491. int ConstFirst = -1;
  492. int ConstLast = 0;
  493. DWORD_PTR dwOID;
  494. DWORD_PTR dwLastOID = 0;
  495. DWORD i;
  496. dwEncodingType = GetEncodingType(dwEncodingType);
  497. if (NULL == (pFuncSet = (PFUNC_SET) CryptInitOIDFunctionSet(
  498. pszFuncName, 0)))
  499. return FALSE;
  500. // Don't need to hold lock while updating local copy of AddFuncSet.
  501. for (i = 0; i < cFuncEntry; i++) {
  502. if (0xFFFF >= (dwOID = (DWORD_PTR) rgFuncEntry[i].pszOID)) {
  503. if (ConstFirst < 0)
  504. ConstFirst = i;
  505. else if (dwOID != dwLastOID + 1) {
  506. if (!AddConstOIDFunc(
  507. hModule,
  508. dwEncodingType,
  509. &AddFuncSet,
  510. ConstLast - ConstFirst + 1,
  511. &rgFuncEntry[ConstFirst]
  512. )) goto AddConstOIDFuncError;
  513. ConstFirst = i;
  514. }
  515. ConstLast = i;
  516. dwLastOID = dwOID;
  517. } else {
  518. if (ConstFirst >= 0) {
  519. if (!AddConstOIDFunc(
  520. hModule,
  521. dwEncodingType,
  522. &AddFuncSet,
  523. ConstLast - ConstFirst + 1,
  524. &rgFuncEntry[ConstFirst]
  525. )) goto AddConstOIDFuncError;
  526. ConstFirst = -1;
  527. }
  528. if (!AddStrOIDFunc(
  529. hModule,
  530. dwEncodingType,
  531. &AddFuncSet,
  532. &rgFuncEntry[i]
  533. )) goto AddStrOIDFuncError;
  534. }
  535. }
  536. if (ConstFirst >= 0) {
  537. if (!AddConstOIDFunc(
  538. hModule,
  539. dwEncodingType,
  540. &AddFuncSet,
  541. ConstLast - ConstFirst + 1,
  542. &rgFuncEntry[ConstFirst]
  543. )) goto AddConstOIDFuncError;
  544. }
  545. // NOTE:::
  546. //
  547. // Since the get function accesses the lists without entering the critical
  548. // section, the following pointers must be updated in the correct
  549. // order. Note, Get doesn't access the tail.
  550. LockOIDFunc();
  551. if (AddFuncSet.pConstOIDFuncHead) {
  552. if (NULL == pFuncSet->pConstOIDFuncHead) {
  553. pFuncSet->pConstOIDFuncHead = AddFuncSet.pConstOIDFuncHead;
  554. pFuncSet->pConstOIDFuncTail = AddFuncSet.pConstOIDFuncTail;
  555. } else if (dwFlags & CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG) {
  556. AddFuncSet.pConstOIDFuncTail->pNext = pFuncSet->pConstOIDFuncHead;
  557. pFuncSet->pConstOIDFuncHead = AddFuncSet.pConstOIDFuncHead;
  558. } else {
  559. pFuncSet->pConstOIDFuncTail->pNext = AddFuncSet.pConstOIDFuncHead;
  560. pFuncSet->pConstOIDFuncTail = AddFuncSet.pConstOIDFuncTail;
  561. }
  562. }
  563. if (AddFuncSet.pStrOIDFuncHead) {
  564. if (NULL == pFuncSet->pStrOIDFuncHead) {
  565. pFuncSet->pStrOIDFuncHead = AddFuncSet.pStrOIDFuncHead;
  566. pFuncSet->pStrOIDFuncTail = AddFuncSet.pStrOIDFuncTail;
  567. } else if (dwFlags & CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG) {
  568. AddFuncSet.pStrOIDFuncTail->pNext = pFuncSet->pStrOIDFuncHead;
  569. pFuncSet->pStrOIDFuncHead = AddFuncSet.pStrOIDFuncHead;
  570. } else {
  571. pFuncSet->pStrOIDFuncTail->pNext = AddFuncSet.pStrOIDFuncHead;
  572. pFuncSet->pStrOIDFuncTail = AddFuncSet.pStrOIDFuncTail;
  573. }
  574. }
  575. UnlockOIDFunc();
  576. fResult = TRUE;
  577. CommonReturn:
  578. return fResult;
  579. ErrorReturn:
  580. fResult = FALSE;
  581. FreeFuncSetConstAndStrElements(&AddFuncSet);
  582. goto CommonReturn;
  583. TRACE_ERROR(AddConstOIDFuncError)
  584. TRACE_ERROR(AddStrOIDFuncError)
  585. }
  586. STATIC LPSTR EncodingTypeToRegName(
  587. IN DWORD dwEncodingType
  588. )
  589. {
  590. LPSTR pszRegName;
  591. DWORD cchRegName;
  592. char szEncodingTypeValue[33];
  593. dwEncodingType = GetEncodingType(dwEncodingType);
  594. _ltoa(dwEncodingType, szEncodingTypeValue, 10);
  595. cchRegName = strlen(CRYPT_OID_REG_ENCODING_TYPE_PREFIX) +
  596. strlen(szEncodingTypeValue) +
  597. 1;
  598. if (pszRegName = (LPSTR) PkiNonzeroAlloc(cchRegName)) {
  599. strcpy(pszRegName, CRYPT_OID_REG_ENCODING_TYPE_PREFIX);
  600. strcat(pszRegName, szEncodingTypeValue);
  601. }
  602. return pszRegName;
  603. }
  604. // Returns FALSE for an invalid EncodingType reg name
  605. STATIC BOOL RegNameToEncodingType(
  606. IN LPCSTR pszRegEncodingType,
  607. OUT DWORD *pdwEncodingType
  608. )
  609. {
  610. BOOL fResult = FALSE;
  611. DWORD dwEncodingType = 0;
  612. const DWORD cchPrefix = strlen(CRYPT_OID_REG_ENCODING_TYPE_PREFIX);
  613. if (pszRegEncodingType && (DWORD) strlen(pszRegEncodingType) >= cchPrefix &&
  614. 2 == CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
  615. pszRegEncodingType, cchPrefix,
  616. CRYPT_OID_REG_ENCODING_TYPE_PREFIX, cchPrefix)) {
  617. long lEncodingType;
  618. lEncodingType = atol(pszRegEncodingType + cchPrefix);
  619. if (lEncodingType >= 0 && lEncodingType <= 0xFFFF) {
  620. dwEncodingType = (DWORD) lEncodingType;
  621. fResult = TRUE;
  622. }
  623. }
  624. *pdwEncodingType = dwEncodingType;
  625. return fResult;
  626. }
  627. STATIC LPSTR FormatOIDFuncRegName(
  628. IN DWORD dwEncodingType,
  629. IN LPCSTR pszFuncName,
  630. IN LPCSTR pszOID
  631. )
  632. {
  633. LPSTR pszRegEncodingType;
  634. LPSTR pszRegName;
  635. DWORD cchRegName;
  636. char szOID[34];
  637. if (pszOID == NULL) {
  638. SetLastError((DWORD) E_INVALIDARG);
  639. return NULL;
  640. }
  641. if (NULL == (pszRegEncodingType = EncodingTypeToRegName(dwEncodingType)))
  642. return NULL;
  643. if ((DWORD_PTR) pszOID <= 0xFFFF) {
  644. szOID[0] = CONST_OID_STR_PREFIX_CHAR;
  645. _ltoa((long) ((DWORD_PTR)pszOID), szOID + 1, 10);
  646. pszOID = szOID;
  647. }
  648. cchRegName = strlen(CRYPT_OID_REGPATH "\\") +
  649. strlen(pszRegEncodingType) + 1 +
  650. strlen(pszFuncName) + 1 +
  651. strlen(pszOID) +
  652. 1;
  653. if (pszRegName = (LPSTR) PkiNonzeroAlloc(cchRegName)) {
  654. strcpy(pszRegName, CRYPT_OID_REGPATH "\\");
  655. strcat(pszRegName, pszRegEncodingType);
  656. strcat(pszRegName, "\\");
  657. strcat(pszRegName, pszFuncName);
  658. strcat(pszRegName, "\\");
  659. strcat(pszRegName, pszOID);
  660. }
  661. PkiFree(pszRegEncodingType);
  662. return pszRegName;
  663. }
  664. //+-------------------------------------------------------------------------
  665. // Set the value for the specified encoding type, function name, OID and
  666. // value name.
  667. //
  668. // See RegSetValueEx for the possible value types.
  669. //
  670. // String types are UNICODE.
  671. //
  672. // If pbValueData == NULL and cbValueData == 0, deletes the value.
  673. //--------------------------------------------------------------------------
  674. BOOL
  675. WINAPI
  676. CryptSetOIDFunctionValue(
  677. IN DWORD dwEncodingType,
  678. IN LPCSTR pszFuncName,
  679. IN LPCSTR pszOID,
  680. IN LPCWSTR pwszValueName,
  681. IN DWORD dwValueType,
  682. IN const BYTE *pbValueData,
  683. IN DWORD cbValueData
  684. )
  685. {
  686. BOOL fResult;
  687. LONG lStatus;
  688. LPSTR pszRegName = NULL;
  689. HKEY hKey = NULL;
  690. DWORD dwDisposition;
  691. if (NULL == (pszRegName = FormatOIDFuncRegName(
  692. dwEncodingType, pszFuncName, pszOID)))
  693. goto FormatRegNameError;
  694. if (ERROR_SUCCESS != (lStatus = RegCreateKeyExA(
  695. HKEY_LOCAL_MACHINE,
  696. pszRegName,
  697. 0, // dwReserved
  698. NULL, // lpClass
  699. REG_OPTION_NON_VOLATILE,
  700. KEY_WRITE,
  701. NULL, // lpSecurityAttributes
  702. &hKey,
  703. &dwDisposition)))
  704. goto RegCreateKeyError;
  705. if (NULL == pbValueData && 0 == cbValueData) {
  706. if (ERROR_SUCCESS != (lStatus = RegDeleteValueU(
  707. hKey,
  708. pwszValueName)))
  709. goto RegDeleteValueError;
  710. } else {
  711. if (ERROR_SUCCESS != (lStatus = RegSetValueExU(
  712. hKey,
  713. pwszValueName,
  714. 0, // dwReserved
  715. dwValueType,
  716. pbValueData,
  717. cbValueData)))
  718. goto RegSetValueError;
  719. }
  720. fResult = TRUE;
  721. CommonReturn:
  722. if (pszRegName)
  723. PkiFree(pszRegName);
  724. if (hKey)
  725. RegCloseKey(hKey);
  726. return fResult;
  727. ErrorReturn:
  728. fResult = FALSE;
  729. goto CommonReturn;
  730. TRACE_ERROR(FormatRegNameError)
  731. SET_ERROR_VAR(RegCreateKeyError, lStatus)
  732. SET_ERROR_VAR(RegDeleteValueError, lStatus)
  733. SET_ERROR_VAR(RegSetValueError, lStatus)
  734. }
  735. //+-------------------------------------------------------------------------
  736. // Get the value for the specified encoding type, function name, OID and
  737. // value name.
  738. //
  739. // See RegEnumValue for the possible value types.
  740. //
  741. // String types are UNICODE.
  742. //--------------------------------------------------------------------------
  743. BOOL
  744. WINAPI
  745. CryptGetOIDFunctionValue(
  746. IN DWORD dwEncodingType,
  747. IN LPCSTR pszFuncName,
  748. IN LPCSTR pszOID,
  749. IN LPCWSTR pwszValueName,
  750. OUT DWORD *pdwValueType,
  751. OUT BYTE *pbValueData,
  752. IN OUT DWORD *pcbValueData
  753. )
  754. {
  755. BOOL fResult;
  756. LONG lStatus;
  757. LPSTR pszRegName = NULL;
  758. HKEY hKey = NULL;
  759. if (NULL == (pszRegName = FormatOIDFuncRegName(
  760. dwEncodingType, pszFuncName, pszOID)))
  761. goto FormatRegNameError;
  762. if (ERROR_SUCCESS != (lStatus = RegOpenKeyExA(
  763. HKEY_LOCAL_MACHINE,
  764. pszRegName,
  765. 0, // dwReserved
  766. KEY_READ,
  767. &hKey))) {
  768. if (ERROR_FILE_NOT_FOUND == lStatus) {
  769. // Inhibit error tracing
  770. SetLastError((DWORD) lStatus);
  771. goto ErrorReturn;
  772. }
  773. goto RegOpenKeyError;
  774. }
  775. if (ERROR_SUCCESS != (lStatus = RegQueryValueExU(
  776. hKey,
  777. pwszValueName,
  778. NULL, // lpdwReserved
  779. pdwValueType,
  780. pbValueData,
  781. pcbValueData))) goto RegQueryValueError;
  782. fResult = TRUE;
  783. CommonReturn:
  784. if (pszRegName)
  785. PkiFree(pszRegName);
  786. if (hKey)
  787. RegCloseKey(hKey);
  788. return fResult;
  789. ErrorReturn:
  790. *pdwValueType = 0;
  791. *pcbValueData = 0;
  792. fResult = FALSE;
  793. goto CommonReturn;
  794. TRACE_ERROR(FormatRegNameError)
  795. SET_ERROR_VAR(RegOpenKeyError, lStatus)
  796. SET_ERROR_VAR(RegQueryValueError, lStatus)
  797. }
  798. //+-------------------------------------------------------------------------
  799. // Register the Dll containing the function to be called for the specified
  800. // encoding type, function name and OID.
  801. //
  802. // pwszDll may contain environment-variable strings
  803. // which are ExpandEnvironmentStrings()'ed before loading the Dll.
  804. //
  805. // In addition to registering the DLL, you may override the
  806. // name of the function to be called. For example,
  807. // pszFuncName = "CryptDllEncodeObject",
  808. // pszOverrideFuncName = "MyEncodeXyz".
  809. // This allows a Dll to export multiple OID functions for the same
  810. // function name without needing to interpose its own OID dispatcher function.
  811. //--------------------------------------------------------------------------
  812. BOOL
  813. WINAPI
  814. CryptRegisterOIDFunction(
  815. IN DWORD dwEncodingType,
  816. IN LPCSTR pszFuncName,
  817. IN LPCSTR pszOID,
  818. IN OPTIONAL LPCWSTR pwszDll,
  819. IN OPTIONAL LPCSTR pszOverrideFuncName
  820. )
  821. {
  822. BOOL fResult;
  823. LPWSTR pwszOverrideFuncName = NULL;
  824. if (pwszDll) {
  825. if (!CryptSetOIDFunctionValue(
  826. dwEncodingType,
  827. pszFuncName,
  828. pszOID,
  829. CRYPT_OID_REG_DLL_VALUE_NAME,
  830. REG_SZ,
  831. (BYTE *) pwszDll,
  832. (wcslen(pwszDll) + 1) * sizeof(WCHAR)))
  833. goto SetDllError;
  834. }
  835. if (pszOverrideFuncName) {
  836. if (NULL == (pwszOverrideFuncName = MkWStr(
  837. (LPSTR) pszOverrideFuncName)))
  838. goto MkWStrError;
  839. if (!CryptSetOIDFunctionValue(
  840. dwEncodingType,
  841. pszFuncName,
  842. pszOID,
  843. CRYPT_OID_REG_FUNC_NAME_VALUE_NAME,
  844. REG_SZ,
  845. (BYTE *) pwszOverrideFuncName,
  846. (wcslen(pwszOverrideFuncName) + 1) * sizeof(WCHAR)))
  847. goto SetFuncNameError;
  848. }
  849. fResult = TRUE;
  850. CommonReturn:
  851. if (pwszOverrideFuncName)
  852. FreeWStr(pwszOverrideFuncName);
  853. return fResult;
  854. ErrorReturn:
  855. fResult = FALSE;
  856. goto CommonReturn;
  857. TRACE_ERROR(SetDllError)
  858. TRACE_ERROR(SetFuncNameError)
  859. TRACE_ERROR(MkWStrError)
  860. }
  861. //+-------------------------------------------------------------------------
  862. // Unregister the Dll containing the function to be called for the specified
  863. // encoding type, function name and OID.
  864. //--------------------------------------------------------------------------
  865. BOOL
  866. WINAPI
  867. CryptUnregisterOIDFunction(
  868. IN DWORD dwEncodingType,
  869. IN LPCSTR pszFuncName,
  870. IN LPCSTR pszOID
  871. )
  872. {
  873. BOOL fResult;
  874. LONG lStatus;
  875. LPSTR pszRegName = NULL;
  876. LPSTR pszRegOID;
  877. HKEY hKey = NULL;
  878. if (NULL == (pszRegName = FormatOIDFuncRegName(
  879. dwEncodingType, pszFuncName, pszOID)))
  880. goto FormatRegNameError;
  881. // Separate off the OID component of the RegName. Its the
  882. // last component of the name.
  883. pszRegOID = pszRegName + strlen(pszRegName);
  884. while (*pszRegOID != '\\')
  885. pszRegOID--;
  886. *pszRegOID++ = '\0';
  887. if (ERROR_SUCCESS != (lStatus = RegOpenKeyExA(
  888. HKEY_LOCAL_MACHINE,
  889. pszRegName,
  890. 0, // dwReserved
  891. KEY_WRITE,
  892. &hKey))) goto RegOpenKeyError;
  893. if (ERROR_SUCCESS != (lStatus = RegDeleteKeyA(
  894. hKey,
  895. pszRegOID)))
  896. goto RegDeleteKeyError;
  897. fResult = TRUE;
  898. CommonReturn:
  899. if (pszRegName)
  900. PkiFree(pszRegName);
  901. if (hKey)
  902. RegCloseKey(hKey);
  903. return fResult;
  904. ErrorReturn:
  905. fResult = FALSE;
  906. goto CommonReturn;
  907. TRACE_ERROR(FormatRegNameError)
  908. SET_ERROR_VAR(RegOpenKeyError, lStatus)
  909. SET_ERROR_VAR(RegDeleteKeyError, lStatus)
  910. }
  911. STATIC BOOL GetDefaultDllList(
  912. IN DWORD dwEncodingType,
  913. IN LPCSTR pszFuncName,
  914. OUT LPWSTR pwszList,
  915. IN OUT DWORD *pcchList
  916. )
  917. {
  918. BOOL fResult;
  919. DWORD dwType;
  920. DWORD cchList;
  921. DWORD cbList;
  922. cchList = *pcchList;
  923. if (pwszList) {
  924. if (cchList < 3)
  925. goto InvalidArg;
  926. else
  927. // make room for two extra null terminators
  928. cchList -= 2;
  929. } else
  930. cchList = 0;
  931. cbList = cchList * sizeof(WCHAR);
  932. fResult = CryptGetOIDFunctionValue(
  933. dwEncodingType,
  934. pszFuncName,
  935. CRYPT_DEFAULT_OID,
  936. CRYPT_OID_REG_DLL_VALUE_NAME,
  937. &dwType,
  938. (BYTE *) pwszList,
  939. &cbList);
  940. cchList = cbList / sizeof(WCHAR);
  941. if (!fResult) {
  942. if (ERROR_FILE_NOT_FOUND != GetLastError()) {
  943. if (cchList)
  944. cchList += 2;
  945. goto GetOIDFunctionValueError;
  946. }
  947. cchList = 0;
  948. } else if (!(REG_MULTI_SZ == dwType ||
  949. REG_SZ == dwType || REG_EXPAND_SZ == dwType))
  950. goto BadDefaultListRegType;
  951. if (pwszList) {
  952. // Ensure the list has two null terminators
  953. pwszList[cchList++] = L'\0';
  954. pwszList[cchList++] = L'\0';
  955. } else {
  956. if (cchList == 0)
  957. cchList = 3;
  958. else
  959. cchList += 2;
  960. }
  961. fResult = TRUE;
  962. CommonReturn:
  963. *pcchList = cchList;
  964. return fResult;
  965. ErrorReturn:
  966. fResult = FALSE;
  967. goto CommonReturn;
  968. TRACE_ERROR(GetOIDFunctionValueError)
  969. SET_ERROR(InvalidArg, E_INVALIDARG)
  970. SET_ERROR(BadDefaultListRegType, E_INVALIDARG)
  971. }
  972. // Remove any entries following the first empty string.
  973. STATIC DWORD AdjustDefaultListLength(
  974. IN LPCWSTR pwszList
  975. )
  976. {
  977. LPCWSTR pwsz = pwszList;
  978. DWORD cch;
  979. while (cch = wcslen(pwsz))
  980. pwsz += cch + 1;
  981. return (DWORD)(pwsz - pwszList) + 1;
  982. }
  983. //+-------------------------------------------------------------------------
  984. // Register the Dll containing the default function to be called for the
  985. // specified encoding type and function name.
  986. //
  987. // Unlike CryptRegisterOIDFunction, you can't override the function name
  988. // needing to be exported by the Dll.
  989. //
  990. // The Dll is inserted before the entry specified by dwIndex.
  991. // dwIndex == 0, inserts at the beginning.
  992. // dwIndex == CRYPT_REGISTER_LAST_INDEX, appends at the end.
  993. //
  994. // pwszDll may contain environment-variable strings
  995. // which are ExpandEnvironmentStrings()'ed before loading the Dll.
  996. //--------------------------------------------------------------------------
  997. BOOL
  998. WINAPI
  999. CryptRegisterDefaultOIDFunction(
  1000. IN DWORD dwEncodingType,
  1001. IN LPCSTR pszFuncName,
  1002. IN DWORD dwIndex,
  1003. IN LPCWSTR pwszDll
  1004. )
  1005. {
  1006. BOOL fResult;
  1007. LPWSTR pwszDllList; // _alloca'ed
  1008. DWORD cchDllList;
  1009. DWORD cchDll;
  1010. LPWSTR pwsz, pwszInsert, pwszSrc, pwszDest;
  1011. DWORD cch, cchRemain;
  1012. if (NULL == pwszDll || L'\0' == *pwszDll)
  1013. goto InvalidArg;
  1014. cchDll = wcslen(pwszDll) + 1;
  1015. if (!GetDefaultDllList(
  1016. dwEncodingType,
  1017. pszFuncName,
  1018. NULL, // pwszDllList
  1019. &cchDllList)) goto GetDefaultDllListError;
  1020. __try {
  1021. pwszDllList = (LPWSTR) _alloca((cchDllList + cchDll) * sizeof(WCHAR));
  1022. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1023. goto OutOfMemory;
  1024. }
  1025. if (!GetDefaultDllList(
  1026. dwEncodingType,
  1027. pszFuncName,
  1028. pwszDllList,
  1029. &cchDllList)) goto GetDefaultDllListError;
  1030. // Remove entries following the first empty entry
  1031. assert(AdjustDefaultListLength(pwszDllList) <= cchDllList);
  1032. cchDllList = AdjustDefaultListLength(pwszDllList);
  1033. // Check if the Dll already exists in the list
  1034. pwsz = pwszDllList;
  1035. while (cch = wcslen(pwsz)) {
  1036. if (0 == _wcsicmp(pwsz, pwszDll))
  1037. goto DllExistsError;
  1038. pwsz += cch + 1;
  1039. }
  1040. // Find the Null terminated DLL in the DllList to insert before.
  1041. // We insert before the dwIndex.
  1042. pwszInsert = pwszDllList;
  1043. while (dwIndex-- && 0 != (cch = wcslen(pwszInsert)))
  1044. pwszInsert += cch + 1;
  1045. // Before inserting, we need to move all the remaining entries in the
  1046. // existing DllList.
  1047. //
  1048. // Note, there must be at least the final zero terminator at
  1049. // pwszDllList[cchDllList - 1].
  1050. assert(pwszInsert < pwszDllList + cchDllList);
  1051. if (pwszInsert >= pwszDllList + cchDllList)
  1052. goto BadRegMultiSzError;
  1053. cchRemain = (DWORD)((pwszDllList + cchDllList) - pwszInsert);
  1054. assert(cchRemain);
  1055. pwszSrc = pwszDllList + cchDllList - 1;
  1056. pwszDest = pwszSrc + cchDll;
  1057. while (cchRemain--)
  1058. *pwszDest-- = *pwszSrc--;
  1059. assert(pwszSrc + 1 == pwszInsert);
  1060. // Insert the pwszDll
  1061. memcpy(pwszInsert, pwszDll, cchDll * sizeof(WCHAR));
  1062. if (!CryptSetOIDFunctionValue(
  1063. dwEncodingType,
  1064. pszFuncName,
  1065. CRYPT_DEFAULT_OID,
  1066. CRYPT_OID_REG_DLL_VALUE_NAME,
  1067. REG_MULTI_SZ,
  1068. (BYTE *) pwszDllList,
  1069. (cchDllList + cchDll) * sizeof(WCHAR))) goto SetDllListError;
  1070. fResult = TRUE;
  1071. CommonReturn:
  1072. return fResult;
  1073. ErrorReturn:
  1074. fResult = FALSE;
  1075. goto CommonReturn;
  1076. SET_ERROR(InvalidArg, E_INVALIDARG)
  1077. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  1078. SET_ERROR(DllExistsError, ERROR_FILE_EXISTS)
  1079. SET_ERROR(BadRegMultiSzError, E_INVALIDARG)
  1080. TRACE_ERROR(GetDefaultDllListError)
  1081. TRACE_ERROR(SetDllListError)
  1082. }
  1083. BOOL
  1084. WINAPI
  1085. CryptUnregisterDefaultOIDFunction(
  1086. IN DWORD dwEncodingType,
  1087. IN LPCSTR pszFuncName,
  1088. IN LPCWSTR pwszDll
  1089. )
  1090. {
  1091. BOOL fResult;
  1092. LPWSTR pwszDllList; // _alloca'ed
  1093. DWORD cchDllList;
  1094. DWORD cchDll;
  1095. LPWSTR pwszDelete, pwszMove;
  1096. DWORD cchDelete, cchRemain;
  1097. if (NULL == pwszDll || L'\0' == *pwszDll)
  1098. goto InvalidArg;
  1099. cchDll = wcslen(pwszDll) + 1;
  1100. if (!GetDefaultDllList(
  1101. dwEncodingType,
  1102. pszFuncName,
  1103. NULL, // pwszDllList
  1104. &cchDllList)) goto GetDefaultDllListError;
  1105. __try {
  1106. pwszDllList = (LPWSTR) _alloca(cchDllList * sizeof(WCHAR));
  1107. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1108. goto OutOfMemory;
  1109. }
  1110. if (!GetDefaultDllList(
  1111. dwEncodingType,
  1112. pszFuncName,
  1113. pwszDllList,
  1114. &cchDllList)) goto GetDefaultDllListError;
  1115. // Remove entries following the first empty entry
  1116. assert(AdjustDefaultListLength(pwszDllList) <= cchDllList);
  1117. cchDllList = AdjustDefaultListLength(pwszDllList);
  1118. // Search the DllList for a match
  1119. pwszDelete = pwszDllList;
  1120. while (cchDelete = wcslen(pwszDelete)) {
  1121. if (0 == _wcsicmp(pwszDll, pwszDelete))
  1122. break;
  1123. pwszDelete += cchDelete + 1;
  1124. }
  1125. if (0 == cchDelete) goto DllNotFound;
  1126. cchDelete++;
  1127. assert(cchDelete == cchDll);
  1128. // Move all the Dll entries that follow.
  1129. //
  1130. // Note, there must be at least the final zero terminator at
  1131. // pwszDllList[cchDllList - 1].
  1132. pwszMove = pwszDelete + cchDelete;
  1133. assert(pwszMove < pwszDllList + cchDllList);
  1134. if (pwszMove >= pwszDllList + cchDllList)
  1135. goto BadRegMultiSzError;
  1136. cchRemain = (DWORD)((pwszDllList + cchDllList) - pwszMove);
  1137. assert(cchRemain);
  1138. while (cchRemain--)
  1139. *pwszDelete++ = *pwszMove++;
  1140. if (!CryptSetOIDFunctionValue(
  1141. dwEncodingType,
  1142. pszFuncName,
  1143. CRYPT_DEFAULT_OID,
  1144. CRYPT_OID_REG_DLL_VALUE_NAME,
  1145. REG_MULTI_SZ,
  1146. (BYTE *) pwszDllList,
  1147. (cchDllList - cchDelete) * sizeof(WCHAR))) goto SetDllListError;
  1148. fResult = TRUE;
  1149. CommonReturn:
  1150. return fResult;
  1151. ErrorReturn:
  1152. fResult = FALSE;
  1153. goto CommonReturn;
  1154. SET_ERROR(InvalidArg, E_INVALIDARG)
  1155. SET_ERROR(DllNotFound, ERROR_FILE_NOT_FOUND)
  1156. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  1157. SET_ERROR(BadRegMultiSzError, E_INVALIDARG)
  1158. TRACE_ERROR(GetDefaultDllListError)
  1159. TRACE_ERROR(SetDllListError)
  1160. }
  1161. #define MAX_SUBKEY_LEN 128
  1162. STATIC HKEY GetNextRegSubKey(
  1163. IN HKEY hKey,
  1164. IN OUT DWORD *piSubKey,
  1165. IN LPCSTR pszFuncNameMatch,
  1166. OUT char szSubKeyName[MAX_SUBKEY_LEN]
  1167. )
  1168. {
  1169. HKEY hSubKey;
  1170. if (pszFuncNameMatch && *pszFuncNameMatch) {
  1171. if ((*piSubKey)++ > 0 || strlen(pszFuncNameMatch) >= MAX_SUBKEY_LEN)
  1172. return NULL;
  1173. strcpy(szSubKeyName, pszFuncNameMatch);
  1174. } else {
  1175. if (ERROR_SUCCESS != RegEnumKeyA(
  1176. hKey,
  1177. (*piSubKey)++,
  1178. szSubKeyName,
  1179. MAX_SUBKEY_LEN))
  1180. return NULL;
  1181. }
  1182. if (ERROR_SUCCESS == RegOpenKeyExA(
  1183. hKey,
  1184. szSubKeyName,
  1185. 0, // dwReserved
  1186. KEY_READ,
  1187. &hSubKey))
  1188. return hSubKey;
  1189. else
  1190. return NULL;
  1191. }
  1192. STATIC BOOL GetRegValues(
  1193. IN HKEY hKey,
  1194. OUT void **ppvAlloc,
  1195. OUT DWORD *pcValue,
  1196. OUT DWORD **ppdwValueType,
  1197. OUT LPWSTR **pppwszValueName,
  1198. OUT BYTE ***pppbValueData,
  1199. OUT DWORD **ppcbValueData
  1200. )
  1201. {
  1202. BOOL fResult;
  1203. LONG lStatus;
  1204. void *pvAlloc = NULL;
  1205. DWORD cValue;
  1206. DWORD iValue;
  1207. DWORD cchMaxName;
  1208. DWORD cbMaxData;
  1209. DWORD cbAlignData = 0;
  1210. DWORD *pdwValueType;
  1211. LPWSTR *ppwszValueName;
  1212. BYTE **ppbValueData;
  1213. DWORD *pcbValueData;
  1214. LPWSTR pwszName;
  1215. BYTE *pbData;
  1216. if (ERROR_SUCCESS != (lStatus = RegQueryInfoKeyU(
  1217. hKey,
  1218. NULL,
  1219. NULL,
  1220. NULL,
  1221. NULL,
  1222. NULL,
  1223. NULL,
  1224. &cValue,
  1225. &cchMaxName,
  1226. &cbMaxData,
  1227. NULL,
  1228. NULL
  1229. ))) goto RegQueryInfoKeyError;
  1230. // Do a single allocation for all the arrays, value names and
  1231. // value data. Update the array pointers.
  1232. if (cValue > 0) {
  1233. BYTE *pbAlloc;
  1234. DWORD cbAlloc;
  1235. // Include NULL terminator for the name and align the data length
  1236. // Also, include two NULL terminators to be added for the data.
  1237. // Ensures REG_MULTI_SZ is always NULL terminated.
  1238. cchMaxName++;
  1239. if (4 > cbMaxData)
  1240. cbMaxData = 4;
  1241. cbAlignData = LEN_ALIGN(cbMaxData + 2 * sizeof(WCHAR));
  1242. cbAlloc = (sizeof(DWORD) + sizeof(LPWSTR) + sizeof(BYTE *) +
  1243. sizeof(DWORD) + cchMaxName * sizeof(WCHAR) + cbAlignData) * cValue;
  1244. if (NULL == (pvAlloc = PkiNonzeroAlloc(cbAlloc)))
  1245. goto OutOfMemory;
  1246. pbAlloc = (BYTE *) pvAlloc;
  1247. ppwszValueName = (LPWSTR *) pbAlloc;
  1248. pbAlloc += sizeof(LPWSTR) * cValue;
  1249. ppbValueData = (BYTE **) pbAlloc;
  1250. pbAlloc += sizeof(BYTE *) * cValue;
  1251. pdwValueType = (DWORD *) pbAlloc;
  1252. pbAlloc += sizeof(DWORD) * cValue;
  1253. pcbValueData = (DWORD *) pbAlloc;
  1254. pbAlloc += sizeof(DWORD) * cValue;
  1255. pbData = pbAlloc;
  1256. pbAlloc += cbAlignData * cValue;
  1257. pwszName = (LPWSTR) pbAlloc;
  1258. assert(((BYTE *) pvAlloc) + cbAlloc ==
  1259. pbAlloc + (cchMaxName * sizeof(WCHAR)) * cValue);
  1260. } else {
  1261. ppwszValueName = NULL;
  1262. ppbValueData = NULL;
  1263. pdwValueType = NULL;
  1264. pcbValueData = NULL;
  1265. pbData = NULL;
  1266. pwszName = NULL;
  1267. }
  1268. for (iValue = 0; iValue < cValue;
  1269. iValue++, pwszName += cchMaxName, pbData += cbAlignData) {
  1270. DWORD cchName = cchMaxName;
  1271. DWORD cbData = cbMaxData;
  1272. DWORD dwType;
  1273. if (ERROR_SUCCESS != (lStatus = RegEnumValueU(
  1274. hKey,
  1275. iValue,
  1276. pwszName,
  1277. &cchName,
  1278. NULL, // pdwReserved
  1279. &dwType,
  1280. pbData,
  1281. &cbData
  1282. )))
  1283. goto RegEnumValueError;
  1284. // Ensure the data has two NULL terminators for REG_MULTI_SZ
  1285. // Note cbAlignData >= cbMaxData + 2 * sizeof(WCHAR)
  1286. memset(pbData + cbData, 0, 2 * sizeof(WCHAR));
  1287. pdwValueType[iValue] = dwType;
  1288. ppwszValueName[iValue] = pwszName;
  1289. ppbValueData[iValue] = pbData;
  1290. pcbValueData[iValue] = cbData;
  1291. }
  1292. fResult = TRUE;
  1293. CommonReturn:
  1294. *ppvAlloc = pvAlloc;
  1295. *pcValue = cValue;
  1296. *ppdwValueType = pdwValueType;
  1297. *pppwszValueName = ppwszValueName;
  1298. *pppbValueData = ppbValueData;
  1299. *ppcbValueData = pcbValueData;
  1300. return fResult;
  1301. ErrorReturn:
  1302. if (pvAlloc) {
  1303. PkiFree(pvAlloc);
  1304. pvAlloc = NULL;
  1305. }
  1306. cValue = 0;
  1307. pdwValueType = NULL;
  1308. ppwszValueName = NULL;
  1309. ppbValueData = NULL;
  1310. pcbValueData = NULL;
  1311. fResult = FALSE;
  1312. goto CommonReturn;
  1313. TRACE_ERROR(OutOfMemory)
  1314. SET_ERROR_VAR(RegQueryInfoKeyError, lStatus)
  1315. SET_ERROR_VAR(RegEnumValueError, lStatus)
  1316. }
  1317. //+-------------------------------------------------------------------------
  1318. // Enumerate the OID functions identified by their encoding type,
  1319. // function name and OID.
  1320. //
  1321. // pfnEnumOIDFunc is called for each registry key matching the input
  1322. // parameters. Setting dwEncodingType to CRYPT_MATCH_ANY_ENCODING_TYPE matches
  1323. // any. Setting pszFuncName or pszOID to NULL matches any.
  1324. //
  1325. // Set pszOID == CRYPT_DEFAULT_OID to restrict the enumeration to only the
  1326. // DEFAULT functions
  1327. //
  1328. // String types are UNICODE.
  1329. //--------------------------------------------------------------------------
  1330. BOOL
  1331. WINAPI
  1332. CryptEnumOIDFunction(
  1333. IN DWORD dwEncodingType,
  1334. IN LPCSTR pszFuncName,
  1335. IN LPCSTR pszOID,
  1336. IN DWORD dwFlags,
  1337. IN void *pvArg,
  1338. IN PFN_CRYPT_ENUM_OID_FUNC pfnEnumOIDFunc
  1339. )
  1340. {
  1341. HKEY hRegKey;
  1342. LPSTR pszEncodingType = NULL;
  1343. char szOID[34];
  1344. if (CRYPT_MATCH_ANY_ENCODING_TYPE != dwEncodingType) {
  1345. dwEncodingType = GetEncodingType(dwEncodingType);
  1346. if (NULL == (pszEncodingType = EncodingTypeToRegName(dwEncodingType)))
  1347. return FALSE;
  1348. }
  1349. if (pszOID && (DWORD_PTR) pszOID <= 0xFFFF) {
  1350. szOID[0] = CONST_OID_STR_PREFIX_CHAR;
  1351. _ltoa((DWORD) ((DWORD_PTR)pszOID), szOID + 1, 10);
  1352. pszOID = szOID;
  1353. }
  1354. if (ERROR_SUCCESS == RegOpenKeyEx(
  1355. HKEY_LOCAL_MACHINE,
  1356. CRYPT_OID_REGPATH,
  1357. 0, // dwReserved
  1358. KEY_READ,
  1359. &hRegKey)) {
  1360. // Enumerate and optionally match encoding type
  1361. HKEY hEncodingTypeKey;
  1362. DWORD iEncodingType = 0;
  1363. char szRegEncodingType[MAX_SUBKEY_LEN];
  1364. while (hEncodingTypeKey = GetNextRegSubKey(hRegKey,
  1365. &iEncodingType, pszEncodingType, szRegEncodingType)) {
  1366. // Convert the EncodingType string and validate
  1367. DWORD dwRegEncodingType;
  1368. if (RegNameToEncodingType(szRegEncodingType, &dwRegEncodingType)) {
  1369. // Enumerate and optionally match FuncName, for example,
  1370. // ("CryptDllEncodeObject")
  1371. HKEY hFuncName;
  1372. DWORD iFuncName = 0;
  1373. char szRegFuncName[MAX_SUBKEY_LEN];
  1374. while (hFuncName = GetNextRegSubKey(hEncodingTypeKey,
  1375. &iFuncName, pszFuncName, szRegFuncName)) {
  1376. // Enumerate and optionally match OID string ("1.2.3.4")
  1377. HKEY hOID;
  1378. DWORD iOID = 0;
  1379. char szRegOID[MAX_SUBKEY_LEN];
  1380. while (hOID = GetNextRegSubKey(hFuncName, &iOID, pszOID,
  1381. szRegOID)) {
  1382. // Read and allocate the registry values
  1383. void *pvAlloc;
  1384. DWORD cValue;
  1385. DWORD *pdwValueType;
  1386. LPWSTR *ppwszValueName;
  1387. BYTE **ppbValueData;
  1388. DWORD *pcbValueData;
  1389. if (GetRegValues(
  1390. hOID,
  1391. &pvAlloc,
  1392. &cValue,
  1393. &pdwValueType,
  1394. &ppwszValueName,
  1395. &ppbValueData,
  1396. &pcbValueData)) {
  1397. pfnEnumOIDFunc(
  1398. dwRegEncodingType,
  1399. szRegFuncName,
  1400. szRegOID,
  1401. cValue,
  1402. pdwValueType,
  1403. (LPCWSTR *) ppwszValueName,
  1404. (const BYTE **) ppbValueData,
  1405. pcbValueData,
  1406. pvArg);
  1407. if (pvAlloc)
  1408. PkiFree(pvAlloc);
  1409. }
  1410. RegCloseKey(hOID);
  1411. }
  1412. RegCloseKey(hFuncName);
  1413. }
  1414. }
  1415. RegCloseKey(hEncodingTypeKey);
  1416. }
  1417. RegCloseKey(hRegKey);
  1418. }
  1419. if (pszEncodingType)
  1420. PkiFree(pszEncodingType);
  1421. return TRUE;
  1422. }
  1423. //+=========================================================================
  1424. // Registry and Dll Load Functions
  1425. //==========================================================================
  1426. // Note, returned Dll element isn't AddRef'ed
  1427. STATIC PDLL_ELEMENT FindDll(
  1428. IN LPCWSTR pwszDll // not expanded
  1429. )
  1430. {
  1431. LPWSTR pwszExpandDll; // _alloca'ed
  1432. WCHAR rgch[4];
  1433. DWORD cchDll;
  1434. PDLL_ELEMENT pDll;
  1435. if (0 == (cchDll = ExpandEnvironmentStringsU(
  1436. pwszDll,
  1437. rgch, // lpszDest, NON_NULL for win95
  1438. sizeof(rgch)/sizeof(rgch[0])))) // cchDest
  1439. return NULL;
  1440. __try {
  1441. pwszExpandDll = (LPWSTR) _alloca(cchDll * sizeof(WCHAR));
  1442. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1443. return NULL;
  1444. }
  1445. if (0 == ExpandEnvironmentStringsU(
  1446. pwszDll,
  1447. pwszExpandDll,
  1448. cchDll))
  1449. return NULL;
  1450. LockOIDFunc();
  1451. // Check if we already have an entry
  1452. for (pDll = pDllHead; pDll; pDll = pDll->pNext) {
  1453. if (0 == _wcsicmp(pwszExpandDll, pDll->pwszDll))
  1454. break;
  1455. }
  1456. if (NULL == pDll) {
  1457. // Need to create a new DLL entry and add to our list
  1458. if (pDll = (PDLL_ELEMENT) PkiZeroAlloc(
  1459. sizeof(DLL_ELEMENT) + cchDll * sizeof(WCHAR))) {
  1460. LPWSTR pwszEleDll;
  1461. pDll->dwOIDType = DLL_OID_TYPE;
  1462. pwszEleDll = (LPWSTR) ((BYTE *) pDll + sizeof(DLL_ELEMENT));
  1463. memcpy(pwszEleDll, pwszExpandDll, cchDll * sizeof(WCHAR));
  1464. pDll->pwszDll = pwszEleDll;
  1465. pDll->pNext = pDllHead;
  1466. pDllHead = pDll;
  1467. }
  1468. }
  1469. UnlockOIDFunc();
  1470. return pDll;
  1471. }
  1472. // Upon entry/exit OIDFunc is locked
  1473. STATIC PDLL_PROC_ELEMENT AddDllProc(
  1474. IN LPCSTR pszFuncName,
  1475. IN LPCWSTR pwszDll
  1476. )
  1477. {
  1478. PDLL_PROC_ELEMENT pProcEle = NULL;
  1479. PDLL_ELEMENT pDll;
  1480. DWORD cchFuncName;
  1481. DWORD cbEle;
  1482. LPSTR psz;
  1483. cchFuncName = strlen(pszFuncName) + 1;
  1484. cbEle = sizeof(DLL_PROC_ELEMENT) + cchFuncName;
  1485. if (NULL == (pProcEle = (PDLL_PROC_ELEMENT) PkiZeroAlloc(cbEle)))
  1486. goto OutOfMemory;
  1487. if (NULL == (pDll = FindDll(pwszDll)))
  1488. goto FindDllError;
  1489. pProcEle->pNext = pDll->pProcHead;
  1490. pDll->pProcHead = pProcEle;
  1491. pProcEle->pDll = pDll;
  1492. psz = (LPSTR) ((BYTE *) pProcEle + sizeof(DLL_PROC_ELEMENT));
  1493. memcpy(psz, pszFuncName, cchFuncName);
  1494. pProcEle->pszName = psz;
  1495. pProcEle->pvAddr = NULL;
  1496. CommonReturn:
  1497. return pProcEle;
  1498. ErrorReturn:
  1499. PkiFree(pProcEle);
  1500. pProcEle = NULL;
  1501. goto CommonReturn;
  1502. TRACE_ERROR(OutOfMemory)
  1503. TRACE_ERROR(FindDllError)
  1504. }
  1505. // Upon entry/exit OIDFunc is locked
  1506. STATIC void AddRegOIDFunc(
  1507. IN DWORD dwEncodingType,
  1508. IN OUT PFUNC_SET pFuncSet,
  1509. IN LPCSTR pszFuncName,
  1510. IN LPCSTR pszOID,
  1511. IN LPCWSTR pwszDll,
  1512. IN DWORD dwCryptFlags
  1513. )
  1514. {
  1515. PREG_OID_FUNC_ELEMENT pOIDEle = NULL;
  1516. PDLL_PROC_ELEMENT pProcEle; // not allocated, doesn't need to be free'ed
  1517. DWORD cchOID;
  1518. DWORD cbEle;
  1519. LPSTR psz;
  1520. if (0xFFFF < (DWORD_PTR) pszOID)
  1521. cchOID = strlen(pszOID) + 1;
  1522. else
  1523. cchOID = 0;
  1524. cbEle = sizeof(REG_OID_FUNC_ELEMENT) + cchOID;
  1525. if (NULL == (pOIDEle = (PREG_OID_FUNC_ELEMENT) PkiZeroAlloc(cbEle)))
  1526. goto OutOfMemory;
  1527. if (NULL == (pProcEle = AddDllProc(pszFuncName, pwszDll)))
  1528. goto AddDllProcError;
  1529. pOIDEle->dwEncodingType = dwEncodingType;
  1530. if (dwCryptFlags & CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG) {
  1531. pOIDEle->pNext = pFuncSet->pRegBeforeOIDFuncHead;
  1532. pFuncSet->pRegBeforeOIDFuncHead = pOIDEle;
  1533. } else {
  1534. pOIDEle->pNext = pFuncSet->pRegAfterOIDFuncHead;
  1535. pFuncSet->pRegAfterOIDFuncHead = pOIDEle;
  1536. }
  1537. if (cchOID) {
  1538. psz = (LPSTR) ((BYTE *) pOIDEle + sizeof(REG_OID_FUNC_ELEMENT));
  1539. memcpy(psz, pszOID, cchOID);
  1540. pOIDEle->pszOID = psz;
  1541. } else
  1542. pOIDEle->dwOID = (DWORD_PTR) pszOID;
  1543. pOIDEle->pDllProc = pProcEle;
  1544. CommonReturn:
  1545. return;
  1546. ErrorReturn:
  1547. PkiFree(pOIDEle);
  1548. goto CommonReturn;
  1549. TRACE_ERROR(OutOfMemory)
  1550. TRACE_ERROR(AddDllProcError)
  1551. }
  1552. // Upon entry/exit OIDFunc is locked
  1553. STATIC void AddDefaultDllList(
  1554. IN DWORD dwEncodingType,
  1555. IN OUT PFUNC_SET pFuncSet,
  1556. IN LPCWSTR pwszInDllList,
  1557. IN DWORD cchInDllList
  1558. )
  1559. {
  1560. LPWSTR pwszDllList; // _alloca'ed
  1561. LPWSTR pwsz;
  1562. DWORD cchDllList;
  1563. DWORD cchDll;
  1564. DWORD cDll;
  1565. DWORD i;
  1566. PDEFAULT_REG_ELEMENT pEle = NULL;
  1567. DWORD cbEle;
  1568. LPWSTR *ppwszEleDll;
  1569. PDLL_PROC_ELEMENT *ppEleDllProc;
  1570. LPWSTR pwszEleDllList;
  1571. // Ensure cchDllList has 2 terminating NULL characters
  1572. assert(cchInDllList && pwszInDllList);
  1573. cchDllList = cchInDllList + 2;
  1574. __try {
  1575. pwszDllList = (LPWSTR) _alloca(cchDllList * sizeof(WCHAR));
  1576. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1577. goto OutOfMemory;
  1578. }
  1579. memcpy(pwszDllList, pwszInDllList, cchInDllList * sizeof(WCHAR));
  1580. pwszDllList[cchInDllList] = L'\0';
  1581. pwszDllList[cchInDllList + 1] = L'\0';
  1582. // Get count of null terminated Dlls
  1583. cDll = 0;
  1584. for (pwsz = pwszDllList; 0 != (cchDll = wcslen(pwsz)); pwsz += cchDll + 1)
  1585. cDll++;
  1586. if (0 == cDll)
  1587. goto NoDll;
  1588. cbEle = sizeof(DEFAULT_REG_ELEMENT) +
  1589. cDll * sizeof(LPWSTR) +
  1590. cDll * sizeof(PDLL_PROC_ELEMENT) +
  1591. cchDllList * sizeof(WCHAR)
  1592. ;
  1593. if (NULL == (pEle = (PDEFAULT_REG_ELEMENT) PkiZeroAlloc(cbEle)))
  1594. goto OutOfMemory;
  1595. ppwszEleDll = (LPWSTR *) ((BYTE *) pEle + sizeof(DEFAULT_REG_ELEMENT));
  1596. ppEleDllProc = (PDLL_PROC_ELEMENT *) ((BYTE *) ppwszEleDll +
  1597. cDll * sizeof(LPWSTR));
  1598. pwszEleDllList = (LPWSTR) ((BYTE *) ppEleDllProc +
  1599. cDll * sizeof(PDLL_PROC_ELEMENT));
  1600. assert((BYTE *) pwszEleDllList + cchDllList * sizeof(WCHAR) ==
  1601. (BYTE *) pEle + cbEle);
  1602. pEle->dwEncodingType = dwEncodingType;
  1603. // pEle->pNext =
  1604. memcpy(pwszEleDllList, pwszDllList, cchDllList * sizeof(WCHAR));
  1605. pEle->pwszDllList = pwszEleDllList;
  1606. pEle->cchDllList = cchDllList;
  1607. pEle->cDll = cDll;
  1608. pEle->rgpwszDll = ppwszEleDll;
  1609. pEle->rgpDllProc = ppEleDllProc;
  1610. for (pwsz = pwszEleDllList, i = 0;
  1611. 0 != (cchDll = wcslen(pwsz)); pwsz += cchDll + 1, i++) {
  1612. ppwszEleDll[i] = pwsz;
  1613. if (NULL == (ppEleDllProc[i] = AddDllProc(
  1614. pFuncSet->pszFuncName, pwsz)))
  1615. goto AddDllProcError;
  1616. }
  1617. assert (i == cDll);
  1618. pEle->pNext = pFuncSet->pDefaultRegHead;
  1619. pFuncSet->pDefaultRegHead = pEle;
  1620. CommonReturn:
  1621. return;
  1622. ErrorReturn:
  1623. PkiFree(pEle);
  1624. goto CommonReturn;
  1625. TRACE_ERROR(NoDll);
  1626. TRACE_ERROR(OutOfMemory);
  1627. TRACE_ERROR(AddDllProcError);
  1628. }
  1629. //+-------------------------------------------------------------------------
  1630. // Called by CryptEnumOIDFunction to enumerate through all the
  1631. // registered OID functions.
  1632. //
  1633. // Called with OIDFunc locked
  1634. //--------------------------------------------------------------------------
  1635. STATIC BOOL WINAPI EnumRegFuncCallback(
  1636. IN DWORD dwEncodingType,
  1637. IN LPCSTR pszFuncName,
  1638. IN LPCSTR pszOID,
  1639. IN DWORD cValue,
  1640. IN const DWORD rgdwValueType[],
  1641. IN LPCWSTR const rgpwszValueName[],
  1642. IN const BYTE * const rgpbValueData[],
  1643. IN const DWORD rgcbValueData[],
  1644. IN void *pvArg
  1645. )
  1646. {
  1647. PFUNC_SET pFuncSet = (PFUNC_SET) pvArg;
  1648. BOOL fDefaultDllList = FALSE;
  1649. LPCWSTR pwszDll = NULL; // not allocated
  1650. DWORD cchDll = 0;
  1651. LPCWSTR pwszOverrideFuncName = NULL; // not allocated
  1652. DWORD dwCryptFlags = 0;
  1653. assert(pFuncSet);
  1654. if (CONST_OID_STR_PREFIX_CHAR == *pszOID) {
  1655. // Convert "#<number>" string to its corresponding constant OID value
  1656. pszOID = (LPCSTR)(DWORD_PTR) atol(pszOID + 1);
  1657. if (0xFFFF < (DWORD_PTR) pszOID)
  1658. // Invalid OID. Skip it.
  1659. goto InvalidOID;
  1660. } else if (0 == _stricmp(CRYPT_DEFAULT_OID, pszOID))
  1661. fDefaultDllList = TRUE;
  1662. while (cValue--) {
  1663. LPCWSTR pwszValueName = rgpwszValueName[cValue];
  1664. DWORD dwValueType = rgdwValueType[cValue];
  1665. const BYTE *pbValueData = rgpbValueData[cValue];
  1666. DWORD cbValueData = rgcbValueData[cValue];
  1667. if (0 == _wcsicmp(pwszValueName, CRYPT_OID_REG_DLL_VALUE_NAME)) {
  1668. if (REG_SZ == dwValueType || REG_EXPAND_SZ == dwValueType ||
  1669. (fDefaultDllList && REG_MULTI_SZ == dwValueType)) {
  1670. pwszDll = (LPCWSTR) pbValueData;
  1671. cchDll = cbValueData / sizeof(WCHAR);
  1672. } else
  1673. // Invalid "Dll" value.
  1674. goto InvalidDll;
  1675. } else if (0 == _wcsicmp(pwszValueName,
  1676. CRYPT_OID_REG_FUNC_NAME_VALUE_NAME)) {
  1677. if (REG_SZ == dwValueType) {
  1678. LPCWSTR pwszValue = (LPCWSTR) pbValueData;
  1679. if (L'\0' != *pwszValue)
  1680. pwszOverrideFuncName = pwszValue;
  1681. } else
  1682. // Invalid "FuncName" value.
  1683. goto InvalidFuncName;
  1684. } else if (0 == _wcsicmp(pwszValueName,
  1685. CRYPT_OID_REG_FLAGS_VALUE_NAME)) {
  1686. if (REG_DWORD == dwValueType &&
  1687. cbValueData >= sizeof(dwCryptFlags))
  1688. memcpy(&dwCryptFlags, pbValueData, sizeof(dwCryptFlags));
  1689. // else
  1690. // Ignore invalid CryptFlags value type
  1691. }
  1692. }
  1693. if (0 == cchDll || L'\0' == *pwszDll)
  1694. goto NoDll;
  1695. if (fDefaultDllList)
  1696. AddDefaultDllList(
  1697. dwEncodingType,
  1698. pFuncSet,
  1699. pwszDll,
  1700. cchDll
  1701. );
  1702. else {
  1703. BYTE rgb[_MAX_PATH];
  1704. if (pwszOverrideFuncName) {
  1705. if (!MkMBStr(rgb, _MAX_PATH, pwszOverrideFuncName,
  1706. (LPSTR *) &pszFuncName))
  1707. goto MkMBStrError;
  1708. }
  1709. AddRegOIDFunc(
  1710. dwEncodingType,
  1711. pFuncSet,
  1712. pszFuncName,
  1713. pszOID,
  1714. pwszDll,
  1715. dwCryptFlags
  1716. );
  1717. if (pwszOverrideFuncName)
  1718. FreeMBStr(rgb, (LPSTR) pszFuncName);
  1719. }
  1720. CommonReturn:
  1721. return TRUE;
  1722. ErrorReturn:
  1723. goto CommonReturn;
  1724. TRACE_ERROR(InvalidOID)
  1725. TRACE_ERROR(InvalidDll)
  1726. TRACE_ERROR(InvalidFuncName)
  1727. TRACE_ERROR(NoDll)
  1728. TRACE_ERROR(MkMBStrError)
  1729. }
  1730. STATIC void LoadRegFunc(
  1731. IN OUT PFUNC_SET pFuncSet
  1732. )
  1733. {
  1734. LockOIDFunc();
  1735. if (pFuncSet->fRegLoaded)
  1736. goto CommonReturn;
  1737. CryptEnumOIDFunction(
  1738. CRYPT_MATCH_ANY_ENCODING_TYPE,
  1739. pFuncSet->pszFuncName,
  1740. NULL, // pszOID
  1741. 0, // dwFlags
  1742. (void *) pFuncSet, // pvArg
  1743. EnumRegFuncCallback
  1744. );
  1745. pFuncSet->fRegLoaded = TRUE;
  1746. CommonReturn:
  1747. UnlockOIDFunc();
  1748. return;
  1749. }
  1750. // Upon entry/exit OIDFunc is locked
  1751. STATIC void RemoveFreeDll(
  1752. IN PDLL_ELEMENT pDll
  1753. )
  1754. {
  1755. // Remove Dll from free list
  1756. if (pDll->pFreeNext)
  1757. pDll->pFreeNext->pFreePrev = pDll->pFreePrev;
  1758. if (pDll->pFreePrev)
  1759. pDll->pFreePrev->pFreeNext = pDll->pFreeNext;
  1760. else if (pDll == pFreeDllHead)
  1761. pFreeDllHead = pDll->pFreeNext;
  1762. // else
  1763. // Not on any list
  1764. pDll->pFreeNext = NULL;
  1765. pDll->pFreePrev = NULL;
  1766. assert(dwFreeDllCnt);
  1767. if (dwFreeDllCnt)
  1768. dwFreeDllCnt--;
  1769. }
  1770. // Upon entry/exit OIDFunc is locked
  1771. STATIC void AddRefDll(
  1772. IN PDLL_ELEMENT pDll
  1773. )
  1774. {
  1775. pDll->dwRefCnt++;
  1776. if (pDll->dwFreeCnt) {
  1777. pDll->dwFreeCnt = 0;
  1778. RemoveFreeDll(pDll);
  1779. }
  1780. }
  1781. // Note, MUST NOT HOLD OID LOCK WHILE CALLING FreeLibrary()!!
  1782. //
  1783. // Therefore, will put the Dll's to be freed on a list while holding the
  1784. // OID LOCK. After releasing the OID LOCK, will iterate through the
  1785. // list and call FreeLibrary().
  1786. STATIC VOID NTAPI FreeDllWaitForCallback(
  1787. PVOID Context,
  1788. BOOLEAN fWaitOrTimedOut // ???
  1789. )
  1790. {
  1791. PDLL_ELEMENT pFreeDll;
  1792. HMODULE *phFreeLibrary = NULL; // _alloca'ed
  1793. DWORD cFreeLibrary = 0;
  1794. LockOIDFunc();
  1795. if (dwFreeDllCnt) {
  1796. DWORD dwOrigFreeDllCnt = dwFreeDllCnt;
  1797. __try {
  1798. phFreeLibrary = (HMODULE *) _alloca(
  1799. dwOrigFreeDllCnt * sizeof(HMODULE));
  1800. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1801. goto OutOfMemory;
  1802. }
  1803. pFreeDll = pFreeDllHead;
  1804. assert(pFreeDll);
  1805. while (pFreeDll) {
  1806. PDLL_ELEMENT pDll = pFreeDll;
  1807. pFreeDll = pFreeDll->pFreeNext;
  1808. assert(pDll->dwFreeCnt);
  1809. if (0 == --pDll->dwFreeCnt) {
  1810. RemoveFreeDll(pDll);
  1811. assert(pDll->fLoaded);
  1812. if (!pDll->fLoaded)
  1813. continue;
  1814. if (NULL == pDll->pfnDllCanUnloadNow ||
  1815. S_OK == pDll->pfnDllCanUnloadNow()) {
  1816. assert(cFreeLibrary < dwOrigFreeDllCnt);
  1817. if (cFreeLibrary < dwOrigFreeDllCnt) {
  1818. PDLL_PROC_ELEMENT pEle;
  1819. // Loop and NULL all proc addresses
  1820. for (pEle = pDll->pProcHead; pEle; pEle = pEle->pNext)
  1821. pEle->pvAddr = NULL;
  1822. pDll->pfnDllCanUnloadNow = NULL;
  1823. // Add to array to be freed after releasing lock!!
  1824. assert(pDll->hDll);
  1825. phFreeLibrary[cFreeLibrary++] = pDll->hDll;
  1826. pDll->hDll = NULL;
  1827. pDll->fLoaded = FALSE;
  1828. }
  1829. }
  1830. }
  1831. }
  1832. } else {
  1833. assert(NULL == pFreeDllHead);
  1834. }
  1835. if (NULL == pFreeDllHead) {
  1836. assert(0 == dwFreeDllCnt);
  1837. // Do interlock to guard against a potential race condition at
  1838. // PROCESS_DETACH. Note, PROCESS_DETACH doesn't do a LockOIDFunc().
  1839. if (InterlockedExchange(&lFreeDll, 0)) {
  1840. HANDLE hRegWaitFor;
  1841. HMODULE hDllLibModule;
  1842. hRegWaitFor = hFreeDllRegWaitFor;
  1843. hFreeDllRegWaitFor = NULL;
  1844. hDllLibModule = hFreeDllLibModule;
  1845. hFreeDllLibModule = NULL;
  1846. UnlockOIDFunc();
  1847. while (cFreeLibrary--)
  1848. FreeLibrary(phFreeLibrary[cFreeLibrary]);
  1849. assert(hRegWaitFor);
  1850. ILS_ExitWait(hRegWaitFor, hDllLibModule);
  1851. assert(FALSE);
  1852. return;
  1853. }
  1854. }
  1855. CommonReturn:
  1856. UnlockOIDFunc();
  1857. while (cFreeLibrary--)
  1858. FreeLibrary(phFreeLibrary[cFreeLibrary]);
  1859. return;
  1860. ErrorReturn:
  1861. goto CommonReturn;
  1862. TRACE_ERROR(OutOfMemory);
  1863. }
  1864. STATIC void ReleaseDll(
  1865. IN PDLL_ELEMENT pDll
  1866. )
  1867. {
  1868. LockOIDFunc();
  1869. assert(pDll->dwRefCnt);
  1870. if (0 == --pDll->dwRefCnt) {
  1871. assert(pDll->fLoaded);
  1872. if (!pDll->fLoaded)
  1873. goto CommonReturn;
  1874. assert(0 == pDll->dwFreeCnt);
  1875. if (pDll->dwFreeCnt)
  1876. goto CommonReturn;
  1877. if (0 == lFreeDll) {
  1878. assert(NULL == hFreeDllRegWaitFor);
  1879. assert(NULL == hFreeDllLibModule);
  1880. // Inhibit crypt32.dll from being unloaded until this thread
  1881. // exits.
  1882. hFreeDllLibModule = DuplicateLibrary(hOidInfoInst);
  1883. if (!ILS_RegisterWaitForSingleObject(
  1884. &hFreeDllRegWaitFor,
  1885. NULL, // hObject
  1886. FreeDllWaitForCallback,
  1887. NULL, // Context
  1888. FREE_DLL_TIMEOUT,
  1889. 0 // dwFlags
  1890. )) {
  1891. hFreeDllRegWaitFor = NULL;
  1892. if (hFreeDllLibModule) {
  1893. FreeLibrary(hFreeDllLibModule);
  1894. hFreeDllLibModule = NULL;
  1895. }
  1896. goto RegisterWaitForError;
  1897. }
  1898. lFreeDll = 1;
  1899. }
  1900. assert(NULL == pDll->pFreeNext);
  1901. assert(NULL == pDll->pFreePrev);
  1902. pDll->dwFreeCnt = 2;
  1903. if (pFreeDllHead) {
  1904. pFreeDllHead->pFreePrev = pDll;
  1905. pDll->pFreeNext = pFreeDllHead;
  1906. }
  1907. pFreeDllHead = pDll;
  1908. dwFreeDllCnt++;
  1909. }
  1910. CommonReturn:
  1911. UnlockOIDFunc();
  1912. return;
  1913. ErrorReturn:
  1914. goto CommonReturn;
  1915. TRACE_ERROR(RegisterWaitForError)
  1916. }
  1917. // Upon entry/exit OIDFunc must NOT be locked!!
  1918. STATIC BOOL LoadDll(
  1919. IN PDLL_ELEMENT pDll
  1920. )
  1921. {
  1922. BOOL fResult;
  1923. HMODULE hDll = NULL;
  1924. LPFNCANUNLOADNOW pfnDllCanUnloadNow = NULL;
  1925. LockOIDFunc();
  1926. if (pDll->fLoaded)
  1927. AddRefDll(pDll);
  1928. else {
  1929. UnlockOIDFunc();
  1930. // NO LoadLibrary() or GetProcAddress() while holding OID lock!!
  1931. hDll = LoadLibraryExU(pDll->pwszDll, NULL, 0);
  1932. if (hDll)
  1933. pfnDllCanUnloadNow = (LPFNCANUNLOADNOW) GetProcAddress(
  1934. hDll, "DllCanUnloadNow");
  1935. LockOIDFunc();
  1936. AddRefDll(pDll);
  1937. if (!pDll->fLoaded) {
  1938. assert(1 == pDll->dwRefCnt);
  1939. assert(0 == pDll->dwFreeCnt);
  1940. assert(pDll->pwszDll);
  1941. assert(NULL == pDll->hDll);
  1942. if (NULL == (pDll->hDll = hDll)) {
  1943. pDll->dwRefCnt = 0;
  1944. goto LoadLibraryError;
  1945. }
  1946. hDll = NULL;
  1947. pDll->fLoaded = TRUE;
  1948. assert(NULL == pDll->pfnDllCanUnloadNow);
  1949. pDll->pfnDllCanUnloadNow = pfnDllCanUnloadNow;
  1950. }
  1951. }
  1952. fResult = TRUE;
  1953. CommonReturn:
  1954. UnlockOIDFunc();
  1955. if (hDll) {
  1956. // Dll was loaded by another thread.
  1957. DWORD dwErr = GetLastError();
  1958. FreeLibrary(hDll);
  1959. SetLastError(dwErr);
  1960. }
  1961. return fResult;
  1962. ErrorReturn:
  1963. fResult = FALSE;
  1964. goto CommonReturn;
  1965. TRACE_ERROR(LoadLibraryError);
  1966. }
  1967. // Upon entry/exit OIDFunc must NOT be locked!!
  1968. STATIC BOOL GetDllProcAddr(
  1969. IN PDLL_PROC_ELEMENT pEle,
  1970. OUT void **ppvFuncAddr,
  1971. OUT HCRYPTOIDFUNCADDR *phFuncAddr
  1972. )
  1973. {
  1974. BOOL fResult;
  1975. void *pvAddr;
  1976. PDLL_ELEMENT pDll;
  1977. LockOIDFunc();
  1978. pDll = pEle->pDll;
  1979. assert(pDll);
  1980. if (pvAddr = pEle->pvAddr)
  1981. AddRefDll(pDll);
  1982. else {
  1983. UnlockOIDFunc();
  1984. // NO LoadLibrary() or GetProcAddress() while holding OID lock!!
  1985. fResult = LoadDll(pDll);
  1986. if (fResult) {
  1987. assert(pDll->hDll);
  1988. pvAddr = GetProcAddress(pDll->hDll, pEle->pszName);
  1989. }
  1990. LockOIDFunc();
  1991. if (!fResult)
  1992. goto LoadDllError;
  1993. if (pvAddr)
  1994. pEle->pvAddr = pvAddr;
  1995. else {
  1996. ReleaseDll(pDll);
  1997. goto GetProcAddressError;
  1998. }
  1999. }
  2000. fResult = TRUE;
  2001. CommonReturn:
  2002. *ppvFuncAddr = pvAddr;
  2003. *phFuncAddr = (HCRYPTOIDFUNCADDR) pDll;
  2004. UnlockOIDFunc();
  2005. return fResult;
  2006. ErrorReturn:
  2007. fResult = FALSE;
  2008. pDll = NULL;
  2009. pvAddr = NULL;
  2010. goto CommonReturn;
  2011. TRACE_ERROR(LoadDllError)
  2012. TRACE_ERROR(GetProcAddressError)
  2013. }
  2014. // Upon entry/exit OIDFunc must NOT be locked!!
  2015. STATIC BOOL GetRegOIDFunctionAddress(
  2016. IN PREG_OID_FUNC_ELEMENT pRegEle,
  2017. IN DWORD dwEncodingType,
  2018. IN LPCSTR pszOID,
  2019. OUT void **ppvFuncAddr,
  2020. OUT HCRYPTOIDFUNCADDR *phFuncAddr
  2021. )
  2022. {
  2023. for (; pRegEle; pRegEle = pRegEle->pNext) {
  2024. if (dwEncodingType != pRegEle->dwEncodingType)
  2025. continue;
  2026. if (0xFFFF >= (DWORD_PTR) pszOID) {
  2027. if (pszOID != pRegEle->pszOID)
  2028. continue;
  2029. } else {
  2030. if (0xFFFF >= (DWORD_PTR) pRegEle->pszOID ||
  2031. 0 != _stricmp(pszOID, pRegEle->pszOID))
  2032. continue;
  2033. }
  2034. return GetDllProcAddr(
  2035. pRegEle->pDllProc,
  2036. ppvFuncAddr,
  2037. phFuncAddr
  2038. );
  2039. }
  2040. *ppvFuncAddr = NULL;
  2041. *phFuncAddr = NULL;
  2042. return FALSE;
  2043. }
  2044. // Upon entry/exit OIDFunc must NOT be locked!!
  2045. STATIC BOOL GetDefaultRegOIDFunctionAddress(
  2046. IN PFUNC_SET pFuncSet,
  2047. IN DWORD dwEncodingType,
  2048. IN LPCWSTR pwszDll,
  2049. OUT void **ppvFuncAddr,
  2050. OUT HCRYPTOIDFUNCADDR *phFuncAddr
  2051. )
  2052. {
  2053. PDEFAULT_REG_ELEMENT pRegEle = pFuncSet->pDefaultRegHead;
  2054. PDLL_ELEMENT pDll;
  2055. for (; pRegEle; pRegEle = pRegEle->pNext) {
  2056. if (dwEncodingType != pRegEle->dwEncodingType)
  2057. continue;
  2058. for (DWORD i = 0; i < pRegEle->cDll; i++) {
  2059. if (0 == _wcsicmp(pwszDll, pRegEle->rgpwszDll[i]))
  2060. return GetDllProcAddr(
  2061. pRegEle->rgpDllProc[i],
  2062. ppvFuncAddr,
  2063. phFuncAddr
  2064. );
  2065. }
  2066. }
  2067. if (pDll = FindDll(pwszDll)) {
  2068. if (LoadDll(pDll)) {
  2069. if (*ppvFuncAddr = GetProcAddress(pDll->hDll,
  2070. pFuncSet->pszFuncName)) {
  2071. *phFuncAddr = (HCRYPTOIDFUNCADDR) pDll;
  2072. return TRUE;
  2073. } else
  2074. ReleaseDll(pDll);
  2075. }
  2076. }
  2077. *ppvFuncAddr = NULL;
  2078. *phFuncAddr = NULL;
  2079. return FALSE;
  2080. }
  2081. //+-------------------------------------------------------------------------
  2082. // Search the list of installed functions for an OID and EncodingType match.
  2083. // If not found, search the registry.
  2084. //
  2085. // For success, returns TRUE with *ppvFuncAddr updated with the function's
  2086. // address and *phFuncAddr updated with the function address's handle.
  2087. // The function's handle is AddRef'ed. CryptFreeOIDFunctionAddress needs to
  2088. // be called to release it.
  2089. //
  2090. // For a registry match, the Dll containing the function is loaded.
  2091. //
  2092. // By default, both the registered and installed function lists are searched.
  2093. // Set CRYPT_GET_INSTALLED_OID_FUNC_FLAG to only search the installed list
  2094. // of functions. This flag would be set by a registered function to get
  2095. // the address of a pre-installed function it was replacing. For example,
  2096. // the registered function might handle a new special case and call the
  2097. // pre-installed function to handle the remaining cases.
  2098. //--------------------------------------------------------------------------
  2099. BOOL
  2100. WINAPI
  2101. CryptGetOIDFunctionAddress(
  2102. IN HCRYPTOIDFUNCSET hFuncSet,
  2103. IN DWORD dwEncodingType,
  2104. IN LPCSTR pszOID,
  2105. IN DWORD dwFlags,
  2106. OUT void **ppvFuncAddr,
  2107. OUT HCRYPTOIDFUNCADDR *phFuncAddr
  2108. )
  2109. {
  2110. PFUNC_SET pFuncSet = (PFUNC_SET) hFuncSet;
  2111. DWORD_PTR dwOID;
  2112. dwEncodingType = GetEncodingType(dwEncodingType);
  2113. if (0xFFFF < (DWORD_PTR) pszOID && CONST_OID_STR_PREFIX_CHAR == *pszOID) {
  2114. // Convert "#<number>" string to its corresponding constant OID value
  2115. pszOID = (LPCSTR)(DWORD_PTR) atol(pszOID + 1);
  2116. if (0xFFFF < (DWORD_PTR) pszOID) {
  2117. SetLastError((DWORD) E_INVALIDARG);
  2118. *ppvFuncAddr = NULL;
  2119. *phFuncAddr = NULL;
  2120. return FALSE;
  2121. }
  2122. }
  2123. if (!pFuncSet->fRegLoaded)
  2124. LoadRegFunc(pFuncSet);
  2125. if (0 == (dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG) &&
  2126. pFuncSet->pRegBeforeOIDFuncHead) {
  2127. if (GetRegOIDFunctionAddress(
  2128. pFuncSet->pRegBeforeOIDFuncHead,
  2129. dwEncodingType,
  2130. pszOID,
  2131. ppvFuncAddr,
  2132. phFuncAddr
  2133. ))
  2134. return TRUE;
  2135. }
  2136. if (0xFFFF >= (dwOID = (DWORD_PTR) pszOID)) {
  2137. PCONST_OID_FUNC_ELEMENT pConstEle = pFuncSet->pConstOIDFuncHead;
  2138. while (pConstEle) {
  2139. if (dwEncodingType == pConstEle->dwEncodingType &&
  2140. dwOID >= pConstEle->dwLowOID &&
  2141. dwOID <= pConstEle->dwHighOID) {
  2142. *ppvFuncAddr = pConstEle->rgpvFuncAddr[
  2143. dwOID - pConstEle->dwLowOID];
  2144. *phFuncAddr = (HCRYPTOIDFUNCADDR) pConstEle;
  2145. return TRUE;
  2146. }
  2147. pConstEle = pConstEle->pNext;
  2148. }
  2149. } else {
  2150. PSTR_OID_FUNC_ELEMENT pStrEle = pFuncSet->pStrOIDFuncHead;
  2151. while (pStrEle) {
  2152. if (dwEncodingType == pStrEle->dwEncodingType &&
  2153. 0 == _stricmp(pszOID, pStrEle->pszOID)) {
  2154. *ppvFuncAddr = pStrEle->pvFuncAddr;
  2155. *phFuncAddr = (HCRYPTOIDFUNCADDR) pStrEle;
  2156. return TRUE;
  2157. }
  2158. pStrEle = pStrEle->pNext;
  2159. }
  2160. }
  2161. if (0 == (dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG) &&
  2162. pFuncSet->pRegAfterOIDFuncHead) {
  2163. if (GetRegOIDFunctionAddress(
  2164. pFuncSet->pRegAfterOIDFuncHead,
  2165. dwEncodingType,
  2166. pszOID,
  2167. ppvFuncAddr,
  2168. phFuncAddr
  2169. ))
  2170. return TRUE;
  2171. }
  2172. SetLastError((DWORD) ERROR_FILE_NOT_FOUND);
  2173. *ppvFuncAddr = NULL;
  2174. *phFuncAddr = NULL;
  2175. return FALSE;
  2176. }
  2177. //+-------------------------------------------------------------------------
  2178. // Get the list of registered default Dll entries for the specified
  2179. // function set and encoding type.
  2180. //
  2181. // The returned list consists of none, one or more null terminated Dll file
  2182. // names. The list is terminated with an empty (L"\0") Dll file name.
  2183. // For example: L"first.dll" L"\0" L"second.dll" L"\0" L"\0"
  2184. //--------------------------------------------------------------------------
  2185. BOOL
  2186. WINAPI
  2187. CryptGetDefaultOIDDllList(
  2188. IN HCRYPTOIDFUNCSET hFuncSet,
  2189. IN DWORD dwEncodingType,
  2190. OUT LPWSTR pwszDllList,
  2191. IN OUT DWORD *pcchDllList
  2192. )
  2193. {
  2194. BOOL fResult;
  2195. PFUNC_SET pFuncSet = (PFUNC_SET) hFuncSet;
  2196. PDEFAULT_REG_ELEMENT pRegEle;
  2197. DWORD cchRegDllList = 2;
  2198. LPWSTR pwszRegDllList = L"\0\0";
  2199. if (!pFuncSet->fRegLoaded)
  2200. LoadRegFunc(pFuncSet);
  2201. dwEncodingType = GetEncodingType(dwEncodingType);
  2202. pRegEle = pFuncSet->pDefaultRegHead;
  2203. for (; pRegEle; pRegEle = pRegEle->pNext) {
  2204. if (dwEncodingType == pRegEle->dwEncodingType) {
  2205. cchRegDllList = pRegEle->cchDllList;
  2206. assert(cchRegDllList >= 2);
  2207. pwszRegDllList = pRegEle->pwszDllList;
  2208. break;
  2209. }
  2210. }
  2211. fResult = TRUE;
  2212. if (pwszDllList) {
  2213. if (cchRegDllList > *pcchDllList) {
  2214. SetLastError((DWORD) ERROR_MORE_DATA);
  2215. fResult = FALSE;
  2216. } else
  2217. memcpy(pwszDllList, pwszRegDllList, cchRegDllList * sizeof(WCHAR));
  2218. }
  2219. *pcchDllList = cchRegDllList;
  2220. return fResult;
  2221. }
  2222. //+-------------------------------------------------------------------------
  2223. // Either: get the first or next installed DEFAULT function OR
  2224. // load the Dll containing the DEFAULT function.
  2225. //
  2226. // If pwszDll is NULL, search the list of installed DEFAULT functions.
  2227. // *phFuncAddr must be set to NULL to get the first installed function.
  2228. // Successive installed functions are returned by setting *phFuncAddr
  2229. // to the hFuncAddr returned by the previous call.
  2230. //
  2231. // If pwszDll is NULL, the input *phFuncAddr
  2232. // is always CryptFreeOIDFunctionAddress'ed by this function, even for
  2233. // an error.
  2234. //
  2235. // If pwszDll isn't NULL, then, attempts to load the Dll and the DEFAULT
  2236. // function. *phFuncAddr is ignored upon entry and isn't
  2237. // CryptFreeOIDFunctionAddress'ed.
  2238. //
  2239. // For success, returns TRUE with *ppvFuncAddr updated with the function's
  2240. // address and *phFuncAddr updated with the function address's handle.
  2241. // The function's handle is AddRef'ed. CryptFreeOIDFunctionAddress needs to
  2242. // be called to release it or CryptGetDefaultOIDFunctionAddress can also
  2243. // be called for a NULL pwszDll.
  2244. //--------------------------------------------------------------------------
  2245. BOOL
  2246. WINAPI
  2247. CryptGetDefaultOIDFunctionAddress(
  2248. IN HCRYPTOIDFUNCSET hFuncSet,
  2249. IN DWORD dwEncodingType,
  2250. IN OPTIONAL LPCWSTR pwszDll,
  2251. IN DWORD dwFlags,
  2252. OUT void **ppvFuncAddr,
  2253. IN OUT HCRYPTOIDFUNCADDR *phFuncAddr
  2254. )
  2255. {
  2256. PFUNC_SET pFuncSet = (PFUNC_SET) hFuncSet;
  2257. if (!pFuncSet->fRegLoaded)
  2258. LoadRegFunc(pFuncSet);
  2259. dwEncodingType = GetEncodingType(dwEncodingType);
  2260. if (NULL == pwszDll) {
  2261. // Get from installed list
  2262. PSTR_OID_FUNC_ELEMENT pStrEle = (PSTR_OID_FUNC_ELEMENT) *phFuncAddr;
  2263. if (pStrEle && STR_OID_TYPE == pStrEle->dwOIDType)
  2264. pStrEle = pStrEle->pNext;
  2265. else
  2266. pStrEle = pFuncSet->pStrOIDFuncHead;
  2267. while (pStrEle) {
  2268. if (dwEncodingType == pStrEle->dwEncodingType &&
  2269. 0 == _stricmp(CRYPT_DEFAULT_OID, pStrEle->pszOID)) {
  2270. *ppvFuncAddr = pStrEle->pvFuncAddr;
  2271. *phFuncAddr = (HCRYPTOIDFUNCADDR) pStrEle;
  2272. return TRUE;
  2273. }
  2274. pStrEle = pStrEle->pNext;
  2275. }
  2276. SetLastError(ERROR_FILE_NOT_FOUND);
  2277. *ppvFuncAddr = NULL;
  2278. *phFuncAddr = NULL;
  2279. return FALSE;
  2280. } else
  2281. return GetDefaultRegOIDFunctionAddress(
  2282. pFuncSet,
  2283. dwEncodingType,
  2284. pwszDll,
  2285. ppvFuncAddr,
  2286. phFuncAddr);
  2287. }
  2288. //+-------------------------------------------------------------------------
  2289. // Releases the handle AddRef'ed and returned by CryptGetOIDFunctionAddress
  2290. // or CryptGetDefaultOIDFunctionAddress.
  2291. //
  2292. // If a Dll was loaded for the function its unloaded. However, before doing
  2293. // the unload, the DllCanUnloadNow function exported by the loaded Dll is
  2294. // called. It should return S_FALSE to inhibit the unload or S_TRUE to enable
  2295. // the unload. If the Dll doesn't export DllCanUnloadNow, the Dll is unloaded.
  2296. //
  2297. // DllCanUnloadNow has the following signature:
  2298. // STDAPI DllCanUnloadNow(void);
  2299. //--------------------------------------------------------------------------
  2300. BOOL
  2301. WINAPI
  2302. CryptFreeOIDFunctionAddress(
  2303. IN HCRYPTOIDFUNCADDR hFuncAddr,
  2304. IN DWORD dwFlags
  2305. )
  2306. {
  2307. PDLL_ELEMENT pDll = (PDLL_ELEMENT) hFuncAddr;
  2308. if (pDll && DLL_OID_TYPE == pDll->dwOIDType) {
  2309. DWORD dwErr = GetLastError();
  2310. ReleaseDll(pDll);
  2311. SetLastError(dwErr);
  2312. }
  2313. return TRUE;
  2314. }