From: Ariel Darshan abdaandroid@gmail.com
Signed-off-by: Ariel Darshan abdaandroid@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);