crypt32(1/2): implement CryptSIPLoad (try 7)

Juan Lang juan.lang at gmail.com
Mon Jul 9 15:48:06 CDT 2007


This patchset is independent of the other series.

This implement CryptSIPLoad, I hope following Alexandre's suggestions this time.

--Juan
-------------- next part --------------
From 4cbd22285e0871990ccb340a28677ab79bd6bcf2 Mon Sep 17 00:00:00 2001
From: Juan Lang <juanlang at juan.corp.google.com>
Date: Mon, 9 Jul 2007 13:43:14 -0700
Subject: [PATCH] Implement CryptSIPLoad
---
 dlls/crypt32/crypt32_private.h |    1 
 dlls/crypt32/main.c            |    1 
 dlls/crypt32/sip.c             |  181 ++++++++++++++++++++++++++++++++++++++++
 dlls/crypt32/tests/sip.c       |   51 +++++------
 4 files changed, 202 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..389e434 100644
--- a/dlls/crypt32/sip.c
+++ b/dlls/crypt32/sip.c
@@ -30,6 +30,7 @@ #include "mssip.h"
 #include "winuser.h"
 
 #include "wine/debug.h"
+#include "wine/list.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 
@@ -59,6 +60,14 @@ 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);
+
+void crypt_sip_free(void)
+{
+    crypt_free_sips();
+}
+
 /* convert a guid to a wide character string */
 static void CRYPT_guid2wstr( const GUID *guid, LPWSTR wstr )
 {
@@ -354,6 +363,165 @@ cleanup3:
     return bRet;
 }
 
+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);
+}
+
+/* Loads the function named function for the SIP specified by pgSubject, and
+ * returns it if found.  Returns NULL on error.  If the function is loaded,
+ * *pLib is set to the library in which it is found.
+ */
+static void *CRYPT_LoadSIPFunc(const GUID *pgSubject, LPCWSTR function,
+ HMODULE *pLib)
+{
+    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;
+
+    lib = LoadLibraryW(dllName);
+    if (!lib)
+        goto error;
+    func = GetProcAddress(lib, functionName);
+    if (func)
+        *pLib = lib;
+    else
+        FreeLibrary(lib);
+
+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);
+        FreeLibrary(prov->info.hSIP);
+        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)
+{
+    SIP_DISPATCH_INFO sip = { 0 };
+    HMODULE lib, temp = NULL;
+
+    sip.pfGet = CRYPT_LoadSIPFunc(pgSubject, szGetSigned, &lib);
+    if (!sip.pfGet)
+        goto error;
+    sip.pfPut = CRYPT_LoadSIPFunc(pgSubject, szPutSigned, &temp);
+    if (!sip.pfPut || temp != lib)
+        goto error;
+    FreeLibrary(temp);
+    sip.pfCreate = CRYPT_LoadSIPFunc(pgSubject, szCreate, &temp);
+    if (!sip.pfCreate || temp != lib)
+        goto error;
+    FreeLibrary(temp);
+    sip.pfVerify = CRYPT_LoadSIPFunc(pgSubject, szVerify, &temp);
+    if (!sip.pfVerify || temp != lib)
+        goto error;
+    FreeLibrary(temp);
+    sip.pfRemove = CRYPT_LoadSIPFunc(pgSubject, szRemoveSigned, &temp);
+    if (!sip.pfRemove || temp != lib)
+        goto error;
+    FreeLibrary(temp);
+    sip.hSIP = lib;
+    CRYPT_CacheSIP(pgSubject, &sip);
+    return TRUE;
+
+error:
+    FreeLibrary(lib);
+    FreeLibrary(temp);
+    SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN);
+    return FALSE;
+}
+
 /***********************************************************************
  *             CryptSIPLoad (CRYPT32.@)
  *
@@ -382,15 +550,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