[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