[SECUR32]
authorJérôme Gardou <jerome.gardou@reactos.org>
Sat, 30 Aug 2014 21:31:32 +0000 (21:31 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Sat, 30 Aug 2014 21:31:32 +0000 (21:31 +0000)
 - Import SSPI module loading from wine

svn path=/trunk/; revision=63994

reactos/dll/win32/secur32/CMakeLists.txt
reactos/dll/win32/secur32/precomp.h
reactos/dll/win32/secur32/secur32.spec
reactos/dll/win32/secur32/secur32_priv.h [new file with mode: 0644]
reactos/dll/win32/secur32/sspi.c
reactos/dll/win32/secur32/thunks.c [new file with mode: 0644]
reactos/dll/win32/secur32/thunks.h [new file with mode: 0644]
reactos/dll/win32/secur32/wrapper.c [new file with mode: 0644]

index c09dc40..94a2b74 100644 (file)
@@ -9,6 +9,8 @@ list(APPEND SOURCE
     secext.c
     sspi.c
     stubs.c
+    thunks.c
+    wrapper.c
     precomp.h)
 
 add_library(secur32 SHARED
@@ -17,11 +19,11 @@ add_library(secur32 SHARED
     ${CMAKE_CURRENT_BINARY_DIR}/secur32_stubs.c
     ${CMAKE_CURRENT_BINARY_DIR}/secur32.def)
 
-set_module_type(secur32 win32dll UNICODE ENTRYPOINT DllMain 12)
+set_module_type(secur32 win32dll UNICODE)
 
-target_link_libraries(secur32 lsalib)
+target_link_libraries(secur32 lsalib wine)
 
-add_importlibs(secur32 advapi32 kernel32 ntdll)
+add_importlibs(secur32 advapi32 msvcrt kernel32 ntdll)
 add_pch(secur32 precomp.h SOURCE)
 
 add_cd_file(TARGET secur32 DESTINATION reactos/system32 FOR all)
index 427b1e0..a57daea 100644 (file)
 #define COM_NO_WINDOWS_H
 #include <windef.h>
 #include <winbase.h>
+#include <winnls.h>
+#include <winreg.h>
 #define NTOS_MODE_USER
 #include <ndk/rtlfuncs.h>
 
 #include <secext.h>
 #include <security.h>
 
+#include "secur32_priv.h"
+#include "thunks.h"
+
 #endif /* _SECUR32_PCH_ */
index 8ccc0dd..d08ae79 100644 (file)
@@ -5,8 +5,7 @@
 @ stdcall AddCredentialsW(ptr wstr wstr long ptr ptr ptr ptr)
 @ stdcall AddSecurityPackageA(str ptr)
 @ stdcall AddSecurityPackageW(wstr ptr)
-@ stdcall ApplyControlTokenA(ptr ptr)
-@ stdcall ApplyControlToken(ptr ptr) ApplyControlTokenW
+@ stdcall ApplyControlToken(ptr ptr)
 @ stdcall CompleteAuthToken(ptr ptr)
 @ stub CredMarshalTargetInfo
 @ stub CredUnmarshalTargetInfo
diff --git a/reactos/dll/win32/secur32/secur32_priv.h b/reactos/dll/win32/secur32/secur32_priv.h
new file mode 100644 (file)
index 0000000..6c675ae
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * secur32 private definitions.
+ *
+ * Copyright (C) 2004 Juan Lang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __SECUR32_PRIV_H__
+#define __SECUR32_PRIV_H__
+
+#include <wine/list.h>
+
+typedef struct _SecureProvider
+{
+    struct list             entry;
+    BOOL                    loaded;
+    PWSTR                   moduleName;
+    HMODULE                 lib;
+    SecurityFunctionTableA  fnTableA;
+    SecurityFunctionTableW  fnTableW;
+} SecureProvider;
+
+typedef struct _SecurePackage
+{
+    struct list     entry;
+    SecPkgInfoW     infoW;
+    SecureProvider *provider;
+} SecurePackage;
+
+/* Tries to find the package named packageName.  If it finds it, implicitly
+ * loads the package if it isn't already loaded.
+ */
+SecurePackage *SECUR32_findPackageW(PCWSTR packageName) DECLSPEC_HIDDEN;
+
+/* Tries to find the package named packageName.  (Thunks to _findPackageW)
+ */
+SecurePackage *SECUR32_findPackageA(PCSTR packageName) DECLSPEC_HIDDEN;
+
+/* A few string helpers; will return NULL if str is NULL.  Free return with
+ * HeapFree */
+PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str) DECLSPEC_HIDDEN;
+PSTR  SECUR32_AllocMultiByteFromWide(PCWSTR str) DECLSPEC_HIDDEN;
+
+#endif /* ndef __SECUR32_PRIV_H__ */
index 5cb902f..670d8b4 100644 (file)
@@ -1,10 +1,53 @@
+/* Copyright (C) 2004 Juan Lang
+ *
+ * This file implements loading of SSP DLLs.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
 #include "precomp.h"
 
-#define NDEBUG
-#include <debug.h>
+#include <assert.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(secur32);
 
-SECURITY_STATUS WINAPI ApplyControlTokenW(PCtxtHandle Handle, PSecBufferDesc Buffer);
-SECURITY_STATUS WINAPI ApplyControlTokenA(PCtxtHandle Handle, PSecBufferDesc Buffer);
+typedef struct _SecurePackageTable
+{
+    DWORD numPackages;
+    DWORD numAllocated;
+    struct list table;
+} SecurePackageTable;
+
+typedef struct _SecureProviderTable
+{
+    DWORD numProviders;
+    DWORD numAllocated;
+    struct list table;
+} SecureProviderTable;
+
+static CRITICAL_SECTION cs;
+static CRITICAL_SECTION_DEBUG cs_debug =
+{
+    0, 0, &cs,
+    { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
+};
+static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
+static SecurePackageTable *packageTable = NULL;
+static SecureProviderTable *providerTable = NULL;
 
 static SecurityFunctionTableA securityFunctionTableA =
 {
@@ -18,7 +61,7 @@ static SecurityFunctionTableA securityFunctionTableA =
     AcceptSecurityContext,
     CompleteAuthToken,
     DeleteSecurityContext,
-    ApplyControlTokenA,
+    ApplyControlToken,
     QueryContextAttributesA,
     ImpersonateSecurityContext,
     RevertSecurityContext,
@@ -50,7 +93,7 @@ static SecurityFunctionTableW securityFunctionTableW =
     AcceptSecurityContext,
     CompleteAuthToken,
     DeleteSecurityContext,
-    ApplyControlTokenW,
+    ApplyControlToken,
     QueryContextAttributesW,
     ImpersonateSecurityContext,
     RevertSecurityContext,
@@ -70,52 +113,167 @@ static SecurityFunctionTableW securityFunctionTableW =
     NULL
 };
 
-SECURITY_STATUS
-WINAPI
-EnumerateSecurityPackagesW (
-       PULONG pcPackages,
-       PSecPkgInfoW* ppPackageInfo
-       )
+/***********************************************************************
+ *      EnumerateSecurityPackagesW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI EnumerateSecurityPackagesW(PULONG pcPackages,
+ PSecPkgInfoW *ppPackageInfo)
 {
     SECURITY_STATUS ret = SEC_E_OK;
 
+    TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
+
+    /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
     *pcPackages = 0;
-    *ppPackageInfo = NULL;
-    /*
+    EnterCriticalSection(&cs);
     if (packageTable)
     {
+        SecurePackage *package;
+        size_t bytesNeeded;
 
+        bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
+        LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
+        {
+            if (package->infoW.Name)
+                bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
+            if (package->infoW.Comment)
+                bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
+        }
+        if (bytesNeeded)
+        {
+            *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
+            if (*ppPackageInfo)
+            {
+                ULONG i = 0;
+                PWSTR nextString;
+
+                *pcPackages = packageTable->numPackages;
+                nextString = (PWSTR)((PBYTE)*ppPackageInfo +
+                 packageTable->numPackages * sizeof(SecPkgInfoW));
+                LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
+                {
+                    PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
+
+                    *pkgInfo = package->infoW;
+                    if (package->infoW.Name)
+                    {
+                        TRACE("Name[%d] = %S\n", i - 1, package->infoW.Name);
+                        pkgInfo->Name = nextString;
+                        lstrcpyW(nextString, package->infoW.Name);
+                        nextString += lstrlenW(nextString) + 1;
+                    }
+                    else
+                        pkgInfo->Name = NULL;
+                    if (package->infoW.Comment)
+                    {
+                        TRACE("Comment[%d] = %S\n", i - 1, package->infoW.Comment);
+                        pkgInfo->Comment = nextString;
+                        lstrcpyW(nextString, package->infoW.Comment);
+                        nextString += lstrlenW(nextString) + 1;
+                    }
+                    else
+                        pkgInfo->Comment = NULL;
+                }
+            }
+            else
+                ret = SEC_E_INSUFFICIENT_MEMORY;
+        }
     }
-    */
+    LeaveCriticalSection(&cs);
+    TRACE("<-- 0x%08x\n", ret);
+    return ret;
+}
 
-    UNIMPLEMENTED;
+/* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
+ * structures) into an array of SecPkgInfoA structures, which it returns.
+ */
+static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
+ const SecPkgInfoW *info)
+{
+    PSecPkgInfoA ret;
+
+    if (info)
+    {
+        size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
+        ULONG i;
+
+        for (i = 0; i < cPackages; i++)
+        {
+            if (info[i].Name)
+                bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
+                 -1, NULL, 0, NULL, NULL);
+            if (info[i].Comment)
+                bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
+                 -1, NULL, 0, NULL, NULL);
+        }
+        ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
+        if (ret)
+        {
+            PSTR nextString;
+
+            nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
+            for (i = 0; i < cPackages; i++)
+            {
+                PSecPkgInfoA pkgInfo = ret + i;
+                int bytes;
+
+                memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
+                if (info[i].Name)
+                {
+                    pkgInfo->Name = nextString;
+                    /* just repeat back to WideCharToMultiByte how many bytes
+                     * it requires, since we asked it earlier
+                     */
+                    bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
+                     NULL, 0, NULL, NULL);
+                    WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
+                     pkgInfo->Name, bytes, NULL, NULL);
+                    nextString += lstrlenA(nextString) + 1;
+                }
+                else
+                    pkgInfo->Name = NULL;
+                if (info[i].Comment)
+                {
+                    pkgInfo->Comment = nextString;
+                    /* just repeat back to WideCharToMultiByte how many bytes
+                     * it requires, since we asked it earlier
+                     */
+                    bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
+                     NULL, 0, NULL, NULL);
+                    WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
+                     pkgInfo->Comment, bytes, NULL, NULL);
+                    nextString += lstrlenA(nextString) + 1;
+                }
+                else
+                    pkgInfo->Comment = NULL;
+            }
+        }
+    }
+    else
+        ret = NULL;
     return ret;
 }
 
-SECURITY_STATUS
-WINAPI
-EnumerateSecurityPackagesA(
-       PULONG pcPackages,
-       PSecPkgInfoA* ppPackageInfo
-       )
+/***********************************************************************
+ *      EnumerateSecurityPackagesA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
+ PSecPkgInfoA *ppPackageInfo)
 {
     SECURITY_STATUS ret;
-    PSecPkgInfoW info = NULL;
+    PSecPkgInfoW info;
 
     ret = EnumerateSecurityPackagesW(pcPackages, &info);
     if (ret == SEC_E_OK && *pcPackages && info)
     {
-        /* *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
+        *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
         if (*pcPackages && !*ppPackageInfo)
         {
             *pcPackages = 0;
             ret = SEC_E_INSUFFICIENT_MEMORY;
-        } */
+        }
         FreeContextBuffer(info);
     }
-    *ppPackageInfo = NULL;
-       UNIMPLEMENTED;
-
     return ret;
 }
 
@@ -129,461 +287,543 @@ FreeContextBuffer (
     return SEC_E_OK;
 }
 
-SECURITY_STATUS
-WINAPI
-FreeCredentialsHandle(PCredHandle Handle)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-SECURITY_STATUS
-WINAPI
-DeleteSecurityContext(PCtxtHandle Handle)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
 PSecurityFunctionTableW
 WINAPI
 InitSecurityInterfaceW(VOID)
 {
-    DPRINT("InitSecurityInterfaceW() called\n");
+    TRACE("InitSecurityInterfaceW() called\n");
     return &securityFunctionTableW;
 }
 
-SECURITY_STATUS
+PSecurityFunctionTableA
 WINAPI
-EncryptMessage(PCtxtHandle Handle,
-               ULONG Foo,
-               PSecBufferDesc Buffer,
-               ULONG Bar)
+InitSecurityInterfaceA(VOID)
 {
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+    TRACE("InitSecurityInterfaceA() called\n");
+    return &securityFunctionTableA;
 }
 
-SECURITY_STATUS
+BOOLEAN
 WINAPI
-DecryptMessage(PCtxtHandle Handle,
-               PSecBufferDesc Buffer,
-               ULONG Foo,
-               PULONG Bar)
+TranslateNameA(
+       LPCSTR lpAccountName,
+       EXTENDED_NAME_FORMAT AccountNameFormat,
+       EXTENDED_NAME_FORMAT DesiredNameFormat,
+       LPSTR lpTranslatedName,
+       PULONG nSize
+)
 {
        UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+       return FALSE;
 }
 
-SECURITY_STATUS
+BOOLEAN
 WINAPI
-ApplyControlTokenW(PCtxtHandle Handle,
-                  PSecBufferDesc Buffer)
+TranslateNameW(
+       LPCWSTR lpAccountName,
+       EXTENDED_NAME_FORMAT AccountNameFormat,
+       EXTENDED_NAME_FORMAT DesiredNameFormat,
+       LPWSTR lpTranslatedName,
+       PULONG nSize
+)
 {
        UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+       return FALSE;
 }
 
-SECURITY_STATUS
-WINAPI
-ApplyControlTokenA(PCtxtHandle Handle,
-                  PSecBufferDesc Buffer)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+/*** PRIVATE FUNCTIONS ***************************************************************************/
 
-SECURITY_STATUS
-WINAPI
-CompleteAuthToken(PCtxtHandle Handle,
-                  PSecBufferDesc Buffer)
+static PWSTR SECUR32_strdupW(PCWSTR str)
 {
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+    PWSTR ret;
+
+    if (str)
+    {
+        ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
+        if (ret)
+            lstrcpyW(ret, str);
+    }
+    else
+        ret = NULL;
+    return ret;
 }
 
-SECURITY_STATUS
-WINAPI
-QueryContextAttributesA(PCtxtHandle Handle,
-                        ULONG Foo,
-                        PVOID Bar)
+PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
 {
-       UNIMPLEMENTED;
+    PWSTR ret;
 
-       if (Handle)
-       {
-               Bar = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
+    if (str)
+    {
+        int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
 
-       return SEC_E_INVALID_HANDLE;
+        if (charsNeeded)
+        {
+            ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
+            if (ret)
+                MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
+        }
+        else
+            ret = NULL;
+    }
+    else
+        ret = NULL;
+    return ret;
 }
 
-SECURITY_STATUS
-WINAPI
-QueryContextAttributesW(PCtxtHandle Handle,
-                        ULONG Foo,
-                        PVOID Bar)
+PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
 {
-       UNIMPLEMENTED;
+    PSTR ret;
 
-       if (Handle)
-       {
-               Bar = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
+    if (str)
+    {
+        int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
+        NULL, NULL);
 
-       return SEC_E_INVALID_HANDLE;
+        if (charsNeeded)
+        {
+            ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
+            if (ret)
+                WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
+                NULL, NULL);
+        }
+        else
+            ret = NULL;
+    }
+    else
+        ret = NULL;
+    return ret;
 }
 
-SECURITY_STATUS
-WINAPI
-AcquireCredentialsHandleA (
-    SEC_CHAR* pszPrincipal,
-    SEC_CHAR* pszPackage,
-    ULONG fUsage,
-    PLUID pID,
-    PVOID pAuth,
-    SEC_GET_KEY_FN pGetKeyFn,
-    PVOID pvGetKeyArgument,
-    PCredHandle phCred,
-    PTimeStamp pExpires
-    )
+static void _makeFnTableA(PSecurityFunctionTableA fnTableA,
+ const SecurityFunctionTableA *inFnTableA,
+ const SecurityFunctionTableW *inFnTableW)
 {
-       UNIMPLEMENTED;
-
-       if (pszPackage)
-       {
-               phCred = NULL;
-               pExpires = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
-
-       return SEC_E_SECPKG_NOT_FOUND;
+    if (fnTableA)
+    {
+        if (inFnTableA)
+        {
+            /* The size of the version 1 table is based on platform sdk's
+             * sspi.h, though the sample ssp also provided with platform sdk
+             * implies only functions through QuerySecurityPackageInfoA are
+             * implemented (yikes)
+             */
+            size_t tableSize = inFnTableA->dwVersion == 1 ?
+             (const BYTE *)&inFnTableA->SetContextAttributesA -
+             (const BYTE *)inFnTableA : sizeof(SecurityFunctionTableA);
+
+            memcpy(fnTableA, inFnTableA, tableSize);
+            /* override this, since we can do it internally anyway */
+            fnTableA->QuerySecurityPackageInfoA =
+             QuerySecurityPackageInfoA;
+        }
+        else if (inFnTableW)
+        {
+            /* functions with thunks */
+            if (inFnTableW->AcquireCredentialsHandleW)
+                fnTableA->AcquireCredentialsHandleA =
+                 thunk_AcquireCredentialsHandleA;
+            if (inFnTableW->InitializeSecurityContextW)
+                fnTableA->InitializeSecurityContextA =
+                 thunk_InitializeSecurityContextA;
+            if (inFnTableW->ImportSecurityContextW)
+                fnTableA->ImportSecurityContextA =
+                 thunk_ImportSecurityContextA;
+            if (inFnTableW->AddCredentialsW)
+                fnTableA->AddCredentialsA =
+                 thunk_AddCredentialsA;
+            if (inFnTableW->QueryCredentialsAttributesW)
+                fnTableA->QueryCredentialsAttributesA =
+                 thunk_QueryCredentialsAttributesA;
+            if (inFnTableW->QueryContextAttributesW)
+                fnTableA->QueryContextAttributesA =
+                 thunk_QueryContextAttributesA;
+            if (inFnTableW->SetContextAttributesW)
+                fnTableA->SetContextAttributesA =
+                 thunk_SetContextAttributesA;
+            /* this can't be thunked, there's no extra param to know which
+             * package to forward to */
+            fnTableA->EnumerateSecurityPackagesA = NULL;
+            /* functions with no thunks needed */
+            fnTableA->AcceptSecurityContext = inFnTableW->AcceptSecurityContext;
+            fnTableA->CompleteAuthToken = inFnTableW->CompleteAuthToken;
+            fnTableA->DeleteSecurityContext = inFnTableW->DeleteSecurityContext;
+            fnTableA->ImpersonateSecurityContext =
+             inFnTableW->ImpersonateSecurityContext;
+            fnTableA->RevertSecurityContext = inFnTableW->RevertSecurityContext;
+            fnTableA->MakeSignature = inFnTableW->MakeSignature;
+            fnTableA->VerifySignature = inFnTableW->VerifySignature;
+            fnTableA->FreeContextBuffer = inFnTableW->FreeContextBuffer;
+            fnTableA->QuerySecurityPackageInfoA =
+             QuerySecurityPackageInfoA;
+            fnTableA->ExportSecurityContext =
+             inFnTableW->ExportSecurityContext;
+            fnTableA->QuerySecurityContextToken =
+             inFnTableW->QuerySecurityContextToken;
+            fnTableA->EncryptMessage = inFnTableW->EncryptMessage;
+            fnTableA->DecryptMessage = inFnTableW->DecryptMessage;
+        }
+    }
 }
 
-SECURITY_STATUS
-WINAPI
-AcquireCredentialsHandleW (
-    SEC_WCHAR* pszPrincipal,
-    SEC_WCHAR* pszPackage,
-    ULONG fUsage,
-    PLUID pID,
-    PVOID pAuth,
-    SEC_GET_KEY_FN pGetKeyFn,
-    PVOID pvGetKeyArgument,
-    PCredHandle phCred,
-    PTimeStamp pExpires
-    )
+static void _makeFnTableW(PSecurityFunctionTableW fnTableW,
+ const SecurityFunctionTableA *inFnTableA,
+ const SecurityFunctionTableW *inFnTableW)
 {
-       UNIMPLEMENTED;
-
-       if (pszPackage)
-       {
-               phCred = NULL;
-               pExpires = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
-
-       return SEC_E_SECPKG_NOT_FOUND;
+    if (fnTableW)
+    {
+        if (inFnTableW)
+        {
+            /* The size of the version 1 table is based on platform sdk's
+             * sspi.h, though the sample ssp also provided with platform sdk
+             * implies only functions through QuerySecurityPackageInfoA are
+             * implemented (yikes)
+             */
+            size_t tableSize = inFnTableW->dwVersion == 1 ?
+             (const BYTE *)&inFnTableW->SetContextAttributesW -
+             (const BYTE *)inFnTableW : sizeof(SecurityFunctionTableW);
+
+            memcpy(fnTableW, inFnTableW, tableSize);
+            /* override this, since we can do it internally anyway */
+            fnTableW->QuerySecurityPackageInfoW =
+             QuerySecurityPackageInfoW;
+        }
+        else if (inFnTableA)
+        {
+            /* functions with thunks */
+            if (inFnTableA->AcquireCredentialsHandleA)
+                fnTableW->AcquireCredentialsHandleW =
+                 thunk_AcquireCredentialsHandleW;
+            if (inFnTableA->InitializeSecurityContextA)
+                fnTableW->InitializeSecurityContextW =
+                 thunk_InitializeSecurityContextW;
+            if (inFnTableA->ImportSecurityContextA)
+                fnTableW->ImportSecurityContextW =
+                 thunk_ImportSecurityContextW;
+            if (inFnTableA->AddCredentialsA)
+                fnTableW->AddCredentialsW =
+                 thunk_AddCredentialsW;
+            if (inFnTableA->QueryCredentialsAttributesA)
+                fnTableW->QueryCredentialsAttributesW =
+                 thunk_QueryCredentialsAttributesW;
+            if (inFnTableA->QueryContextAttributesA)
+                fnTableW->QueryContextAttributesW =
+                 thunk_QueryContextAttributesW;
+            if (inFnTableA->SetContextAttributesA)
+                fnTableW->SetContextAttributesW =
+                 thunk_SetContextAttributesW;
+            /* this can't be thunked, there's no extra param to know which
+             * package to forward to */
+            fnTableW->EnumerateSecurityPackagesW = NULL;
+            /* functions with no thunks needed */
+            fnTableW->AcceptSecurityContext = inFnTableA->AcceptSecurityContext;
+            fnTableW->CompleteAuthToken = inFnTableA->CompleteAuthToken;
+            fnTableW->DeleteSecurityContext = inFnTableA->DeleteSecurityContext;
+            fnTableW->ImpersonateSecurityContext =
+             inFnTableA->ImpersonateSecurityContext;
+            fnTableW->RevertSecurityContext = inFnTableA->RevertSecurityContext;
+            fnTableW->MakeSignature = inFnTableA->MakeSignature;
+            fnTableW->VerifySignature = inFnTableA->VerifySignature;
+            fnTableW->FreeContextBuffer = inFnTableA->FreeContextBuffer;
+            fnTableW->QuerySecurityPackageInfoW =
+             QuerySecurityPackageInfoW;
+            fnTableW->ExportSecurityContext =
+             inFnTableA->ExportSecurityContext;
+            fnTableW->QuerySecurityContextToken =
+             inFnTableA->QuerySecurityContextToken;
+            fnTableW->EncryptMessage = inFnTableA->EncryptMessage;
+            fnTableW->DecryptMessage = inFnTableA->DecryptMessage;
+        }
+    }
 }
 
-SECURITY_STATUS
-WINAPI
-InitializeSecurityContextW (
-    PCredHandle phCred,
-    PCtxtHandle phContext,
-    SEC_WCHAR* pszTarget,
-    ULONG fContextReq,
-    ULONG Reserved,
-    ULONG TargetData,
-    PSecBufferDesc pInput,
-    ULONG Reserved2,
-    PCtxtHandle phNewContext,
-    PSecBufferDesc pOut,
-    PULONG pfContextAttributes,
-    PTimeStamp pExpires
-    )
+static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
+ const SecPkgInfoW *inInfoW)
 {
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+    if (info && (inInfoA || inInfoW))
+    {
+        /* odd, I know, but up until Name and Comment the structures are
+         * identical
+         */
+        memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
+        if (inInfoW)
+        {
+            info->Name = SECUR32_strdupW(inInfoW->Name);
+            info->Comment = SECUR32_strdupW(inInfoW->Comment);
+        }
+        else
+        {
+            info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
+            info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
+        }
+    }
 }
 
-SECURITY_STATUS
-WINAPI
-InitializeSecurityContextA (
-    PCredHandle phCred,
-    PCtxtHandle phContext,
-    SEC_CHAR* pszTarget,
-    ULONG fContextReq,
-    ULONG Reserved,
-    ULONG TargetData,
-    PSecBufferDesc pInput,
-    ULONG Reserved2,
-    PCtxtHandle phNewContext,
-    PSecBufferDesc pOut,
-    PULONG pfContextAttributes,
-    PTimeStamp pExpires
-    )
+static
+SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
+ const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
 {
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    SecureProvider *ret;
 
+    EnterCriticalSection(&cs);
 
-SECURITY_STATUS
-SEC_ENTRY
-MakeSignature(
-    PCtxtHandle phContext,
-    ULONG fQOP,
-    PSecBufferDesc pMessage,
-    ULONG MessageSeqNo
-    )
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    if (!providerTable)
+    {
+        providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
+        if (!providerTable)
+        {
+            LeaveCriticalSection(&cs);
+            return NULL;
+        }
 
+        list_init(&providerTable->table);
+    }
 
-SECURITY_STATUS
-SEC_ENTRY
-VerifySignature(
-    PCtxtHandle phContext,
-    PSecBufferDesc pMessage,
-    ULONG MessageSeqNo,
-    PULONG pfQOP
-    )
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
+    if (!ret)
+    {
+        LeaveCriticalSection(&cs);
+        return NULL;
+    }
 
-SECURITY_STATUS
-SEC_ENTRY
-QuerySecurityPackageInfoA(
-    SEC_CHAR* pszPackageName,
-    PSecPkgInfoA* ppPackageInfo
-)
-{
-       UNIMPLEMENTED;
+    list_add_tail(&providerTable->table, &ret->entry);
+    ret->lib = NULL;
 
-       if (pszPackageName)
-       {
-               *ppPackageInfo = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
-       return SEC_E_SECPKG_NOT_FOUND;
+    if (fnTableA || fnTableW)
+    {
+        ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
+        _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
+        _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
+        ret->loaded = !moduleName;
+    }
+    else
+    {
+        ret->moduleName = SECUR32_strdupW(moduleName);
+        ret->loaded = FALSE;
+    }
+
+    LeaveCriticalSection(&cs);
+    return ret;
 }
 
-SECURITY_STATUS
-SEC_ENTRY
-QuerySecurityPackageInfoW(
-    SEC_WCHAR* pszPackageName,
-    PSecPkgInfoW* ppPackageInfo
-)
+static
+void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
+ const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
 {
-       UNIMPLEMENTED;
+    ULONG i;
 
-       if (pszPackageName)
-       {
-               *ppPackageInfo = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
-       return SEC_E_SECPKG_NOT_FOUND;
-}
+    assert(provider);
+    assert(infoA || infoW);
 
-SECURITY_STATUS
-WINAPI
-AcceptSecurityContext(
-    PCredHandle phCredential,
-    PCtxtHandle phContext,
-       PSecBufferDesc pInput,
-    ULONG fContextReq,
-       ULONG TargetDataRep,
-       PCtxtHandle phNewContext,
-    PSecBufferDesc pOutput,
-       ULONG *pfContextAttr,
-       PTimeStamp ptsExpiry
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    EnterCriticalSection(&cs);
 
-SECURITY_STATUS
-WINAPI
-AddCredentialsA(
-       PCredHandle hCredentials,
-       SEC_CHAR *pszPrincipal,
-       SEC_CHAR *pszPackage,
-       ULONG fCredentialUse,
-       LPVOID pAuthData,
-       SEC_GET_KEY_FN pGetKeyFn,
-       LPVOID pvGetKeyArgument,
-       PTimeStamp ptsExpiry
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    if (!packageTable)
+    {
+        packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
+        if (!packageTable)
+        {
+            LeaveCriticalSection(&cs);
+            return;
+        }
 
-SECURITY_STATUS
-WINAPI
-AddCredentialsW(
-       PCredHandle hCredentials,
-       SEC_WCHAR *pszPrincipal,
-       SEC_WCHAR *pszPackage,
-       ULONG fCredentialUse,
-       LPVOID pAuthData,
-       SEC_GET_KEY_FN pGetKeyFn,
-       LPVOID pvGetKeyArgument,
-       PTimeStamp ptsExpiry
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+        packageTable->numPackages = 0;
+        list_init(&packageTable->table);
+    }
 
-SECURITY_STATUS
-WINAPI
-ExportSecurityContext(
-       PCtxtHandle phContext,
-       ULONG fFlags,
-       PSecBuffer pPackedContext,
-       LPVOID *pToken
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    for (i = 0; i < toAdd; i++)
+    {
+        SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
+        if (!package)
+            continue;
 
-SECURITY_STATUS
-WINAPI
-ImpersonateSecurityContext(
-       PCtxtHandle phContext
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+        list_add_tail(&packageTable->table, &package->entry);
 
-SECURITY_STATUS
-WINAPI
-ImportSecurityContextA(
-       SEC_CHAR *pszPackage,
-       PSecBuffer pPackedContext,
-       LPVOID Token,
-       PCtxtHandle phContext
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+        package->provider = provider;
+        _copyPackageInfo(&package->infoW,
+            infoA ? &infoA[i] : NULL,
+            infoW ? &infoW[i] : NULL);
+    }
+    packageTable->numPackages += toAdd;
+
+    LeaveCriticalSection(&cs);
 }
 
-SECURITY_STATUS
-WINAPI
-ImportSecurityContextW(
-       SEC_WCHAR *pszPackage,
-       PSecBuffer pPackedContext,
-       LPVOID Token,
-       PCtxtHandle phContext
-)
+static void _tryLoadProvider(PWSTR moduleName)
 {
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+    HMODULE lib = LoadLibraryW(moduleName);
+
+    if (lib)
+    {
+        INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
+         (INIT_SECURITY_INTERFACE_W)GetProcAddress(lib,
+         SECURITY_ENTRYPOINT_ANSIW);
+        INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
+         (INIT_SECURITY_INTERFACE_A)GetProcAddress(lib,
+         SECURITY_ENTRYPOINT_ANSIA);
+
+        TRACE("loaded %S, InitSecurityInterfaceA is %p, InitSecurityInterfaceW is %p\n",
+         moduleName, pInitSecurityInterfaceA,
+         pInitSecurityInterfaceW);
+        if (pInitSecurityInterfaceW || pInitSecurityInterfaceA)
+        {
+            PSecurityFunctionTableA fnTableA = NULL;
+            PSecurityFunctionTableW fnTableW = NULL;
+            ULONG toAdd = 0;
+            PSecPkgInfoA infoA = NULL;
+            PSecPkgInfoW infoW = NULL;
+            SECURITY_STATUS ret = SEC_E_OK;
+
+            if (pInitSecurityInterfaceA)
+                fnTableA = pInitSecurityInterfaceA();
+            if (pInitSecurityInterfaceW)
+                fnTableW = pInitSecurityInterfaceW();
+            if (fnTableW && fnTableW->EnumerateSecurityPackagesW)
+            {
+                if (fnTableW != &securityFunctionTableW)
+                    ret = fnTableW->EnumerateSecurityPackagesW(&toAdd, &infoW);
+                else
+                    TRACE("%S has built-in providers, skip adding\n", moduleName);
+            }
+            else if (fnTableA && fnTableA->EnumerateSecurityPackagesA)
+            {
+                if (fnTableA != &securityFunctionTableA)
+                    ret = fnTableA->EnumerateSecurityPackagesA(&toAdd, &infoA);
+                else
+                    TRACE("%S has built-in providers, skip adding\n", moduleName);
+            }
+            if (ret == SEC_E_OK && toAdd > 0 && (infoW || infoA))
+            {
+                SecureProvider *provider = SECUR32_addProvider(NULL, NULL,
+                 moduleName);
+
+                if (provider)
+                    SECUR32_addPackages(provider, toAdd, infoA, infoW);
+                if (infoW)
+                    fnTableW->FreeContextBuffer(infoW);
+                else
+                    fnTableA->FreeContextBuffer(infoA);
+            }
+        }
+        FreeLibrary(lib);
+    }
+    else
+        WARN("failed to load %S\n", moduleName);
 }
 
-SECURITY_STATUS
-WINAPI
-QueryCredentialsAttributesA(
-       PCredHandle phCredential,
-       ULONG ulAttribute,
-       LPVOID pBuffer
-)
+static const WCHAR securityProvidersKeyW[] = {
+ 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
+ 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','S','e','c','u','r',
+ 'i','t','y','P','r','o','v','i','d','e','r','s','\0'
+ };
+static const WCHAR securityProvidersW[] = {
+ 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s',0
+ };
+
+static void SECUR32_initializeProviders(void)
 {
-       UNIMPLEMENTED;
+    HKEY key;
+    LSTATUS apiRet;
 
-       if (phCredential)
-       {
-               pBuffer = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
+    /* Now load providers from registry */
+    apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
+     KEY_READ, &key);
+    if (apiRet == ERROR_SUCCESS)
+    {
+        WCHAR securityPkgNames[MAX_PATH]; /* arbitrary len */
+        DWORD size = sizeof(securityPkgNames) / sizeof(WCHAR), type;
 
-       return SEC_E_INVALID_HANDLE;
+        apiRet = RegQueryValueExW(key, securityProvidersW, NULL, &type,
+         (PBYTE)securityPkgNames, &size);
+        if (apiRet == ERROR_SUCCESS && type == REG_SZ)
+        {
+            WCHAR *ptr;
+
+            size = size / sizeof(WCHAR);
+            for (ptr = securityPkgNames;
+              ptr < securityPkgNames + size; )
+            {
+                WCHAR *comma;
+
+                for (comma = ptr; *comma && *comma != ','; comma++)
+                    ;
+                if (*comma == ',')
+                    *comma = '\0';
+                for (; *ptr && isspace(*ptr) && ptr < securityPkgNames + size;
+                 ptr++)
+                    ;
+                if (*ptr)
+                    _tryLoadProvider(ptr);
+                ptr += lstrlenW(ptr) + 1;
+            }
+        }
+        RegCloseKey(key);
+    }
 }
 
-SECURITY_STATUS
-WINAPI
-QueryCredentialsAttributesW(
-       PCredHandle phCredential,
-       ULONG ulAttribute,
-       LPVOID pBuffer
-)
+SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
 {
-       UNIMPLEMENTED;
+    SecurePackage *ret = NULL;
+    BOOL matched = FALSE;
 
-       if (phCredential)
-       {
-               pBuffer = NULL;
-               return ERROR_CALL_NOT_IMPLEMENTED;
-       }
+    if (!packageTable)
+        SECUR32_initializeProviders();
 
-       return SEC_E_INVALID_HANDLE;
-}
+    if (packageTable && packageName)
+    {
+        LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
+        {
+            matched = !lstrcmpiW(ret->infoW.Name, packageName);
+            if (matched)
+                break;
+        }
 
-SECURITY_STATUS
-WINAPI
-QuerySecurityContextToken(
-       PCtxtHandle phContext,
-       PHANDLE phToken
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
-}
+        if (!matched)
+            return NULL;
 
-SECURITY_STATUS
-WINAPI
-RevertSecurityContext(
-       PCtxtHandle phContext
-)
-{
-       UNIMPLEMENTED;
-       return ERROR_CALL_NOT_IMPLEMENTED;
+        if (ret->provider && !ret->provider->loaded)
+        {
+            ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
+            if (ret->provider->lib)
+            {
+                INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
+                    (INIT_SECURITY_INTERFACE_W) GetProcAddress(ret->provider->lib,
+                    SECURITY_ENTRYPOINT_ANSIW);
+                INIT_SECURITY_INTERFACE_A pInitSecurityInterfaceA =
+                    (INIT_SECURITY_INTERFACE_A) GetProcAddress(ret->provider->lib,
+                    SECURITY_ENTRYPOINT_ANSIA);
+                PSecurityFunctionTableA fnTableA = NULL;
+                PSecurityFunctionTableW fnTableW = NULL;
+
+                if (pInitSecurityInterfaceA)
+                    fnTableA = pInitSecurityInterfaceA();
+                if (pInitSecurityInterfaceW)
+                    fnTableW = pInitSecurityInterfaceW();
+                /* don't update built-in SecurityFunctionTable */
+                if (fnTableA != &securityFunctionTableA)
+                    _makeFnTableA(&ret->provider->fnTableA, fnTableA, fnTableW);
+                if (fnTableW != &securityFunctionTableW)
+                    _makeFnTableW(&ret->provider->fnTableW, fnTableA, fnTableW);
+                ret->provider->loaded = TRUE;
+            }
+            else
+                ret = NULL;
+        }
+    }
+    return ret;
 }
 
-PSecurityFunctionTableA
-WINAPI
-InitSecurityInterfaceA(VOID)
+SecurePackage *SECUR32_findPackageA(PCSTR packageName)
 {
-    DPRINT("InitSecurityInterfaceA() called\n");
-    return &securityFunctionTableA;
-}
+    SecurePackage *ret;
 
-BOOLEAN
-WINAPI
-TranslateNameA(
-       LPCSTR lpAccountName,
-       EXTENDED_NAME_FORMAT AccountNameFormat,
-       EXTENDED_NAME_FORMAT DesiredNameFormat,
-       LPSTR lpTranslatedName,
-       PULONG nSize
-)
-{
-       UNIMPLEMENTED;
-       return FALSE;
-}
+    if (packageName)
+    {
+        UNICODE_STRING package;
 
-BOOLEAN
-WINAPI
-TranslateNameW(
-       LPCWSTR lpAccountName,
-       EXTENDED_NAME_FORMAT AccountNameFormat,
-       EXTENDED_NAME_FORMAT DesiredNameFormat,
-       LPWSTR lpTranslatedName,
-       PULONG nSize
-)
-{
-       UNIMPLEMENTED;
-       return FALSE;
+        RtlCreateUnicodeStringFromAsciiz(&package, packageName);
+        ret = SECUR32_findPackageW(package.Buffer);
+        RtlFreeUnicodeString(&package);
+    }
+    else
+        ret = NULL;
+    return ret;
 }
diff --git a/reactos/dll/win32/secur32/thunks.c b/reactos/dll/win32/secur32/thunks.c
new file mode 100644 (file)
index 0000000..6fc7258
--- /dev/null
@@ -0,0 +1,893 @@
+/* Copyright (C) 2004 Juan Lang
+ *
+ * This file implements thunks between wide char and multibyte functions for
+ * SSPs that only provide one or the other.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "precomp.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+
+SECURITY_STATUS SEC_ENTRY thunk_AcquireCredentialsHandleA(
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialsUse,
+ PLUID pvLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%s %s %d %p %p %p %p %p %p\n", debugstr_a(pszPrincipal),
+     debugstr_a(pszPackage), fCredentialsUse, pvLogonID, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, phCredential, ptsExpiry);
+    if (pszPackage)
+    {
+        UNICODE_STRING principal, package;
+
+        RtlCreateUnicodeStringFromAsciiz(&principal, pszPrincipal);
+        RtlCreateUnicodeStringFromAsciiz(&package, pszPackage);
+        ret = AcquireCredentialsHandleW(principal.Buffer, package.Buffer,
+         fCredentialsUse, pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument,
+         phCredential, ptsExpiry);
+        RtlFreeUnicodeString(&principal);
+        RtlFreeUnicodeString(&package);
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_AcquireCredentialsHandleW(
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialsUse,
+ PLUID pvLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%s %s %d %p %p %p %p %p %p\n", debugstr_w(pszPrincipal),
+     debugstr_w(pszPackage), fCredentialsUse, pvLogonID, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, phCredential, ptsExpiry);
+    if (pszPackage)
+    {
+        PSTR principal, package;
+
+        principal = SECUR32_AllocMultiByteFromWide(pszPrincipal);
+        package = SECUR32_AllocMultiByteFromWide(pszPackage);
+        ret = AcquireCredentialsHandleA(principal, package, fCredentialsUse,
+         pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential,
+         ptsExpiry);
+        HeapFree(GetProcessHeap(), 0, principal);
+        HeapFree(GetProcessHeap(), 0, package);
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+/* thunking is pretty dicey for these--the output type depends on ulAttribute,
+ * so we have to know about every type the caller does
+ */
+SECURITY_STATUS SEC_ENTRY thunk_QueryCredentialsAttributesA(
+ PCredHandle phCredential, ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phCredential, ulAttribute, pBuffer);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+        PCredHandle cred = (PCredHandle)phCredential->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.QueryCredentialsAttributesW)
+            {
+                ret = package->provider->fnTableW.QueryCredentialsAttributesW(
+                 cred, ulAttribute, pBuffer);
+                if (ret == SEC_E_OK)
+                {
+                    switch (ulAttribute)
+                    {
+                        case SECPKG_CRED_ATTR_NAMES:
+                        {
+                            PSecPkgCredentials_NamesW names =
+                             (PSecPkgCredentials_NamesW)pBuffer;
+                            SEC_WCHAR *oldUser = names->sUserName;
+
+                            if (oldUser)
+                            {
+                                names->sUserName =
+                                 (PWSTR)SECUR32_AllocMultiByteFromWide(oldUser);
+                                package->provider->fnTableW.FreeContextBuffer(
+                                 oldUser);
+                            }
+                            break;
+                        }
+                        default:
+                            WARN("attribute type %d unknown\n", ulAttribute);
+                            ret = SEC_E_INTERNAL_ERROR;
+                    }
+                }
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_QueryCredentialsAttributesW(
+ PCredHandle phCredential, ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phCredential, ulAttribute, pBuffer);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+        PCredHandle cred = (PCredHandle)phCredential->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.QueryCredentialsAttributesA)
+            {
+                ret = package->provider->fnTableA.QueryCredentialsAttributesA(
+                 cred, ulAttribute, pBuffer);
+                if (ret == SEC_E_OK)
+                {
+                    switch (ulAttribute)
+                    {
+                        case SECPKG_CRED_ATTR_NAMES:
+                        {
+                            PSecPkgCredentials_NamesA names =
+                             (PSecPkgCredentials_NamesA)pBuffer;
+                            SEC_CHAR *oldUser = names->sUserName;
+
+                            if (oldUser)
+                            {
+                                names->sUserName =
+                                 (PSTR)SECUR32_AllocWideFromMultiByte(oldUser);
+                                package->provider->fnTableA.FreeContextBuffer(
+                                 oldUser);
+                            }
+                            break;
+                        }
+                        default:
+                            WARN("attribute type %d unknown\n", ulAttribute);
+                            ret = SEC_E_INTERNAL_ERROR;
+                    }
+                }
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_InitializeSecurityContextA(
+ PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_CHAR *pszTargetName, ULONG fContextReq,
+ ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,
+ ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput,
+ ULONG *pfContextAttr, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
+     debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
+     Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.InitializeSecurityContextW)
+            {
+                UNICODE_STRING target;
+
+                RtlCreateUnicodeStringFromAsciiz(&target, pszTargetName);
+                ret = package->provider->fnTableW.InitializeSecurityContextW(
+                 phCredential, phContext, target.Buffer, fContextReq, Reserved1,
+                 TargetDataRep, pInput, Reserved2, phNewContext, pOutput,
+                 pfContextAttr, ptsExpiry);
+                RtlFreeUnicodeString(&target);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_InitializeSecurityContextW(
+ PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_WCHAR *pszTargetName, ULONG fContextReq,
+ ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,
+ ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput,
+ ULONG *pfContextAttr, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
+     debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
+     Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.InitializeSecurityContextA)
+            {
+                PSTR target = SECUR32_AllocMultiByteFromWide(pszTargetName);
+
+                ret = package->provider->fnTableA.InitializeSecurityContextA(
+                 phCredential, phContext, target, fContextReq, Reserved1,
+                 TargetDataRep, pInput, Reserved2, phNewContext, pOutput,
+                 pfContextAttr, ptsExpiry);
+                HeapFree(GetProcessHeap(), 0, target);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_AddCredentialsA(PCredHandle hCredentials,
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
+ void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %s %s %d %p %p %p %p\n", hCredentials, debugstr_a(pszPrincipal),
+     debugstr_a(pszPackage), fCredentialUse, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, ptsExpiry);
+    if (hCredentials)
+    {
+        SecurePackage *package = (SecurePackage *)hCredentials->dwUpper;
+        PCredHandle cred = (PCtxtHandle)hCredentials->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.AddCredentialsW)
+            {
+                UNICODE_STRING szPrincipal, szPackage;
+
+                RtlCreateUnicodeStringFromAsciiz(&szPrincipal, pszPrincipal);
+                RtlCreateUnicodeStringFromAsciiz(&szPackage, pszPackage);
+                ret = package->provider->fnTableW.AddCredentialsW(
+                 cred, szPrincipal.Buffer, szPackage.Buffer, fCredentialUse,
+                 pAuthData, pGetKeyFn, pvGetKeyArgument, ptsExpiry);
+                RtlFreeUnicodeString(&szPrincipal);
+                RtlFreeUnicodeString(&szPackage);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_AddCredentialsW(PCredHandle hCredentials,
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
+ void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %s %s %d %p %p %p %p\n", hCredentials, debugstr_w(pszPrincipal),
+     debugstr_w(pszPackage), fCredentialUse, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, ptsExpiry);
+    if (hCredentials)
+    {
+        SecurePackage *package = (SecurePackage *)hCredentials->dwUpper;
+        PCredHandle cred = (PCtxtHandle)hCredentials->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.AddCredentialsA)
+            {
+                PSTR szPrincipal = SECUR32_AllocMultiByteFromWide(pszPrincipal);
+                PSTR szPackage = SECUR32_AllocMultiByteFromWide(pszPackage);
+
+                ret = package->provider->fnTableA.AddCredentialsA(
+                 cred, szPrincipal, szPackage, fCredentialUse, pAuthData,
+                 pGetKeyFn, pvGetKeyArgument, ptsExpiry);
+                HeapFree(GetProcessHeap(), 0, szPrincipal);
+                HeapFree(GetProcessHeap(), 0, szPackage);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+static PSecPkgInfoA _copyPackageInfoFlatWToA(const SecPkgInfoW *infoW)
+{
+    PSecPkgInfoA ret;
+
+    if (infoW)
+    {
+        size_t bytesNeeded = sizeof(SecPkgInfoA);
+        int nameLen = 0, commentLen = 0;
+
+        if (infoW->Name)
+        {
+            nameLen = WideCharToMultiByte(CP_ACP, 0, infoW->Name, -1,
+             NULL, 0, NULL, NULL);
+            bytesNeeded += nameLen;
+        }
+        if (infoW->Comment)
+        {
+            commentLen = WideCharToMultiByte(CP_ACP, 0, infoW->Comment, -1,
+             NULL, 0, NULL, NULL);
+            bytesNeeded += commentLen;
+        }
+        ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
+        if (ret)
+        {
+            PSTR nextString = (PSTR)((PBYTE)ret + sizeof(SecPkgInfoA));
+
+            memcpy(ret, infoW, sizeof(SecPkgInfoA));
+            if (infoW->Name)
+            {
+                ret->Name = nextString;
+                WideCharToMultiByte(CP_ACP, 0, infoW->Name, -1, nextString,
+                 nameLen, NULL, NULL);
+                nextString += nameLen;
+            }
+            else
+                ret->Name = NULL;
+            if (infoW->Comment)
+            {
+                ret->Comment = nextString;
+                WideCharToMultiByte(CP_ACP, 0, infoW->Comment, -1, nextString,
+                 nameLen, NULL, NULL);
+            }
+            else
+                ret->Comment = NULL;
+        }
+    }
+    else
+        ret = NULL;
+    return ret;
+}
+
+static SECURITY_STATUS thunk_ContextAttributesWToA(SecurePackage *package,
+ ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret = SEC_E_OK;
+
+    if (package && pBuffer)
+    {
+        switch (ulAttribute)
+        {
+            case SECPKG_ATTR_NAMES:
+            {
+                PSecPkgContext_NamesW names = (PSecPkgContext_NamesW)pBuffer;
+                SEC_WCHAR *oldUser = names->sUserName;
+
+                if (oldUser)
+                {
+                    names->sUserName =
+                     (PWSTR)SECUR32_AllocMultiByteFromWide(oldUser);
+                    package->provider->fnTableW.FreeContextBuffer(oldUser);
+                }
+                break;
+            }
+            case SECPKG_ATTR_AUTHORITY:
+            {
+                PSecPkgContext_AuthorityW names =
+                 (PSecPkgContext_AuthorityW)pBuffer;
+                SEC_WCHAR *oldAuth = names->sAuthorityName;
+
+                if (oldAuth)
+                {
+                    names->sAuthorityName =
+                     (PWSTR)SECUR32_AllocMultiByteFromWide(oldAuth);
+                    package->provider->fnTableW.FreeContextBuffer(oldAuth);
+                }
+                break;
+            }
+            case SECPKG_ATTR_KEY_INFO:
+            {
+                PSecPkgContext_KeyInfoW info = (PSecPkgContext_KeyInfoW)pBuffer;
+                SEC_WCHAR *oldSigAlgName = info->sSignatureAlgorithmName;
+                SEC_WCHAR *oldEncAlgName = info->sEncryptAlgorithmName;
+
+                if (oldSigAlgName)
+                {
+                    info->sSignatureAlgorithmName =
+                     (PWSTR)SECUR32_AllocMultiByteFromWide(oldSigAlgName);
+                    package->provider->fnTableW.FreeContextBuffer(
+                     oldSigAlgName);
+                }
+                if (oldEncAlgName)
+                {
+                    info->sEncryptAlgorithmName =
+                     (PWSTR)SECUR32_AllocMultiByteFromWide(oldEncAlgName);
+                    package->provider->fnTableW.FreeContextBuffer(
+                     oldEncAlgName);
+                }
+                break;
+            }
+            case SECPKG_ATTR_PACKAGE_INFO:
+            {
+                PSecPkgContext_PackageInfoW info =
+                 (PSecPkgContext_PackageInfoW)pBuffer;
+                PSecPkgInfoW oldPkgInfo = info->PackageInfo;
+
+                if (oldPkgInfo)
+                {
+                    info->PackageInfo = (PSecPkgInfoW)
+                     _copyPackageInfoFlatWToA(oldPkgInfo);
+                    package->provider->fnTableW.FreeContextBuffer(oldPkgInfo);
+                }
+                break;
+            }
+            case SECPKG_ATTR_NEGOTIATION_INFO:
+            {
+                PSecPkgContext_NegotiationInfoW info =
+                 (PSecPkgContext_NegotiationInfoW)pBuffer;
+                PSecPkgInfoW oldPkgInfo = info->PackageInfo;
+
+                if (oldPkgInfo)
+                {
+                    info->PackageInfo = (PSecPkgInfoW)
+                     _copyPackageInfoFlatWToA(oldPkgInfo);
+                    package->provider->fnTableW.FreeContextBuffer(oldPkgInfo);
+                }
+                break;
+            }
+            case SECPKG_ATTR_NATIVE_NAMES:
+            {
+                PSecPkgContext_NativeNamesW names =
+                 (PSecPkgContext_NativeNamesW)pBuffer;
+                PWSTR oldClient = names->sClientName;
+                PWSTR oldServer = names->sServerName;
+
+                if (oldClient)
+                {
+                    names->sClientName = (PWSTR)SECUR32_AllocMultiByteFromWide(
+                     oldClient);
+                    package->provider->fnTableW.FreeContextBuffer(oldClient);
+                }
+                if (oldServer)
+                {
+                    names->sServerName = (PWSTR)SECUR32_AllocMultiByteFromWide(
+                     oldServer);
+                    package->provider->fnTableW.FreeContextBuffer(oldServer);
+                }
+                break;
+            }
+            case SECPKG_ATTR_CREDENTIAL_NAME:
+            {
+                PSecPkgContext_CredentialNameW name =
+                 (PSecPkgContext_CredentialNameW)pBuffer;
+                PWSTR oldCred = name->sCredentialName;
+
+                if (oldCred)
+                {
+                    name->sCredentialName =
+                     (PWSTR)SECUR32_AllocMultiByteFromWide(oldCred);
+                    package->provider->fnTableW.FreeContextBuffer(oldCred);
+                }
+                break;
+            }
+            /* no thunking needed: */
+            case SECPKG_ATTR_ACCESS_TOKEN:
+            case SECPKG_ATTR_DCE_INFO:
+            case SECPKG_ATTR_FLAGS:
+            case SECPKG_ATTR_LIFESPAN:
+            case SECPKG_ATTR_PASSWORD_EXPIRY:
+            case SECPKG_ATTR_SESSION_KEY:
+            case SECPKG_ATTR_SIZES:
+            case SECPKG_ATTR_STREAM_SIZES:
+            case SECPKG_ATTR_TARGET_INFORMATION:
+                break;
+            default:
+                WARN("attribute type %d unknown\n", ulAttribute);
+                ret = SEC_E_INTERNAL_ERROR;
+        }
+    }
+    else
+        ret = SEC_E_INVALID_TOKEN;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_QueryContextAttributesA(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.QueryContextAttributesW)
+            {
+                ret = package->provider->fnTableW.QueryContextAttributesW(
+                 ctxt, ulAttribute, pBuffer);
+                if (ret == SEC_E_OK)
+                    ret = thunk_ContextAttributesWToA(package, ulAttribute,
+                     pBuffer);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+static PSecPkgInfoW _copyPackageInfoFlatAToW(const SecPkgInfoA *infoA)
+{
+    PSecPkgInfoW ret;
+
+    if (infoA)
+    {
+        size_t bytesNeeded = sizeof(SecPkgInfoW);
+        int nameLen = 0, commentLen = 0;
+
+        if (infoA->Name)
+        {
+            nameLen = MultiByteToWideChar(CP_ACP, 0, infoA->Name, -1,
+             NULL, 0);
+            bytesNeeded += nameLen * sizeof(WCHAR);
+        }
+        if (infoA->Comment)
+        {
+            commentLen = MultiByteToWideChar(CP_ACP, 0, infoA->Comment, -1,
+             NULL, 0);
+            bytesNeeded += commentLen * sizeof(WCHAR);
+        }
+        ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
+        if (ret)
+        {
+            PWSTR nextString = (PWSTR)((PBYTE)ret + sizeof(SecPkgInfoW));
+
+            memcpy(ret, infoA, sizeof(SecPkgInfoA));
+            if (infoA->Name)
+            {
+                ret->Name = nextString;
+                MultiByteToWideChar(CP_ACP, 0, infoA->Name, -1, nextString,
+                 nameLen);
+                nextString += nameLen;
+            }
+            else
+                ret->Name = NULL;
+            if (infoA->Comment)
+            {
+                ret->Comment = nextString;
+                MultiByteToWideChar(CP_ACP, 0, infoA->Comment, -1, nextString,
+                 commentLen);
+            }
+            else
+                ret->Comment = NULL;
+        }
+    }
+    else
+        ret = NULL;
+    return ret;
+}
+
+static SECURITY_STATUS thunk_ContextAttributesAToW(SecurePackage *package,
+ ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret = SEC_E_OK;
+
+    if (package && pBuffer)
+    {
+        switch (ulAttribute)
+        {
+            case SECPKG_ATTR_NAMES:
+            {
+                PSecPkgContext_NamesA names = (PSecPkgContext_NamesA)pBuffer;
+                SEC_CHAR *oldUser = names->sUserName;
+
+                if (oldUser)
+                {
+                    names->sUserName =
+                     (PSTR)SECUR32_AllocWideFromMultiByte(oldUser);
+                    package->provider->fnTableW.FreeContextBuffer(oldUser);
+                }
+                break;
+            }
+            case SECPKG_ATTR_AUTHORITY:
+            {
+                PSecPkgContext_AuthorityA names =
+                 (PSecPkgContext_AuthorityA)pBuffer;
+                SEC_CHAR *oldAuth = names->sAuthorityName;
+
+                if (oldAuth)
+                {
+                    names->sAuthorityName =
+                     (PSTR)SECUR32_AllocWideFromMultiByte(oldAuth);
+                    package->provider->fnTableW.FreeContextBuffer(oldAuth);
+                }
+                break;
+            }
+            case SECPKG_ATTR_KEY_INFO:
+            {
+                PSecPkgContext_KeyInfoA info = (PSecPkgContext_KeyInfoA)pBuffer;
+                SEC_CHAR *oldSigAlgName = info->sSignatureAlgorithmName;
+                SEC_CHAR *oldEncAlgName = info->sEncryptAlgorithmName;
+
+                if (oldSigAlgName)
+                {
+                    info->sSignatureAlgorithmName =
+                     (PSTR)SECUR32_AllocWideFromMultiByte(oldSigAlgName);
+                    package->provider->fnTableW.FreeContextBuffer(
+                     oldSigAlgName);
+                }
+                if (oldEncAlgName)
+                {
+                    info->sEncryptAlgorithmName =
+                     (PSTR)SECUR32_AllocWideFromMultiByte(
+                     oldEncAlgName);
+                    package->provider->fnTableW.FreeContextBuffer(
+                     oldEncAlgName);
+                }
+                break;
+            }
+            case SECPKG_ATTR_PACKAGE_INFO:
+            {
+                PSecPkgContext_PackageInfoA info =
+                 (PSecPkgContext_PackageInfoA)pBuffer;
+                PSecPkgInfoA oldPkgInfo = info->PackageInfo;
+
+                if (oldPkgInfo)
+                {
+                    info->PackageInfo = (PSecPkgInfoA)
+                     _copyPackageInfoFlatAToW(oldPkgInfo);
+                    package->provider->fnTableW.FreeContextBuffer(oldPkgInfo);
+                }
+                break;
+            }
+            case SECPKG_ATTR_NEGOTIATION_INFO:
+            {
+                PSecPkgContext_NegotiationInfoA info =
+                 (PSecPkgContext_NegotiationInfoA)pBuffer;
+                PSecPkgInfoA oldPkgInfo = info->PackageInfo;
+
+                if (oldPkgInfo)
+                {
+                    info->PackageInfo = (PSecPkgInfoA)
+                     _copyPackageInfoFlatAToW(oldPkgInfo);
+                    package->provider->fnTableW.FreeContextBuffer(oldPkgInfo);
+                }
+                break;
+            }
+            case SECPKG_ATTR_NATIVE_NAMES:
+            {
+                PSecPkgContext_NativeNamesA names =
+                 (PSecPkgContext_NativeNamesA)pBuffer;
+                PSTR oldClient = names->sClientName;
+                PSTR oldServer = names->sServerName;
+
+                if (oldClient)
+                {
+                    names->sClientName = (PSTR)SECUR32_AllocWideFromMultiByte(
+                     oldClient);
+                    package->provider->fnTableW.FreeContextBuffer(oldClient);
+                }
+                if (oldServer)
+                {
+                    names->sServerName = (PSTR)SECUR32_AllocWideFromMultiByte(
+                     oldServer);
+                    package->provider->fnTableW.FreeContextBuffer(oldServer);
+                }
+                break;
+            }
+            case SECPKG_ATTR_CREDENTIAL_NAME:
+            {
+                PSecPkgContext_CredentialNameA name =
+                 (PSecPkgContext_CredentialNameA)pBuffer;
+                PSTR oldCred = name->sCredentialName;
+
+                if (oldCred)
+                {
+                    name->sCredentialName =
+                     (PSTR)SECUR32_AllocWideFromMultiByte(oldCred);
+                    package->provider->fnTableW.FreeContextBuffer(oldCred);
+                }
+                break;
+            }
+            /* no thunking needed: */
+            case SECPKG_ATTR_ACCESS_TOKEN:
+            case SECPKG_ATTR_DCE_INFO:
+            case SECPKG_ATTR_FLAGS:
+            case SECPKG_ATTR_LIFESPAN:
+            case SECPKG_ATTR_PASSWORD_EXPIRY:
+            case SECPKG_ATTR_SESSION_KEY:
+            case SECPKG_ATTR_SIZES:
+            case SECPKG_ATTR_STREAM_SIZES:
+            case SECPKG_ATTR_TARGET_INFORMATION:
+                break;
+            default:
+                WARN("attribute type %d unknown\n", ulAttribute);
+                ret = SEC_E_INTERNAL_ERROR;
+        }
+    }
+    else
+        ret = SEC_E_INVALID_TOKEN;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_QueryContextAttributesW(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.QueryContextAttributesA)
+            {
+                ret = package->provider->fnTableA.QueryContextAttributesA(
+                 ctxt, ulAttribute, pBuffer);
+                if (ret == SEC_E_OK)
+                    ret = thunk_ContextAttributesAToW(package, ulAttribute,
+                     pBuffer);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_SetContextAttributesA(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer, ULONG cbBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %d\n", phContext, ulAttribute, pBuffer, cbBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider && pBuffer && cbBuffer)
+        {
+            if (package->provider->fnTableW.SetContextAttributesW)
+            {
+                /* TODO: gotta validate size too! */
+                ret = thunk_ContextAttributesWToA(package, ulAttribute,
+                 pBuffer);
+                if (ret == SEC_E_OK)
+                    ret = package->provider->fnTableW.SetContextAttributesW(
+                     ctxt, ulAttribute, pBuffer, cbBuffer);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_SetContextAttributesW(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer, ULONG cbBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %d\n", phContext, ulAttribute, pBuffer, cbBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider && pBuffer && cbBuffer)
+        {
+            if (package->provider->fnTableA.SetContextAttributesA)
+            {
+                /* TODO: gotta validate size too! */
+                ret = thunk_ContextAttributesAToW(package, ulAttribute,
+                 pBuffer);
+                if (ret == SEC_E_OK)
+                    ret = package->provider->fnTableA.SetContextAttributesA(
+                     ctxt, ulAttribute, pBuffer, cbBuffer);
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_ImportSecurityContextA(
+ SEC_CHAR *pszPackage, PSecBuffer pPackedContext, void *Token,
+ PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+    UNICODE_STRING package;
+
+    TRACE("%s %p %p %p\n", debugstr_a(pszPackage), pPackedContext, Token,
+     phContext);
+    RtlCreateUnicodeStringFromAsciiz(&package, pszPackage);
+    ret = ImportSecurityContextW(package.Buffer, pPackedContext, Token,
+     phContext);
+    RtlFreeUnicodeString(&package);
+    return ret;
+}
+
+SECURITY_STATUS SEC_ENTRY thunk_ImportSecurityContextW(
+ SEC_WCHAR *pszPackage, PSecBuffer pPackedContext, void *Token,
+ PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+    PSTR package = SECUR32_AllocMultiByteFromWide(pszPackage);
+
+    TRACE("%s %p %p %p\n", debugstr_w(pszPackage), pPackedContext, Token,
+     phContext);
+    ret = ImportSecurityContextA(package, pPackedContext, Token, phContext);
+    HeapFree(GetProcessHeap(), 0, package);
+    return ret;
+}
+
diff --git a/reactos/dll/win32/secur32/thunks.h b/reactos/dll/win32/secur32/thunks.h
new file mode 100644 (file)
index 0000000..7c3171e
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2004 Juan Lang
+ *
+ * This file defines thunks between wide char and multibyte functions for
+ * SSPs that only provide one or the other.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __SECUR32_THUNKS_H__
+#define __SECUR32_THUNKS_H__
+
+/* Prototypes for functions that thunk between wide char and multibyte versions,
+ * for SSPs that only provide one or the other.
+ */
+SECURITY_STATUS SEC_ENTRY thunk_AcquireCredentialsHandleA(
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialsUse,
+ PLUID pvLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_AcquireCredentialsHandleW(
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialsUse,
+ PLUID pvLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_InitializeSecurityContextA(
+ PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_CHAR *pszTargetName, ULONG fContextReq,
+ ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,
+ ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput,
+ ULONG *pfContextAttr, PTimeStamp ptsExpiry) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_InitializeSecurityContextW(
+ PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_WCHAR *pszTargetName, ULONG fContextReq,
+ ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,
+ ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput,
+ ULONG *pfContextAttr, PTimeStamp ptsExpiry) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_ImportSecurityContextA(
+ SEC_CHAR *pszPackage, PSecBuffer pPackedContext, void *Token,
+ PCtxtHandle phContext) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_ImportSecurityContextW(
+ SEC_WCHAR *pszPackage, PSecBuffer pPackedContext, void *Token,
+ PCtxtHandle phContext) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_AddCredentialsA(PCredHandle hCredentials,
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
+ void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PTimeStamp ptsExpiry) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_AddCredentialsW(PCredHandle hCredentials,
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
+ void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PTimeStamp ptsExpiry) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_QueryCredentialsAttributesA(
+ PCredHandle phCredential, ULONG ulAttribute, void *pBuffer) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_QueryCredentialsAttributesW(
+ PCredHandle phCredential, ULONG ulAttribute, void *pBuffer) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_QueryContextAttributesA(
+ PCtxtHandle phContext, ULONG ulAttribute, void *pBuffer) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_QueryContextAttributesW(
+ PCtxtHandle phContext, ULONG ulAttribute, void *pBuffer) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_SetContextAttributesA(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer, ULONG cbBuffer) DECLSPEC_HIDDEN;
+SECURITY_STATUS SEC_ENTRY thunk_SetContextAttributesW(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer, ULONG cbBuffer) DECLSPEC_HIDDEN;
+
+#endif /* ndef __SECUR32_THUNKS_H__ */
diff --git a/reactos/dll/win32/secur32/wrapper.c b/reactos/dll/win32/secur32/wrapper.c
new file mode 100644 (file)
index 0000000..882144c
--- /dev/null
@@ -0,0 +1,1121 @@
+/* Copyright (C) 2004 Juan Lang
+ *
+ * Implements secur32 functions that forward to (wrap) an SSP's implementation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "precomp.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+
+/* Tries to allocate a new SecHandle, into which it stores package (in
+ * phSec->dwUpper) and a copy of realHandle (allocated with SECUR32_ALLOC,
+ * and stored in phSec->dwLower).  SecHandle is equivalent to both a
+ * CredHandle and a CtxtHandle.
+ */
+static SECURITY_STATUS SECUR32_makeSecHandle(PSecHandle phSec,
+ SecurePackage *package, PSecHandle realHandle)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p %p\n", phSec, package, realHandle);
+
+    if (phSec && package && realHandle)
+    {
+        PSecHandle newSec = HeapAlloc(GetProcessHeap(), 0, sizeof(SecHandle));
+
+        if (newSec)
+        {
+            *newSec = *realHandle;
+            phSec->dwUpper = (ULONG_PTR)package;
+            phSec->dwLower = (ULONG_PTR)newSec;
+            ret = SEC_E_OK;
+        }
+        else
+            ret = SEC_E_INSUFFICIENT_MEMORY;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      AcquireCredentialsHandleA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI AcquireCredentialsHandleA(
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialsUse,
+ PLUID pvLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%s %s %d %p %p %p %p %p %p\n", debugstr_a(pszPrincipal),
+     debugstr_a(pszPackage), fCredentialsUse, pvLogonID, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, phCredential, ptsExpiry);
+    if (pszPackage)
+    {
+        SecurePackage *package = SECUR32_findPackageA(pszPackage);
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.AcquireCredentialsHandleA)
+            {
+                CredHandle myCred;
+
+                ret = package->provider->fnTableA.AcquireCredentialsHandleA(
+                 pszPrincipal, pszPackage, fCredentialsUse, pvLogonID,
+                 pAuthData, pGetKeyFn, pvGetKeyArgument, &myCred,
+                 ptsExpiry);
+                if (ret == SEC_E_OK)
+                {
+                    ret = SECUR32_makeSecHandle(phCredential, package, &myCred);
+                    if (ret != SEC_E_OK)
+                        package->provider->fnTableW.FreeCredentialsHandle(
+                         &myCred);
+                }
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_SECPKG_NOT_FOUND;
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+/***********************************************************************
+ *      AcquireCredentialsHandleW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI AcquireCredentialsHandleW(
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialsUse,
+ PLUID pvLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%s %s %d %p %p %p %p %p %p\n", debugstr_w(pszPrincipal),
+     debugstr_w(pszPackage), fCredentialsUse, pvLogonID, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, phCredential, ptsExpiry);
+    if (pszPackage)
+    {
+        SecurePackage *package = SECUR32_findPackageW(pszPackage);
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.AcquireCredentialsHandleW)
+            {
+                CredHandle myCred;
+
+                ret = package->provider->fnTableW.AcquireCredentialsHandleW(
+                 pszPrincipal, pszPackage, fCredentialsUse, pvLogonID,
+                 pAuthData, pGetKeyFn, pvGetKeyArgument, &myCred,
+                 ptsExpiry);
+                if (ret == SEC_E_OK)
+                {
+                    ret = SECUR32_makeSecHandle(phCredential, package, &myCred);
+                    if (ret != SEC_E_OK)
+                        package->provider->fnTableW.FreeCredentialsHandle(
+                         &myCred);
+                }
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_SECPKG_NOT_FOUND;
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+/***********************************************************************
+ *      FreeCredentialsHandle (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI FreeCredentialsHandle(
+ PCredHandle phCredential)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p\n", phCredential);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+        PCredHandle cred = (PCredHandle)phCredential->dwLower;
+
+        if (package && package->provider &&
+         package->provider->fnTableW.FreeCredentialsHandle)
+            ret = package->provider->fnTableW.FreeCredentialsHandle(cred);
+        else
+            ret = SEC_E_INVALID_HANDLE;
+        HeapFree(GetProcessHeap(), 0, cred);
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      QueryCredentialsAttributesA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QueryCredentialsAttributesA(
+ PCredHandle phCredential, ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phCredential, ulAttribute, pBuffer);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+        PCredHandle cred = (PCredHandle)phCredential->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.QueryCredentialsAttributesA)
+                ret = package->provider->fnTableA.QueryCredentialsAttributesA(
+                 cred, ulAttribute, pBuffer);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      QueryCredentialsAttributesW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QueryCredentialsAttributesW(
+ PCredHandle phCredential, ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phCredential, ulAttribute, pBuffer);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+        PCredHandle cred = (PCredHandle)phCredential->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.QueryCredentialsAttributesW)
+                ret = package->provider->fnTableW.QueryCredentialsAttributesW(
+                 cred, ulAttribute, pBuffer);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      InitializeSecurityContextA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI InitializeSecurityContextA(
+ PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_CHAR *pszTargetName, ULONG fContextReq,
+ ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,
+ ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput,
+ ULONG *pfContextAttr, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+    SecurePackage *package = NULL;
+    PCredHandle cred = NULL;
+    PCredHandle ctxt = NULL;
+
+    TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
+     debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
+     Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+
+    if (phContext)
+    {
+        package = (SecurePackage *)phContext->dwUpper;
+        ctxt = (PCtxtHandle)phContext->dwLower;
+    }
+    if (phCredential)
+    {
+        package = (SecurePackage *)phCredential->dwUpper;
+        cred = (PCredHandle)phCredential->dwLower;
+    }
+
+    if (package && package->provider)
+    {
+        if (package->provider->fnTableA.InitializeSecurityContextA)
+        {
+            CtxtHandle myCtxt;
+
+            if (phContext)
+            {
+                PCtxtHandle realCtxt = (PCtxtHandle)phContext->dwLower;
+                myCtxt.dwUpper = realCtxt->dwUpper;
+                myCtxt.dwLower = realCtxt->dwLower;
+            }
+
+            ret = package->provider->fnTableA.InitializeSecurityContextA(
+                 cred, ctxt, pszTargetName, fContextReq,
+                 Reserved1, TargetDataRep, pInput, Reserved2, phNewContext ? &myCtxt : NULL,
+                 pOutput, pfContextAttr, ptsExpiry);
+            if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) &&
+                phNewContext && phNewContext != phContext)
+            {
+                SECURITY_STATUS ret2;
+                ret2 = SECUR32_makeSecHandle(phNewContext, package, &myCtxt);
+                if (ret2 != SEC_E_OK)
+                    package->provider->fnTableA.DeleteSecurityContext(&myCtxt);
+            }
+        }
+        else
+            ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      InitializeSecurityContextW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI InitializeSecurityContextW(
+ PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_WCHAR *pszTargetName, ULONG fContextReq,
+ ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,
+ ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput,
+ ULONG *pfContextAttr, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+    SecurePackage *package = NULL;
+    PCredHandle cred = NULL;
+    PCredHandle ctxt = NULL;
+
+    TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
+     debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
+     Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+
+    if (phContext)
+    {
+        package = (SecurePackage *)phContext->dwUpper;
+        ctxt = (PCtxtHandle)phContext->dwLower;
+    }
+    if (phCredential)
+    {
+        package = (SecurePackage *)phCredential->dwUpper;
+        cred = (PCredHandle)phCredential->dwLower;
+    }
+
+    if (package && package->provider)
+    {
+        if (package->provider->fnTableW.InitializeSecurityContextW)
+        {
+            CtxtHandle myCtxt;
+
+            if (phContext)
+            {
+                PCtxtHandle realCtxt = (PCtxtHandle)phContext->dwLower;
+                myCtxt.dwUpper = realCtxt->dwUpper;
+                myCtxt.dwLower = realCtxt->dwLower;
+            }
+
+            ret = package->provider->fnTableW.InitializeSecurityContextW(
+                 cred, ctxt, pszTargetName, fContextReq,
+                 Reserved1, TargetDataRep, pInput, Reserved2, phNewContext ? &myCtxt : NULL,
+                 pOutput, pfContextAttr, ptsExpiry);
+            if ((ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) &&
+                phNewContext && phNewContext != phContext)
+            {
+                SECURITY_STATUS ret2;
+                ret2 = SECUR32_makeSecHandle(phNewContext, package, &myCtxt);
+                if (ret2 != SEC_E_OK)
+                    package->provider->fnTableW.DeleteSecurityContext(&myCtxt);
+            }
+        }
+        else
+            ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      AcceptSecurityContext (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI AcceptSecurityContext(
+ PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
+ ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
+ PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput,
+     fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
+     ptsExpiry);
+    if (phCredential)
+    {
+        SecurePackage *package = (SecurePackage *)phCredential->dwUpper;
+        PCredHandle cred = (PCredHandle)phCredential->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.AcceptSecurityContext)
+            {
+                CtxtHandle myCtxt;
+
+                if(phContext)
+                {
+                    PCtxtHandle realCtxt = (PCtxtHandle)phContext->dwLower;
+                    TRACE("realCtx: %p\n", realCtxt);
+                    myCtxt.dwUpper = realCtxt->dwUpper;
+                    myCtxt.dwLower = realCtxt->dwLower;
+                }
+
+                ret = package->provider->fnTableW.AcceptSecurityContext(
+                 cred, phContext ? &myCtxt : NULL, pInput, fContextReq,
+                 TargetDataRep, &myCtxt, pOutput, pfContextAttr, ptsExpiry);
+                if (ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED)
+                {
+                    SECURITY_STATUS ret2;
+                    ret2 = SECUR32_makeSecHandle(phNewContext, package, &myCtxt);
+                    if (ret2 != SEC_E_OK)
+                        package->provider->fnTableW.DeleteSecurityContext(
+                         &myCtxt);
+                }
+            }
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      CompleteAuthToken (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI CompleteAuthToken(PCtxtHandle phContext,
+ PSecBufferDesc pToken)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p\n", phContext, pToken);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.CompleteAuthToken)
+                ret = package->provider->fnTableW.CompleteAuthToken(ctxt,
+                 pToken);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      DeleteSecurityContext (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI DeleteSecurityContext(PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p\n", phContext);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider &&
+         package->provider->fnTableW.DeleteSecurityContext)
+            ret = package->provider->fnTableW.DeleteSecurityContext(ctxt);
+        else
+            ret = SEC_E_INVALID_HANDLE;
+        HeapFree(GetProcessHeap(), 0, ctxt);
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      ApplyControlToken (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI ApplyControlToken(PCtxtHandle phContext,
+ PSecBufferDesc pInput)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p\n", phContext, pInput);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.ApplyControlToken)
+                ret = package->provider->fnTableW.ApplyControlToken(
+                 ctxt, pInput);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      QueryContextAttributesA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QueryContextAttributesA(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.QueryContextAttributesA)
+                ret = package->provider->fnTableA.QueryContextAttributesA(
+                 ctxt, ulAttribute, pBuffer);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      QueryContextAttributesW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QueryContextAttributesW(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.QueryContextAttributesW)
+                ret = package->provider->fnTableW.QueryContextAttributesW(
+                 ctxt, ulAttribute, pBuffer);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      ImpersonateSecurityContext (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI ImpersonateSecurityContext(PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p\n", phContext);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.ImpersonateSecurityContext)
+                ret = package->provider->fnTableW.ImpersonateSecurityContext(
+                 ctxt);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      RevertSecurityContext (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI RevertSecurityContext(PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p\n", phContext);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.RevertSecurityContext)
+                ret = package->provider->fnTableW.RevertSecurityContext(
+                 ctxt);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      MakeSignature (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI MakeSignature(PCtxtHandle phContext, ULONG fQOP,
+ PSecBufferDesc pMessage, ULONG MessageSeqNo)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.MakeSignature)
+                ret = package->provider->fnTableW.MakeSignature(
+                 ctxt, fQOP, pMessage, MessageSeqNo);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      VerifySignature (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI VerifySignature(PCtxtHandle phContext,
+ PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.VerifySignature)
+                ret = package->provider->fnTableW.VerifySignature(
+                 ctxt, pMessage, MessageSeqNo, pfQOP);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      QuerySecurityPackageInfoA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QuerySecurityPackageInfoA(SEC_CHAR *pszPackageName,
+ PSecPkgInfoA *ppPackageInfo)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%s %p\n", debugstr_a(pszPackageName), ppPackageInfo);
+    if (pszPackageName)
+    {
+        SecurePackage *package = SECUR32_findPackageA(pszPackageName);
+
+        if (package)
+        {
+            size_t bytesNeeded = sizeof(SecPkgInfoA);
+            int nameLen = 0, commentLen = 0;
+
+            if (package->infoW.Name)
+            {
+                nameLen = WideCharToMultiByte(CP_ACP, 0,
+                 package->infoW.Name, -1, NULL, 0, NULL, NULL);
+                bytesNeeded += nameLen;
+            }
+            if (package->infoW.Comment)
+            {
+                commentLen = WideCharToMultiByte(CP_ACP, 0,
+                 package->infoW.Comment, -1, NULL, 0, NULL, NULL);
+                bytesNeeded += commentLen;
+            }
+            *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
+            if (*ppPackageInfo)
+            {
+                PSTR nextString = (PSTR)((PBYTE)*ppPackageInfo +
+                 sizeof(SecPkgInfoA));
+
+                memcpy(*ppPackageInfo, &package->infoW, sizeof(package->infoW));
+                if (package->infoW.Name)
+                {
+                    (*ppPackageInfo)->Name = nextString;
+                    nextString += WideCharToMultiByte(CP_ACP, 0,
+                     package->infoW.Name, -1, nextString, nameLen, NULL, NULL);
+                }
+                else
+                    (*ppPackageInfo)->Name = NULL;
+                if (package->infoW.Comment)
+                {
+                    (*ppPackageInfo)->Comment = nextString;
+                    nextString += WideCharToMultiByte(CP_ACP, 0,
+                     package->infoW.Comment, -1, nextString, commentLen, NULL,
+                     NULL);
+                }
+                else
+                    (*ppPackageInfo)->Comment = NULL;
+                ret = SEC_E_OK;
+            }
+            else
+                ret = SEC_E_INSUFFICIENT_MEMORY;
+        }
+        else
+            ret = SEC_E_SECPKG_NOT_FOUND;
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+/***********************************************************************
+ *      QuerySecurityPackageInfoW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QuerySecurityPackageInfoW(SEC_WCHAR *pszPackageName,
+ PSecPkgInfoW *ppPackageInfo)
+{
+    SECURITY_STATUS ret;
+    SecurePackage *package = SECUR32_findPackageW(pszPackageName);
+
+    TRACE("%s %p\n", debugstr_w(pszPackageName), ppPackageInfo);
+    if (package)
+    {
+        size_t bytesNeeded = sizeof(SecPkgInfoW);
+        int nameLen = 0, commentLen = 0;
+
+        if (package->infoW.Name)
+        {
+            nameLen = lstrlenW(package->infoW.Name) + 1;
+            bytesNeeded += nameLen * sizeof(WCHAR);
+        }
+        if (package->infoW.Comment)
+        {
+            commentLen = lstrlenW(package->infoW.Comment) + 1;
+            bytesNeeded += commentLen * sizeof(WCHAR);
+        }
+        *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
+        if (*ppPackageInfo)
+        {
+            PWSTR nextString = (PWSTR)((PBYTE)*ppPackageInfo +
+             sizeof(SecPkgInfoW));
+
+            **ppPackageInfo = package->infoW;
+            if (package->infoW.Name)
+            {
+                (*ppPackageInfo)->Name = nextString;
+                lstrcpynW(nextString, package->infoW.Name, nameLen);
+                nextString += nameLen;
+            }
+            else
+                (*ppPackageInfo)->Name = NULL;
+            if (package->infoW.Comment)
+            {
+                (*ppPackageInfo)->Comment = nextString;
+                lstrcpynW(nextString, package->infoW.Comment, commentLen);
+            }
+            else
+                (*ppPackageInfo)->Comment = NULL;
+            ret = SEC_E_OK;
+        }
+        else
+            ret = SEC_E_INSUFFICIENT_MEMORY;
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+/***********************************************************************
+ *      ExportSecurityContext (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI ExportSecurityContext(PCtxtHandle phContext,
+ ULONG fFlags, PSecBuffer pPackedContext, void **pToken)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %p\n", phContext, fFlags, pPackedContext, pToken);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.ExportSecurityContext)
+                ret = package->provider->fnTableW.ExportSecurityContext(
+                 ctxt, fFlags, pPackedContext, pToken);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      ImportSecurityContextA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI ImportSecurityContextA(SEC_CHAR *pszPackage,
+ PSecBuffer pPackedContext, void *Token, PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+    SecurePackage *package = SECUR32_findPackageA(pszPackage);
+
+    TRACE("%s %p %p %p\n", debugstr_a(pszPackage), pPackedContext, Token,
+     phContext);
+    if (package && package->provider)
+    {
+        if (package->provider->fnTableA.ImportSecurityContextA)
+        {
+            CtxtHandle myCtxt;
+
+            ret = package->provider->fnTableA.ImportSecurityContextA(
+             pszPackage, pPackedContext, Token, &myCtxt);
+            if (ret == SEC_E_OK)
+            {
+                ret = SECUR32_makeSecHandle(phContext, package, &myCtxt);
+                if (ret != SEC_E_OK)
+                    package->provider->fnTableW.DeleteSecurityContext(&myCtxt);
+            }
+        }
+        else
+            ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+
+}
+
+/***********************************************************************
+ *      ImportSecurityContextW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI ImportSecurityContextW(SEC_WCHAR *pszPackage,
+ PSecBuffer pPackedContext, void *Token, PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+    SecurePackage *package = SECUR32_findPackageW(pszPackage);
+
+    TRACE("%s %p %p %p\n", debugstr_w(pszPackage), pPackedContext, Token,
+     phContext);
+    if (package && package->provider)
+    {
+        if (package->provider->fnTableW.ImportSecurityContextW)
+        {
+            CtxtHandle myCtxt;
+
+            ret = package->provider->fnTableW.ImportSecurityContextW(
+             pszPackage, pPackedContext, Token, &myCtxt);
+            if (ret == SEC_E_OK)
+            {
+                ret = SECUR32_makeSecHandle(phContext, package, &myCtxt);
+                if (ret != SEC_E_OK)
+                    package->provider->fnTableW.DeleteSecurityContext(&myCtxt);
+            }
+        }
+        else
+            ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+        ret = SEC_E_SECPKG_NOT_FOUND;
+    return ret;
+}
+
+/***********************************************************************
+ *      AddCredentialsA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI AddCredentialsA(PCredHandle hCredentials,
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
+ void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %s %s %d %p %p %p %p\n", hCredentials, debugstr_a(pszPrincipal),
+     debugstr_a(pszPackage), fCredentialUse, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, ptsExpiry);
+    if (hCredentials)
+    {
+        SecurePackage *package = (SecurePackage *)hCredentials->dwUpper;
+        PCredHandle cred = (PCtxtHandle)hCredentials->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.AddCredentialsA)
+                ret = package->provider->fnTableA.AddCredentialsA(
+                 cred, pszPrincipal, pszPackage, fCredentialUse, pAuthData,
+                 pGetKeyFn, pvGetKeyArgument, ptsExpiry);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      AddCredentialsW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI AddCredentialsW(PCredHandle hCredentials,
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
+ void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %s %s %d %p %p %p %p\n", hCredentials, debugstr_w(pszPrincipal),
+     debugstr_w(pszPackage), fCredentialUse, pAuthData, pGetKeyFn,
+     pvGetKeyArgument, ptsExpiry);
+    if (hCredentials)
+    {
+        SecurePackage *package = (SecurePackage *)hCredentials->dwUpper;
+        PCredHandle cred = (PCtxtHandle)hCredentials->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.AddCredentialsW)
+                ret = package->provider->fnTableW.AddCredentialsW(
+                 cred, pszPrincipal, pszPackage, fCredentialUse, pAuthData,
+                 pGetKeyFn, pvGetKeyArgument, ptsExpiry);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      QuerySecurityContextToken (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI QuerySecurityContextToken(PCtxtHandle phContext,
+ HANDLE *phToken)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p\n", phContext, phToken);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.QuerySecurityContextToken)
+                ret = package->provider->fnTableW.QuerySecurityContextToken(
+                 ctxt, phToken);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      EncryptMessage (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
+ PSecBufferDesc pMessage, ULONG MessageSeqNo)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.EncryptMessage)
+                ret = package->provider->fnTableW.EncryptMessage(
+                 ctxt, fQOP, pMessage, MessageSeqNo);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      DecryptMessage (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI DecryptMessage(PCtxtHandle phContext,
+ PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.DecryptMessage)
+                ret = package->provider->fnTableW.DecryptMessage(
+                 ctxt, pMessage, MessageSeqNo, pfQOP);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      SetContextAttributesA (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI SetContextAttributesA(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer, ULONG cbBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %d\n", phContext, ulAttribute, pBuffer, cbBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableA.SetContextAttributesA)
+                ret = package->provider->fnTableA.SetContextAttributesA(
+                 ctxt, ulAttribute, pBuffer, cbBuffer);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}
+
+/***********************************************************************
+ *      SetContextAttributesW (SECUR32.@)
+ */
+SECURITY_STATUS WINAPI SetContextAttributesW(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer, ULONG cbBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p %d %p %d\n", phContext, ulAttribute, pBuffer, cbBuffer);
+    if (phContext)
+    {
+        SecurePackage *package = (SecurePackage *)phContext->dwUpper;
+        PCtxtHandle ctxt = (PCtxtHandle)phContext->dwLower;
+
+        if (package && package->provider)
+        {
+            if (package->provider->fnTableW.SetContextAttributesW)
+                ret = package->provider->fnTableW.SetContextAttributesW(
+                 ctxt, ulAttribute, pBuffer, cbBuffer);
+            else
+                ret = SEC_E_UNSUPPORTED_FUNCTION;
+        }
+        else
+            ret = SEC_E_INVALID_HANDLE;
+    }
+    else
+        ret = SEC_E_INVALID_HANDLE;
+    return ret;
+}