[PATCH 16/16] ncrypt: Implement NCryptFreeBuffer

abdaandroid at gmail.com abdaandroid at gmail.com
Sun Oct 11 10:45:35 CDT 2020


From: Ariel Darshan <abdaandroid at gmail.com>

Signed-off-by: Ariel Darshan <abdaandroid at gmail.com>
---
 dlls/ncrypt/main.c            | 147 +++++++++++++++++++++++++++++++---
 dlls/ncrypt/ncrypt_internal.h |  11 +++
 2 files changed, 145 insertions(+), 13 deletions(-)

diff --git a/dlls/ncrypt/main.c b/dlls/ncrypt/main.c
index 3eca9018bec..1ea31d42e9a 100644
--- a/dlls/ncrypt/main.c
+++ b/dlls/ncrypt/main.c
@@ -31,6 +31,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(ncrypt);
 
+static struct list bufferList = LIST_INIT(bufferList);
+
 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
 {
     TRACE("(%p, %u, %p)\n", instance, reason, reserved);
@@ -154,6 +156,7 @@ SECURITY_STATUS WINAPI NCryptEnumAlgorithms(NCRYPT_PROV_HANDLE provider, DWORD a
                                             DWORD flags)
 {
     struct ncrypt_provider_instance *providerInstance;
+    SECURITY_STATUS ret;
 
     TRACE("(0x%lx, 0x%08x, %p, %p, 0x%08x)\n", provider, alg_ops, alg_count, alg_list, flags);
 
@@ -162,7 +165,13 @@ SECURITY_STATUS WINAPI NCryptEnumAlgorithms(NCRYPT_PROV_HANDLE provider, DWORD a
         return NTE_INVALID_HANDLE;
     }
     providerInstance = handle2provider(provider);
-    return providerInstance->functions.EnumAlgorithms(providerInstance->kspHandle, alg_ops, alg_count, alg_list, flags);
+    ret = providerInstance->functions.EnumAlgorithms(providerInstance->kspHandle, alg_ops, alg_count, alg_list, flags);
+    if (ret == ERROR_SUCCESS)
+    {
+        register_buffer(provider, *alg_list);
+    }
+
+    return ret;
 }
 
 SECURITY_STATUS WINAPI NCryptEnumKeys(NCRYPT_PROV_HANDLE provider, const WCHAR *scope,
@@ -186,16 +195,60 @@ SECURITY_STATUS WINAPI NCryptEnumKeys(NCRYPT_PROV_HANDLE provider, const WCHAR *
 
     if (firstRound && *enum_state)
     {
-        /* FIXME: enum_state must be freed with NCryptFreeBuffer, which as it seems should in turn
-            call the FreeBuffer function that is in the KSP DLL, so provider should live until after that happens */
-        providerInstance->refCount++;
+        ret = register_buffer(provider, *enum_state);
+        if (ret == NTE_NO_MEMORY)
+        {
+            ret = providerInstance->functions.FreeBuffer(*enum_state);
+            if (ret != ERROR_SUCCESS)
+            {
+                ERR("Provider failed to free enum_state\n");
+            }
+            *enum_state = NULL;
+
+            if (*key_name)
+            {
+                ret = providerInstance->functions.FreeBuffer(*key_name);
+                if (ret != ERROR_SUCCESS)
+                {
+                    ERR("Provider failed to free key_name\n");
+                }
+            }
+            *key_name = NULL;
+            return NTE_NO_MEMORY;
+        }
+        else if (ret != ERROR_SUCCESS)
+        {
+            FIXME("Unknown error while registering buffer: 0x%08x", ret);
+        }
     }
 
     if (ret == ERROR_SUCCESS && *key_name)
     {
-        /* FIXME: key_name must be freed with NCryptFreeBuffer, which as it seems should in turn
-            call the FreeBuffer function that is in the KSP DLL, so provider should live until after that happens */
-        providerInstance->refCount++;
+        ret = register_buffer(provider, *key_name);
+        if (ret == NTE_NO_MEMORY)
+        {
+            ret = providerInstance->functions.FreeBuffer(*key_name);
+            if (ret != ERROR_SUCCESS)
+            {
+                ERR("Provider failed to free key_name\n");
+            }
+            *key_name = NULL;
+
+            if (*enum_state)
+            {
+                ret = NCryptFreeBuffer(*enum_state);
+                if (ret != ERROR_SUCCESS)
+                {
+                    ERR("Provider failed to unregister enum_state\n");
+                }
+            }
+            *enum_state = NULL;
+            return NTE_NO_MEMORY;
+        }
+        else if (ret != ERROR_SUCCESS)
+        {
+            FIXME("Unknown error while registering buffer: 0x%08x", ret);
+        }
     }
     return ret;
 }
@@ -311,6 +364,7 @@ cleanup:
     {
         *providerCount = outCount;
         *providerList = outList;
+        register_buffer(0, outList);
     }
 
     RegCloseKey(hKey);
@@ -368,11 +422,47 @@ SECURITY_STATUS WINAPI NCryptFinalizeKey(NCRYPT_KEY_HANDLE key, DWORD flags)
 
 SECURITY_STATUS WINAPI NCryptFreeBuffer(PVOID buf)
 {
-    /* FIXME: How do we tell which provider should be called?
-                How do we update refCounts of referenced objects? */
-    FIXME("(%p): semi-stub\n", buf);
+    struct ncrypt_buffer *cursor, *safetyCursor;
+    struct ncrypt_provider_instance *providerInstance;
+    SECURITY_STATUS ret;
+    BOOL found;
+
+    TRACE("(%p)\n", buf);
+
+    found = FALSE;
+
+    LIST_FOR_EACH_ENTRY_SAFE(cursor, safetyCursor, &bufferList, struct ncrypt_buffer, entry)
+    {
+        if (cursor->buffer == buf)
+        {
+            found = TRUE;
+            list_remove(&cursor->entry);
 
-    heap_free(buf);
+            if (!cursor->owner)
+            {
+                heap_free(buf);
+                heap_free(cursor);
+                break;
+            }
+
+            providerInstance = handle2provider(cursor->owner);
+            ret = providerInstance->functions.FreeBuffer(buf);
+            if (ret != ERROR_SUCCESS)
+            {
+                ERR("Provider failed to free buffer: %p\n", buf);
+                return ret;
+            }
+            unref_provider(cursor->owner);
+            heap_free(cursor);
+            break;
+        }
+    }
+
+    if (!found)
+    {
+        WARN("Couldn't find buffer in list of registered buffers\n");
+        return NTE_INVALID_PARAMETER;
+    }
     return ERROR_SUCCESS;
 }
 
@@ -759,16 +849,47 @@ static struct ncrypt_key_instance* create_key(NCRYPT_PROV_HANDLE provider, const
     return ret;
 }
 
+static SECURITY_STATUS register_buffer(NCRYPT_PROV_HANDLE provider, const void *buffer)
+{
+    struct ncrypt_buffer *bufferEntry;
+
+    bufferEntry = heap_alloc(sizeof(struct ncrypt_buffer));
+    if (!bufferEntry)
+    {
+        return NTE_NO_MEMORY;
+    }
+
+    bufferEntry->buffer = buffer;
+    bufferEntry->owner = ref_provider(provider);
+
+    list_add_head(&bufferList, &bufferEntry->entry);
+    return ERROR_SUCCESS;
+}
+
 static NCRYPT_PROV_HANDLE ref_provider(NCRYPT_PROV_HANDLE provider)
 {
     struct ncrypt_provider_instance *providerInstance;
 
-    providerInstance = handle2provider(provider);
-    providerInstance->refCount++;
+    if (provider)
+    {
+        providerInstance = handle2provider(provider);
+        providerInstance->refCount++;
+    }
 
     return provider;
 }
 
+static void unref_provider(NCRYPT_PROV_HANDLE provider)
+{
+    struct ncrypt_provider_instance *providerInstance;
+
+    if (provider)
+    {
+        providerInstance = handle2provider(provider);
+        providerInstance->refCount--;
+    }
+}
+
 static SECURITY_STATUS free_provider(NCRYPT_HANDLE provider)
 {
     struct ncrypt_provider_instance *providerInstance;
diff --git a/dlls/ncrypt/ncrypt_internal.h b/dlls/ncrypt/ncrypt_internal.h
index 3a87727cb1e..8a6e2b3c3a5 100644
--- a/dlls/ncrypt/ncrypt_internal.h
+++ b/dlls/ncrypt/ncrypt_internal.h
@@ -22,6 +22,7 @@
 #define __NCRYPT_INTERNAL__
 
 #include "bcrypt.h"
+#include "wine/list.h"
 
 typedef struct _NCRYPT_KEY_STORAGE_FUNCTION_TABLE
 {
@@ -96,11 +97,21 @@ struct ncrypt_key_instance
 #define handle2provider(x) ((struct ncrypt_provider_instance*)(x))
 #define provider2handle(x) ((NCRYPT_PROV_HANDLE)(x))
 
+/* A buffer should be passed to the provider that allocated it,
+	so we need to keep track of it */
+struct ncrypt_buffer
+{
+	struct list entry;
+	NCRYPT_PROV_HANDLE owner;
+	const void *buffer;
+};
 
 
 static SECURITY_STATUS open_provider(NCRYPT_PROV_HANDLE *providerInstance ,const WCHAR *name, const WCHAR *dllName, DWORD flags);
 static struct ncrypt_key_instance* create_key(NCRYPT_PROV_HANDLE provider, const WCHAR *name);
+static SECURITY_STATUS register_buffer(NCRYPT_PROV_HANDLE provider, const void *buffer);
 static NCRYPT_PROV_HANDLE ref_provider(NCRYPT_PROV_HANDLE provider);
+static void unref_provider(NCRYPT_PROV_HANDLE provider);
 static SECURITY_STATUS free_provider(NCRYPT_HANDLE provider);
 static SECURITY_STATUS free_key(NCRYPT_HANDLE key);
 
-- 
2.28.0




More information about the wine-devel mailing list