crypt32: implement CryptSIPLoad (resend)
Juan Lang
juan.lang at gmail.com
Thu Jul 5 11:13:17 CDT 2007
Hi, any feedback on this one, please?
--Juan
-------------- next part --------------
From 223565b825ec864b09bfea385e692fa881933337 Mon Sep 17 00:00:00 2001
From: Juan Lang <juanlang at juan.corp.google.com>
Date: Mon, 2 Jul 2007 13:19:58 -0700
Subject: [PATCH] Implement CryptSIPLoad
---
dlls/crypt32/crypt32_private.h | 1
dlls/crypt32/main.c | 1
dlls/crypt32/sip.c | 235 ++++++++++++++++++++++++++++++++++++++++
dlls/crypt32/tests/sip.c | 51 ++++-----
4 files changed, 256 insertions(+), 32 deletions(-)
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index 64900d2..7a1aa32 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -50,6 +50,7 @@ HCRYPTPROV CRYPT_GetDefaultProvider(void
void crypt_oid_init(HINSTANCE hinst);
void crypt_oid_free(void);
+void crypt_sip_free(void);
/* Some typedefs that make it easier to abstract which type of context we're
* working with.
diff --git a/dlls/crypt32/main.c b/dlls/crypt32/main.c
index a0c4f4c..a377b24 100644
--- a/dlls/crypt32/main.c
+++ b/dlls/crypt32/main.c
@@ -43,6 +43,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstance,
break;
case DLL_PROCESS_DETACH:
crypt_oid_free();
+ crypt_sip_free();
if (hDefProv) CryptReleaseContext(hDefProv, 0);
break;
}
diff --git a/dlls/crypt32/sip.c b/dlls/crypt32/sip.c
index 1e24455..e9d0731 100644
--- a/dlls/crypt32/sip.c
+++ b/dlls/crypt32/sip.c
@@ -30,6 +30,8 @@ #include "mssip.h"
#include "winuser.h"
#include "wine/debug.h"
+#include "wine/list.h"
+#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
@@ -59,6 +61,16 @@ static const WCHAR szIsMyFile2[] = {
static const WCHAR szDllName[] = { 'D','l','l',0 };
static const WCHAR szFuncName[] = { 'F','u','n','c','N','a','m','e',0 };
+/* Prototypes */
+static void crypt_free_sips(void);
+static void crypt_unload_libraries(void);
+
+void crypt_sip_free(void)
+{
+ crypt_free_sips();
+ crypt_unload_libraries();
+}
+
/* convert a guid to a wide character string */
static void CRYPT_guid2wstr( const GUID *guid, LPWSTR wstr )
{
@@ -354,6 +366,216 @@ cleanup3:
return bRet;
}
+static struct list libraries = { &libraries, &libraries };
+static CRITICAL_SECTION libraries_cs;
+static CRITICAL_SECTION_DEBUG libraries_cs_debug =
+{
+ 0, 0, &libraries_cs,
+ { &libraries_cs_debug.ProcessLocksList,
+ &libraries_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": libraries_cs") }
+};
+static CRITICAL_SECTION libraries_cs = { &libraries_cs_debug, -1, 0, 0, 0, 0 };
+
+/* FIXME: use a hash table instead */
+typedef struct _WINE_CACHED_LIB
+{
+ LPWSTR dll;
+ HMODULE lib;
+ struct list entry;
+} WINE_CACHED_LIB;
+
+static void CRYPT_CacheLib(LPCWSTR dll, HMODULE lib)
+{
+ WINE_CACHED_LIB *cachedLib = CryptMemAlloc(sizeof(WINE_CACHED_LIB));
+
+ if (cachedLib)
+ {
+ cachedLib->dll = CryptMemAlloc((lstrlenW(dll) + 1) * sizeof(WCHAR));
+ if (cachedLib->dll)
+ {
+ strcpyW(cachedLib->dll, dll);
+ cachedLib->lib = lib;
+ EnterCriticalSection(&libraries_cs);
+ list_add_tail(&libraries, &cachedLib->entry);
+ LeaveCriticalSection(&libraries_cs);
+ }
+ else
+ CryptMemFree(cachedLib);
+ }
+}
+
+static HMODULE CRYPT_GetCachedLib(LPCWSTR dll)
+{
+ WINE_CACHED_LIB *entry = NULL;
+ HMODULE ret = NULL;
+
+ EnterCriticalSection(&libraries_cs);
+ LIST_FOR_EACH_ENTRY(entry, &libraries, WINE_CACHED_LIB, entry)
+ {
+ if (!strcmpiW(dll, entry->dll))
+ break;
+ }
+ if (entry && strcmpiW(dll, entry->dll))
+ ret = entry->lib;
+ LeaveCriticalSection(&libraries_cs);
+ return ret;
+}
+
+static void crypt_unload_libraries(void)
+{
+ WINE_CACHED_LIB *entry, *next;
+
+ LIST_FOR_EACH_ENTRY_SAFE(entry, next, &libraries, WINE_CACHED_LIB, entry)
+ {
+ list_remove(&entry->entry);
+ FreeLibrary(entry->lib);
+ CryptMemFree(entry->dll);
+ CryptMemFree(entry);
+ }
+}
+
+static LONG CRYPT_OpenSIPFunctionKey(const GUID *guid, LPCWSTR function,
+ HKEY *key)
+{
+ WCHAR szFullKey[ 0x100 ];
+
+ lstrcpyW(szFullKey, szOID);
+ lstrcatW(szFullKey, function);
+ CRYPT_guid2wstr(guid, &szFullKey[lstrlenW(szFullKey)]);
+ return RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, key);
+}
+
+static void *CRYPT_LoadSIPFunc(const GUID *pgSubject, LPCWSTR function)
+{
+ LONG r;
+ HKEY key = NULL;
+ DWORD size;
+ WCHAR dllName[MAX_PATH];
+ char functionName[MAX_PATH];
+ HMODULE lib;
+ void *func = NULL;
+
+ TRACE("(%s, %s)\n", debugstr_guid(pgSubject), debugstr_w(function));
+
+ r = CRYPT_OpenSIPFunctionKey(pgSubject, function, &key);
+ if (r) goto error;
+
+ /* Read the DLL entry */
+ size = sizeof(dllName);
+ r = RegQueryValueExW(key, szDllName, NULL, NULL, (LPBYTE)dllName, &size);
+ if (r) goto error;
+
+ /* Read the Function entry */
+ size = sizeof(functionName);
+ r = RegQueryValueExA(key, "FuncName", NULL, NULL, (LPBYTE)functionName,
+ &size);
+ if (r) goto error;
+
+ /* Check whether the library's been cached */
+ if (!(lib = CRYPT_GetCachedLib(dllName)))
+ {
+ lib = LoadLibraryW(dllName);
+ if (!lib)
+ goto error;
+ else
+ CRYPT_CacheLib(dllName, lib);
+ }
+
+ func = GetProcAddress(lib, functionName);
+
+error:
+ RegCloseKey(key);
+ TRACE("returning %p\n", func);
+ return func;
+}
+
+typedef struct _WINE_SIP_PROVIDER {
+ GUID subject;
+ SIP_DISPATCH_INFO info;
+ struct list entry;
+} WINE_SIP_PROVIDER;
+
+static struct list providers = { &providers, &providers };
+static CRITICAL_SECTION providers_cs;
+static CRITICAL_SECTION_DEBUG providers_cs_debug =
+{
+ 0, 0, &providers_cs,
+ { &providers_cs_debug.ProcessLocksList,
+ &providers_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": providers_cs") }
+};
+static CRITICAL_SECTION providers_cs = { &providers_cs_debug, -1, 0, 0, 0, 0 };
+
+static void CRYPT_CacheSIP(const GUID *pgSubject, SIP_DISPATCH_INFO *info)
+{
+ WINE_SIP_PROVIDER *prov = CryptMemAlloc(sizeof(WINE_SIP_PROVIDER));
+
+ if (prov)
+ {
+ memcpy(&prov->subject, pgSubject, sizeof(prov->subject));
+ memcpy(&prov->info, info, sizeof(prov->info));
+ EnterCriticalSection(&providers_cs);
+ list_add_tail(&providers, &prov->entry);
+ LeaveCriticalSection(&providers_cs);
+ }
+}
+
+static WINE_SIP_PROVIDER *CRYPT_GetCachedSIP(const GUID *pgSubject)
+{
+ WINE_SIP_PROVIDER *provider = NULL, *ret = NULL;
+
+ EnterCriticalSection(&providers_cs);
+ LIST_FOR_EACH_ENTRY(provider, &providers, WINE_SIP_PROVIDER, entry)
+ {
+ if (IsEqualGUID(pgSubject, &provider->subject))
+ break;
+ }
+ if (provider && IsEqualGUID(pgSubject, &provider->subject))
+ ret = provider;
+ LeaveCriticalSection(&providers_cs);
+ return ret;
+}
+
+static inline BOOL CRYPT_IsSIPCached(const GUID *pgSubject)
+{
+ return CRYPT_GetCachedSIP(pgSubject) != NULL;
+}
+
+static void crypt_free_sips(void)
+{
+ WINE_SIP_PROVIDER *prov, *next;
+
+ LIST_FOR_EACH_ENTRY_SAFE(prov, next, &providers, WINE_SIP_PROVIDER, entry)
+ {
+ list_remove(&prov->entry);
+ CryptMemFree(prov);
+ }
+}
+
+/* Loads the SIP for pgSubject into the global cache. Returns FALSE if the
+ * SIP isn't registered or is invalid.
+ */
+static BOOL CRYPT_LoadSIP(const GUID *pgSubject)
+{
+ BOOL ret = FALSE;
+ SIP_DISPATCH_INFO sip = { 0 };
+
+ sip.pfGet = CRYPT_LoadSIPFunc(pgSubject, szGetSigned);
+ sip.pfPut = CRYPT_LoadSIPFunc(pgSubject, szPutSigned);
+ sip.pfCreate = CRYPT_LoadSIPFunc(pgSubject, szCreate);
+ sip.pfVerify = CRYPT_LoadSIPFunc(pgSubject, szVerify);
+ sip.pfRemove = CRYPT_LoadSIPFunc(pgSubject, szRemoveSigned);
+ if (sip.pfGet && sip.pfPut && sip.pfCreate && sip.pfVerify && sip.pfRemove)
+ {
+ CRYPT_CacheSIP(pgSubject, &sip);
+ ret = TRUE;
+ }
+ else
+ SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN);
+ return ret;
+}
+
/***********************************************************************
* CryptSIPLoad (CRYPT32.@)
*
@@ -382,15 +604,24 @@ cleanup3:
BOOL WINAPI CryptSIPLoad
(const GUID *pgSubject, DWORD dwFlags, SIP_DISPATCH_INFO *pSipDispatch)
{
- FIXME("(%s %d %p) stub!\n", debugstr_guid(pgSubject), dwFlags, pSipDispatch);
+ TRACE("(%s %d %p)\n", debugstr_guid(pgSubject), dwFlags, pSipDispatch);
if (!pgSubject || dwFlags != 0 || !pSipDispatch)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
+ if (!CRYPT_IsSIPCached(pgSubject) && !CRYPT_LoadSIP(pgSubject))
+ return FALSE;
- return FALSE;
+ pSipDispatch->hSIP = NULL;
+ pSipDispatch->pfGet = CryptSIPGetSignedDataMsg;
+ pSipDispatch->pfPut = CryptSIPPutSignedDataMsg;
+ pSipDispatch->pfCreate = CryptSIPCreateIndirectData;
+ pSipDispatch->pfVerify = CryptSIPVerifyIndirectData;
+ pSipDispatch->pfRemove = CryptSIPRemoveSignedDataMsg;
+
+ return TRUE;
}
/***********************************************************************
diff --git a/dlls/crypt32/tests/sip.c b/dlls/crypt32/tests/sip.c
index cce058e..0496370 100644
--- a/dlls/crypt32/tests/sip.c
+++ b/dlls/crypt32/tests/sip.c
@@ -283,9 +283,8 @@ static void test_SIPLoad(void)
sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef;
ret = CryptSIPLoad(&dummySubject, 0, &sdi);
ok ( !ret, "Expected CryptSIPLoad to fail\n");
- todo_wine
- ok ( GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN,
- "Expected TRUST_E_SUBJECT_FORM_UNKNOWN, got 0x%08x\n", GetLastError());
+ ok ( GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN,
+ "Expected TRUST_E_SUBJECT_FORM_UNKNOWN, got 0x%08x\n", GetLastError());
ok( sdi.pfGet == (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected no change to the function pointer\n");
hCrypt = LoadLibraryA("crypt32.dll");
@@ -306,16 +305,13 @@ static void test_SIPLoad(void)
sdi.cbSize = sizeof(SIP_DISPATCH_INFO);
sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef;
ret = CryptSIPLoad(&unknown, 0, &sdi);
- todo_wine
- {
- ok ( ret, "Expected CryptSIPLoad to succeed\n");
- /* On native the last error will always be ERROR_PROC_NOT_FOUND as native searches for the function DllCanUnloadNow
- * in WINTRUST.DLL (in this case). This function is not available in WINTRUST.DLL.
- * For now there's no need to implement this is Wine as I doubt any program will rely on
- * this last error when the call succeeded.
- */
- ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n");
- }
+ ok ( ret, "Expected CryptSIPLoad to succeed\n");
+ /* On native the last error will always be ERROR_PROC_NOT_FOUND as native searches for the function DllCanUnloadNow
+ * in WINTRUST.DLL (in this case). This function is not available in WINTRUST.DLL.
+ * For now there's no need to implement this is Wine as I doubt any program will rely on
+ * this last error when the call succeeded.
+ */
+ ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n");
/* The function addresses returned by CryptSIPLoad are actually the addresses of
* crypt32's own functions. A function calling these addresses will end up first
@@ -324,13 +320,12 @@ static void test_SIPLoad(void)
*/
if (funcCryptSIPGetSignedDataMsg && funcCryptSIPPutSignedDataMsg && funcCryptSIPCreateIndirectData &&
funcCryptSIPVerifyIndirectData && funcCryptSIPRemoveSignedDataMsg)
- todo_wine
- ok (sdi.pfGet == funcCryptSIPGetSignedDataMsg &&
- sdi.pfPut == funcCryptSIPPutSignedDataMsg &&
- sdi.pfCreate == funcCryptSIPCreateIndirectData &&
- sdi.pfVerify == funcCryptSIPVerifyIndirectData &&
- sdi.pfRemove == funcCryptSIPRemoveSignedDataMsg,
- "Expected function addresses to be from crypt32\n");
+ ok (sdi.pfGet == funcCryptSIPGetSignedDataMsg &&
+ sdi.pfPut == funcCryptSIPPutSignedDataMsg &&
+ sdi.pfCreate == funcCryptSIPCreateIndirectData &&
+ sdi.pfVerify == funcCryptSIPVerifyIndirectData &&
+ sdi.pfRemove == funcCryptSIPRemoveSignedDataMsg,
+ "Expected function addresses to be from crypt32\n");
else
trace("Couldn't load function pointers\n");
@@ -340,16 +335,12 @@ static void test_SIPLoad(void)
sdi.cbSize = sizeof(SIP_DISPATCH_INFO);
sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef;
ret = CryptSIPLoad(&unknown2, 0, &sdi);
- todo_wine
- {
- ok ( ret, "Expected CryptSIPLoad to succeed\n");
- /* This call on its own would have resulted in an ERROR_PROC_NOT_FOUND, but the previous
- * call to CryptSIPLoad already loaded wintrust.dll. As this information is cached,
- * CryptSIPLoad will not try to search for the already mentioned DllCanUnloadNow.
- */
- }
- todo_wine
- ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n");
+ ok ( ret, "Expected CryptSIPLoad to succeed\n");
+ /* This call on its own would have resulted in an ERROR_PROC_NOT_FOUND, but the previous
+ * call to CryptSIPLoad already loaded wintrust.dll. As this information is cached,
+ * CryptSIPLoad will not try to search for the already mentioned DllCanUnloadNow.
+ */
+ ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n");
/* All OK, but other SIP */
SetLastError(0xdeadbeef);
--
1.4.1
More information about the wine-patches
mailing list