>From cfec0ed59a864f414db6ce6d1d8b89ffd474d06d Mon Sep 17 00:00:00 2001
From: George Popoff <ambulance@etersoft.ru>
Date: Wed, 11 Oct 2017 14:53:11 +0300
Subject: [PATCH 7/8] create new kerberos ssp based on GSSAPI ssp. Delete old.

---
 wine/configure                   |   69 +-
 wine/configure.ac                |   10 +
 wine/dlls/kerberos/Makefile.in   |    3 +-
 wine/dlls/kerberos/kerberos.spec |    2 +
 wine/dlls/kerberos/krb5_ssp.c    | 1304 ++++++++++++++++++++++++++++++++++++++
 wine/dlls/secur32/Makefile.in    |    1 -
 wine/dlls/secur32/kerberos.c     |  323 ----------
 wine/dlls/secur32/secur32.c      |   33 +-
 wine/include/config.h.in         |    6 +
 wine/loader/wine.inf.in          |    2 +
 10 files changed, 1411 insertions(+), 342 deletions(-)
 create mode 100644 wine/dlls/kerberos/krb5_ssp.c
 delete mode 100644 wine/dlls/secur32/kerberos.c

diff --git a/wine/configure b/wine/configure
index 82ba566..e7ebf89 100755
--- a/wine/configure
+++ b/wine/configure
@@ -6877,6 +6877,8 @@ for ac_header in \
 	grp.h \
 	gsm.h \
 	gsm/gsm.h \
+	gssapi/gssapi.h \
+	gssapi/gssapi_krb5.h \
 	ieeefp.h \
 	inet/mib2.h \
 	io.h \
@@ -13765,6 +13767,72 @@ esac
 
 fi
 
+if test "$ac_cv_header_gssapi_gssapi_krb5_h" = "yes"
+then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lgssapi_krb5" >&5
+$as_echo_n "checking for -lgssapi_krb5... " >&6; }
+if ${ac_cv_lib_soname_gssapi_krb5+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_soname_save_LIBS=$LIBS
+LIBS="-lgssapi_krb5  $LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gss_init_sec_context ();
+int
+main ()
+{
+return gss_init_sec_context ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  case "$LIBEXT" in
+    dll) ac_cv_lib_soname_gssapi_krb5=`$ac_cv_path_LDD conftest.exe | grep "gssapi_krb5" | sed -e "s/dll.*/dll/"';2,$d'` ;;
+    dylib) ac_cv_lib_soname_gssapi_krb5=`$OTOOL -L conftest$ac_exeext | grep "libgssapi_krb5\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgssapi_krb5\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;;
+    *) ac_cv_lib_soname_gssapi_krb5=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgssapi_krb5\\.$LIBEXT[^	 ]*\\)\\].*$/\1/"';2,$d'`
+       if ${ac_cv_lib_soname_gssapi_krb5:+false} :; then :
+  ac_cv_lib_soname_gssapi_krb5=`$LDD conftest$ac_exeext | grep "libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\(libgssapi_krb5\.$LIBEXT[^	 ]*\).*$/\1/"';2,$d'`
+fi ;;
+  esac
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LIBS=$ac_check_soname_save_LIBS
+fi
+if ${ac_cv_lib_soname_gssapi_krb5:+false} :; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gssapi_krb5" >&5
+$as_echo "$ac_cv_lib_soname_gssapi_krb5" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define SONAME_LIBGSSAPI_KRB5 "$ac_cv_lib_soname_gssapi_krb5"
+_ACEOF
+
+
+fi
+fi
+if test "x$ac_cv_lib_soname_gssapi_krb5" = "x"; then :
+  case "x$with_gssapi_krb5" in
+  x)   as_fn_append wine_notices "|libgssapi_krb5 ${notice_platform}development files not found gssapi won't be supported." ;;
+  xno) ;;
+  *)   as_fn_error $? "libgssapi_krb5 ${notice_platform}development files not found gssapi won't be supported.
+This is an error since --with-gssapi_krb5 was requested." "$LINENO" 5 ;;
+esac
+
+fi
+
 if test "x$with_jpeg" != "xno"
 then
     if ${JPEG_CFLAGS:+false} :; then :
@@ -20531,4 +20599,3 @@ IFS="$ac_save_IFS"
 $as_echo "
 $as_me: Finished.  Do '${ac_make}' to compile Wine.
 " >&6
-
diff --git a/wine/configure.ac b/wine/configure.ac
index c19ad60..35a2830 100644
--- a/wine/configure.ac
+++ b/wine/configure.ac
@@ -419,6 +419,8 @@ AC_CHECK_HEADERS(\
 	grp.h \
 	gsm.h \
 	gsm/gsm.h \
+	gssapi/gssapi.h \
+	gssapi/gssapi_krb5.h \
 	ieeefp.h \
 	inet/mib2.h \
 	io.h \
@@ -1634,6 +1636,14 @@ fi
 WINE_NOTICE_WITH(krb5,[test "x$ac_cv_lib_soname_krb5" = "x"],
                  [libkrb5 ${notice_platform}development files not found, krb5 won't be supported.])
 
+dnl **** Check for libgssapi_krb5 ****
+if test "$ac_cv_header_gssapi_gssapi_krb5_h" = "yes"
+then
+    WINE_CHECK_SONAME(gssapi_krb5,gss_init_sec_context)
+fi
+WINE_NOTICE_WITH(gssapi_krb5,[test "x$ac_cv_lib_soname_gssapi_krb5" = "x"],
+                 [libgssapi_krb5 ${notice_platform}development files not found gssapi won't be supported.])
+
 dnl **** Check for libjpeg ****
 if test "x$with_jpeg" != "xno"
 then
diff --git a/wine/dlls/kerberos/Makefile.in b/wine/dlls/kerberos/Makefile.in
index db155f8..e14a218 100644
--- a/wine/dlls/kerberos/Makefile.in
+++ b/wine/dlls/kerberos/Makefile.in
@@ -1,4 +1,5 @@
 MODULE    = kerberos.dll
 
 C_SRCS = \
-	krb5_ap.c
+	krb5_ap.c \
+	krb5_ssp.c
diff --git a/wine/dlls/kerberos/kerberos.spec b/wine/dlls/kerberos/kerberos.spec
index d277cee..e92516f 100644
--- a/wine/dlls/kerberos/kerberos.spec
+++ b/wine/dlls/kerberos/kerberos.spec
@@ -1 +1,3 @@
 @ stdcall SpLsaModeInitialize(long ptr ptr ptr)
+@ stdcall InitSecurityInterfaceA()
+@ stdcall InitSecurityInterfaceW()
diff --git a/wine/dlls/kerberos/krb5_ssp.c b/wine/dlls/kerberos/krb5_ssp.c
new file mode 100644
index 0000000..cfb408e
--- /dev/null
+++ b/wine/dlls/kerberos/krb5_ssp.c
@@ -0,0 +1,1304 @@
+/*
+ * Kerberos API based on GSSAPI SSP
+ *
+ * Copyright 2005, 2006 Kai Blin
+ * Copyright 2008 Robert Shearman for CodeWeavers
+ * Copyright 2016 Jacek Caban for CodeWeavers
+ * Copyright 2017 George Popoff
+ *
+ * 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 "config.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "wincred.h"
+#include "rpc.h"
+#include "sspi.h"
+#include "lm.h"
+#include "wine/unicode.h"
+#include "wine/library.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(kerberos);
+WINE_DECLARE_DEBUG_CHANNEL(winediag);
+
+#define MAKE_FUNCPTR(f) static typeof(f) * p_##f
+MAKE_FUNCPTR(gss_import_name);
+MAKE_FUNCPTR(gss_acquire_cred);
+MAKE_FUNCPTR(gss_release_name);
+MAKE_FUNCPTR(gss_init_sec_context);
+MAKE_FUNCPTR(gss_accept_sec_context);
+MAKE_FUNCPTR(gss_delete_sec_context);
+MAKE_FUNCPTR(gss_get_mic);
+MAKE_FUNCPTR(gss_verify_mic);
+MAKE_FUNCPTR(gss_release_cred);
+MAKE_FUNCPTR(gss_wrap);
+MAKE_FUNCPTR(gss_unwrap);
+#undef MAKE_FUNCPTR
+
+#define GSS_KERBEROS_MAX_BUF 1904
+
+#define KERBEROS_MAGIC ('K' << 24 | 'E' << 16 | 'R' << 8 | 'B')
+
+#define GSS_KERBEROS_COMMENT \
+   { 'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', ' ', \
+     'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', \
+     'P', 'a', 'c', 'k', 'a', 'g', 'e', 0}
+
+static CHAR kerberos_comment_A[] = GSS_KERBEROS_COMMENT;
+static WCHAR kerberos_comment_W[] = GSS_KERBEROS_COMMENT;
+
+#define GSS_KERBEROS_NAME {'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', 0}
+
+static char kerberos_name_A[] = GSS_KERBEROS_NAME;
+static WCHAR kerberos_name_W[] = GSS_KERBEROS_NAME;
+
+/* FIXME */
+#define CAPS ( \
+        SECPKG_FLAG_INTEGRITY | \
+        SECPKG_FLAG_PRIVACY | \
+        SECPKG_FLAG_TOKEN_ONLY | \
+        SECPKG_FLAG_CONNECTION | \
+        SECPKG_FLAG_MULTI_REQUIRED | \
+        SECPKG_FLAG_IMPERSONATION | \
+        SECPKG_FLAG_ACCEPT_WIN32_NAME | \
+        SECPKG_FLAG_READONLY_WITH_CHECKSUM)
+
+
+static SecPkgInfoW infoW = {
+    CAPS,
+    1,
+    RPC_C_AUTHN_GSS_KERBEROS,
+    GSS_KERBEROS_MAX_BUF,
+    kerberos_name_W,
+    kerberos_comment_W
+};
+
+static SecPkgInfoA infoA = {
+    CAPS,
+    1,
+    RPC_C_AUTHN_GSS_KERBEROS,
+    GSS_KERBEROS_MAX_BUF,
+    kerberos_name_A,
+    kerberos_comment_A
+};
+
+
+SecPkgInfoA *kerberos_package_infoA = (SecPkgInfoA *)&infoA;
+SecPkgInfoW *kerberos_package_infoW = (SecPkgInfoW *)&infoW;
+
+static BOOL load_gssapi(void)
+{
+    void *libgssapi_handle;
+
+    if (!(libgssapi_handle = wine_dlopen(SONAME_LIBGSSAPI_KRB5, RTLD_NOW, NULL, 0)))
+    {
+        ERR_(winediag)("failed to load libgssapi\n" );
+        return FALSE;
+    }
+
+#define LOAD_FUNCPTR(f) \
+    if (!(p_##f = wine_dlsym(libgssapi_handle, #f, NULL, 0))) \
+    { \
+        ERR("failed to load %s\n", #f); \
+        goto fail; \
+    }
+
+    LOAD_FUNCPTR(gss_import_name);
+    LOAD_FUNCPTR(gss_acquire_cred);
+    LOAD_FUNCPTR(gss_release_name);
+    LOAD_FUNCPTR(gss_init_sec_context);
+    LOAD_FUNCPTR(gss_accept_sec_context);
+    LOAD_FUNCPTR(gss_delete_sec_context);
+    LOAD_FUNCPTR(gss_get_mic);
+    LOAD_FUNCPTR(gss_verify_mic);
+    LOAD_FUNCPTR(gss_release_cred);
+    LOAD_FUNCPTR(gss_wrap);
+    LOAD_FUNCPTR(gss_unwrap);
+#undef LOAD_FUNCPTR
+
+    return TRUE;
+
+fail:
+    wine_dlclose(libgssapi_handle, NULL, 0);
+    return FALSE;
+}
+
+static inline gss_cred_id_t kerberos_CredHandleSSPItoGSSAPI(const CredHandle *phCredential)
+{
+    return (gss_cred_id_t)phCredential->dwLower;
+}
+
+static inline void kerberos_CredHandleGSSAPItoSSPI(gss_cred_id_t cred_handle, PCredHandle phCredential)
+{
+    phCredential->dwLower = (DWORD)cred_handle;
+    phCredential->dwUpper = KERBEROS_MAGIC;
+}
+
+static inline gss_ctx_id_t kerberos_CtxtHandleSSPItoGSSAPI(const CtxtHandle *phCredential)
+{
+    return (gss_ctx_id_t)phCredential->dwLower;
+}
+
+static inline void kerberos_CtxtHandleGSSAPItoSSPI(gss_ctx_id_t ctx_handle, PCtxtHandle phCredential)
+{
+    phCredential->dwLower = (DWORD)ctx_handle;
+    phCredential->dwUpper = KERBEROS_MAGIC;
+}
+
+static inline void kerberos_CtxtAttrsGSSPItoSSPI(OM_uint32 ret_flags, PULONG pfContextAttr)
+{
+    *pfContextAttr = 0;
+
+    if (ret_flags & GSS_C_DELEG_FLAG)
+        *pfContextAttr |= ISC_RET_DELEGATE;
+    if (ret_flags & GSS_C_MUTUAL_FLAG)
+        *pfContextAttr |= ISC_RET_MUTUAL_AUTH;
+    if (ret_flags & GSS_C_REPLAY_FLAG)
+        *pfContextAttr |= ISC_RET_REPLAY_DETECT;
+    if (ret_flags & GSS_C_SEQUENCE_FLAG)
+        *pfContextAttr |= ISC_RET_SEQUENCE_DETECT;
+    if (ret_flags & GSS_C_CONF_FLAG)
+        *pfContextAttr |= ISC_RET_CONFIDENTIALITY;
+    if (ret_flags & GSS_C_INTEG_FLAG)
+        *pfContextAttr |= ISC_RET_INTEGRITY;
+    if (ret_flags & GSS_C_ANON_FLAG)
+        *pfContextAttr |= ISC_RET_NULL_SESSION;
+}
+
+static inline OM_uint32 kerberos_CtxtAttrsSSPItoGSSAPI(ULONG fContextAttr)
+{
+    OM_uint32 ret_flags = 0;
+
+    if (fContextAttr & ISC_RET_DELEGATE)
+        ret_flags |= GSS_C_DELEG_FLAG;
+    if (fContextAttr & ISC_RET_MUTUAL_AUTH)
+        ret_flags |= GSS_C_MUTUAL_FLAG;
+    if (fContextAttr & ISC_RET_REPLAY_DETECT)
+        ret_flags |= GSS_C_REPLAY_FLAG;
+    if (fContextAttr & ISC_RET_SEQUENCE_DETECT)
+        ret_flags |= GSS_C_SEQUENCE_FLAG;
+    if (fContextAttr & ISC_RET_CONFIDENTIALITY)
+        ret_flags |= GSS_C_CONF_FLAG;
+    if (fContextAttr & ISC_RET_INTEGRITY)
+        ret_flags |= GSS_C_INTEG_FLAG;
+    if (fContextAttr & ISC_RET_NULL_SESSION)
+        ret_flags |= GSS_C_ANON_FLAG;
+
+    return ret_flags;
+}
+
+static inline OM_uint32 kerberos_CtxtReqsSSPItoGSSAPI(ULONG fRequirements)
+{
+    OM_uint32 req_flags = 0;
+
+    if (fRequirements & ISC_REQ_DELEGATE)
+        req_flags |= GSS_C_DELEG_FLAG;
+    if (fRequirements & ISC_REQ_MUTUAL_AUTH)
+        req_flags |= GSS_C_MUTUAL_FLAG;
+    if (fRequirements & ISC_REQ_REPLAY_DETECT)
+        req_flags |= GSS_C_REPLAY_FLAG;
+    if (fRequirements & ISC_REQ_SEQUENCE_DETECT)
+        req_flags |= GSS_C_SEQUENCE_FLAG;
+    if (fRequirements & ISC_REQ_CONFIDENTIALITY)
+        req_flags |= GSS_C_CONF_FLAG;
+    if (fRequirements & ISC_REQ_INTEGRITY)
+        req_flags |= GSS_C_INTEG_FLAG;
+    if (fRequirements & ISC_REQ_NULL_SESSION)
+        req_flags |= GSS_C_ANON_FLAG;
+
+    return req_flags;
+}
+
+static inline void kerberos_CtxtReqsGSSAPItoSSPI(OM_uint32 req_flags, PULONG pfRequirements)
+{
+    *pfRequirements = 0;
+
+    if (req_flags & GSS_C_DELEG_FLAG)
+        *pfRequirements |= ISC_REQ_DELEGATE;
+    if (req_flags & GSS_C_MUTUAL_FLAG)
+        *pfRequirements |= ISC_REQ_MUTUAL_AUTH;
+    if (req_flags & GSS_C_REPLAY_FLAG)
+        *pfRequirements |= ISC_REQ_REPLAY_DETECT;
+    if (req_flags & GSS_C_SEQUENCE_FLAG)
+        *pfRequirements |= ISC_REQ_SEQUENCE_DETECT;
+    if (req_flags & GSS_C_CONF_FLAG)
+        *pfRequirements |= ISC_REQ_CONFIDENTIALITY;
+    if (req_flags & GSS_C_INTEG_FLAG)
+        *pfRequirements |= ISC_REQ_INTEGRITY;
+    if (req_flags & GSS_C_ANON_FLAG)
+        *pfRequirements |= ISC_REQ_NULL_SESSION;
+}
+
+static SECURITY_STATUS kerberos_GSSAPIStatusToSecurityStatus(OM_uint32 status)
+{
+    switch (status)
+    {
+    case GSS_S_COMPLETE: return SEC_E_OK;
+    case GSS_S_BAD_MECH: return SEC_E_SECPKG_NOT_FOUND;
+    case GSS_S_BAD_SIG: return SEC_E_MESSAGE_ALTERED;
+    case GSS_S_NO_CRED: return SEC_E_NO_CREDENTIALS;
+    case GSS_S_NO_CONTEXT: return SEC_E_INVALID_HANDLE;
+    case GSS_S_DEFECTIVE_TOKEN: return SEC_E_MESSAGE_ALTERED;
+    case GSS_S_DEFECTIVE_CREDENTIAL: return SEC_E_INVALID_TOKEN;
+    case GSS_S_CREDENTIALS_EXPIRED: return SEC_E_CONTEXT_EXPIRED;
+    case GSS_S_CONTEXT_EXPIRED: return SEC_E_CONTEXT_EXPIRED;
+    case GSS_S_BAD_QOP: return SEC_E_QOP_NOT_SUPPORTED;
+
+    case GSS_S_CONTINUE_NEEDED: return SEC_I_CONTINUE_NEEDED;
+    case GSS_S_DUPLICATE_TOKEN: return SEC_E_INVALID_TOKEN;
+    case GSS_S_OLD_TOKEN: return SEC_E_INVALID_TOKEN;
+    case GSS_S_UNSEQ_TOKEN: return SEC_E_OUT_OF_SEQUENCE;
+    case GSS_S_GAP_TOKEN: return SEC_E_OUT_OF_SEQUENCE;
+
+    default:
+        FIXME("couldn't convert status 0x%x to SECURITY_STATUS\n", status);
+
+        return SEC_E_INTERNAL_ERROR;
+    }
+}
+
+/***********************************************************************
+ *              EnumerateSecurityPackagesW
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_EnumerateSecurityPackagesW(
+        PULONG pcPackages, PSecPkgInfoW *ppPackageInfo)
+{
+    *pcPackages = 1;
+    *ppPackageInfo = &infoW;
+
+    return SEC_E_OK;
+}
+
+/***********************************************************************
+ *              EnumerateSecurityPackagesA
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_EnumerateSecurityPackagesA(
+        PULONG pcPackages, PSecPkgInfoA *ppPackageInfo)
+{
+    *pcPackages = 1;
+    *ppPackageInfo = &infoA;
+
+    return SEC_E_OK;
+}
+
+/***********************************************************************
+ *              QueryCredentialsAttributesA
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesA(
+        PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
+
+    if(ulAttribute == SECPKG_ATTR_NAMES)
+    {
+        FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
+        ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+        ret = SEC_E_UNSUPPORTED_FUNCTION;
+
+    return ret;
+}
+
+/***********************************************************************
+ *              QueryCredentialsAttributesW
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW(
+        PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
+
+    if(ulAttribute == SECPKG_ATTR_NAMES)
+    {
+        FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
+        ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+        ret = SEC_E_UNSUPPORTED_FUNCTION;
+
+    return ret;
+}
+
+static void kerberos_ExpiryTimeToTimeStamp(OM_uint32 expiry_time, PTimeStamp ptsExpiry)
+{
+    SYSTEMTIME current_local_time;
+    FILETIME current_local_filetime;
+    ULARGE_INTEGER temp;
+    GetLocalTime(&current_local_time);
+    SystemTimeToFileTime(&current_local_time, &current_local_filetime);
+    temp.QuadPart = ((ULONGLONG)current_local_filetime.dwLowDateTime |
+        (ULONGLONG)current_local_filetime.dwHighDateTime << 32) +
+        expiry_time;
+    ptsExpiry->LowPart = temp.QuadPart;
+    ptsExpiry->HighPart = temp.QuadPart >> 32;
+}
+
+/***********************************************************************
+ *              AcquireCredentialsHandleW
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleW(
+ SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
+ PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+    gss_name_t principal_name = GSS_C_NO_NAME;
+    gss_cred_usage_t cred_usage;
+    gss_cred_id_t cred_handle;
+    OM_uint32 expiry_time;
+
+    TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
+          debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
+          pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
+
+    if (pAuthData)
+    {
+        /* gssapi has no way to specify the credentials to use, so we just
+         * return an error when the caller tries to do so */
+        FIXME("specific credentials not supported\n");
+        return SEC_E_UNKNOWN_CREDENTIALS;
+    }
+
+    switch (fCredentialUse)
+    {
+        case SECPKG_CRED_INBOUND:
+            cred_usage = GSS_C_ACCEPT;
+            break;
+        case SECPKG_CRED_OUTBOUND:
+            cred_usage = GSS_C_INITIATE;
+            break;
+        case SECPKG_CRED_BOTH:
+            cred_usage = GSS_C_BOTH;
+            break;
+        default:
+            phCredential = NULL;
+            return SEC_E_UNKNOWN_CREDENTIALS;
+    }
+
+    if (pszPrincipal)
+    {
+        char *principal_name_str;
+        int len;
+        gss_buffer_desc name_buffer;
+
+        len = WideCharToMultiByte(CP_UNIXCP, 0, pszPrincipal, -1, NULL, 0, NULL, NULL);
+        principal_name_str = HeapAlloc(GetProcessHeap(), 0, len);
+        if (!principal_name_str)
+            return SEC_E_INSUFFICIENT_MEMORY;
+        WideCharToMultiByte(CP_UNIXCP, 0, pszPrincipal, -1, principal_name_str, len, NULL, NULL);
+
+        name_buffer.length = len-1;
+        name_buffer.value = principal_name_str;
+
+        ret = p_gss_import_name(&minor_status, &name_buffer,
+                              GSS_C_NULL_OID /* FIXME: detect the appropriate value for this ourselves? */,
+                              &principal_name);
+        HeapFree(GetProcessHeap(), 0, principal_name_str);
+
+        if (ret != GSS_S_COMPLETE)
+            return kerberos_GSSAPIStatusToSecurityStatus(ret);
+    }
+
+    ret = p_gss_acquire_cred(&minor_status, principal_name, GSS_C_INDEFINITE,
+                           GSS_C_NULL_OID_SET /* FIXME: gss_mech_set_krb5 */, cred_usage, &cred_handle,
+                           NULL, &expiry_time);
+
+    if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED)
+    {
+        if (ptsExpiry != NULL) {
+            kerberos_ExpiryTimeToTimeStamp(expiry_time, ptsExpiry);
+            kerberos_CredHandleGSSAPItoSSPI(cred_handle, phCredential);
+        }
+    }
+
+    if (principal_name != GSS_C_NO_NAME)
+        p_gss_release_name(&minor_status, &principal_name);
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *              AcquireCredentialsHandleA
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
+ SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
+ PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
+ PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+    SECURITY_STATUS ret;
+    int user_sizeW, domain_sizeW, passwd_sizeW;
+
+    SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL;
+
+    PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
+    PSEC_WINNT_AUTH_IDENTITY_A identity  = NULL;
+
+    TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
+     debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
+     pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
+
+    if(pszPackage != NULL)
+    {
+        int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1,
+                NULL, 0);
+
+        package = HeapAlloc(GetProcessHeap(), 0, package_sizeW *
+                sizeof(SEC_WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW);
+    }
+
+
+    if(pAuthData != NULL)
+    {
+        identity = (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData;
+
+        if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
+        {
+            pAuthDataW = HeapAlloc(GetProcessHeap(), 0,
+                    sizeof(SEC_WINNT_AUTH_IDENTITY_W));
+
+            if(identity->UserLength != 0)
+            {
+                user_sizeW = MultiByteToWideChar(CP_ACP, 0,
+                    (LPCSTR)identity->User, identity->UserLength, NULL, 0);
+                user = HeapAlloc(GetProcessHeap(), 0, user_sizeW *
+                        sizeof(SEC_WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User,
+                    identity->UserLength, user, user_sizeW);
+            }
+            else
+            {
+                user_sizeW = 0;
+            }
+
+            if(identity->DomainLength != 0)
+            {
+                domain_sizeW = MultiByteToWideChar(CP_ACP, 0,
+                    (LPCSTR)identity->Domain, identity->DomainLength, NULL, 0);
+                domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW
+                    * sizeof(SEC_WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain,
+                    identity->DomainLength, domain, domain_sizeW);
+            }
+            else
+            {
+                domain_sizeW = 0;
+            }
+
+            if(identity->PasswordLength != 0)
+            {
+                passwd_sizeW = MultiByteToWideChar(CP_ACP, 0,
+                    (LPCSTR)identity->Password, identity->PasswordLength,
+                    NULL, 0);
+                passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW
+                    * sizeof(SEC_WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password,
+                    identity->PasswordLength, passwd, passwd_sizeW);
+            }
+            else
+            {
+                passwd_sizeW = 0;
+            }
+
+            pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+            pAuthDataW->User = user;
+            pAuthDataW->UserLength = user_sizeW;
+            pAuthDataW->Domain = domain;
+            pAuthDataW->DomainLength = domain_sizeW;
+            pAuthDataW->Password = passwd;
+            pAuthDataW->PasswordLength = passwd_sizeW;
+        }
+        else
+        {
+            pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity;
+        }
+    }
+
+    ret = kerberos_AcquireCredentialsHandleW(NULL, package, fCredentialUse,
+            pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
+            ptsExpiry);
+
+    HeapFree(GetProcessHeap(), 0, package);
+    HeapFree(GetProcessHeap(), 0, user);
+    HeapFree(GetProcessHeap(), 0, domain);
+    HeapFree(GetProcessHeap(), 0, passwd);
+    if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity)
+        HeapFree(GetProcessHeap(), 0, pAuthDataW);
+
+    return ret;
+}
+
+/*************************************************************************
+ *             kerberos_GetTokenBufferIndex
+ * Calculates the index of the secbuffer with BufferType == SECBUFFER_TOKEN
+ * Returns index if found or -1 if not found.
+ */
+static int kerberos_GetTokenBufferIndex(PSecBufferDesc pMessage)
+{
+    UINT i;
+
+    TRACE("%p\n", pMessage);
+
+    for( i = 0; i < pMessage->cBuffers; ++i )
+    {
+        if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
+            return i;
+    }
+
+    return -1;
+}
+
+/*************************************************************************
+ *             kerberos_GetDataBufferIndex
+ * Calculates the index of the first secbuffer with BufferType == SECBUFFER_DATA
+ * Returns index if found or -1 if not found.
+ */
+static int kerberos_GetDataBufferIndex(PSecBufferDesc pMessage)
+{
+    UINT i;
+
+    TRACE("%p\n", pMessage);
+
+    for( i = 0; i < pMessage->cBuffers; ++i )
+    {
+        if(pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
+            return i;
+    }
+
+    return -1;
+}
+
+/***********************************************************************
+ *              InitializeSecurityContextW
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_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)
+{
+    int output_token_idx;
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+    gss_cred_id_t cred_handle;
+    gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
+    OM_uint32 req_flags = 0;
+    OM_uint32 ret_flags;
+    gss_buffer_desc input_token;
+    gss_buffer_desc output_token;
+    OM_uint32 expiry_time;
+    gss_name_t target_name = GSS_C_NO_NAME;
+
+    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 && !pInput)
+    {
+        if (!phCredential)
+            return SEC_E_INVALID_HANDLE;
+        cred_handle = kerberos_CredHandleSSPItoGSSAPI(phCredential);
+    }
+    else
+    {
+        cred_handle = GSS_C_NO_CREDENTIAL;
+
+        if (phContext)
+        {
+            context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext);
+        }
+    }
+
+    input_token.length = 0;
+    if (pInput)
+    {
+        int input_token_idx = kerberos_GetTokenBufferIndex(pInput);
+        if (input_token_idx == -1)
+            return SEC_E_INVALID_TOKEN;
+        input_token.length = pInput->pBuffers[input_token_idx].cbBuffer;
+        input_token.value = pInput->pBuffers[input_token_idx].pvBuffer;
+    }
+
+    req_flags = kerberos_CtxtReqsSSPItoGSSAPI(fContextReq);
+
+    output_token_idx = kerberos_GetTokenBufferIndex(pOutput);
+    if (output_token_idx == -1)
+        return SEC_E_INVALID_TOKEN;
+
+    output_token.length = pOutput->pBuffers[output_token_idx].cbBuffer;
+    output_token.value = pOutput->pBuffers[output_token_idx].pvBuffer;
+
+    if (pszTargetName)
+    {
+        char *target_name_str;
+        int len;
+        gss_buffer_desc name_buffer;
+
+        len = WideCharToMultiByte(CP_UNIXCP, 0, pszTargetName, -1, NULL, 0, NULL, NULL);
+        target_name_str = HeapAlloc(GetProcessHeap(), 0, len);
+        if (!target_name_str)
+            return SEC_E_INSUFFICIENT_MEMORY;
+        WideCharToMultiByte(CP_UNIXCP, 0, pszTargetName, -1, target_name_str, len, NULL, NULL);
+
+        name_buffer.length = len-1;
+        name_buffer.value = target_name_str;
+
+        ret = p_gss_import_name(&minor_status, &name_buffer,
+                              GSS_C_NULL_OID /* FIXME: detect the appropriate value for this ourselves? */,
+                              &target_name);
+        HeapFree(GetProcessHeap(), 0, target_name_str);
+
+        if (ret != GSS_S_COMPLETE)
+            return kerberos_GSSAPIStatusToSecurityStatus(ret);
+    }
+
+    ret = p_gss_init_sec_context(&minor_status, cred_handle, &context_handle,
+                               target_name, GSS_C_NO_OID, req_flags, 0,
+                               GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL,
+                               &output_token, &ret_flags, &expiry_time);
+
+    if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED)
+    {
+        kerberos_ExpiryTimeToTimeStamp(expiry_time, ptsExpiry);
+        kerberos_CtxtHandleGSSAPItoSSPI(context_handle, phNewContext);
+
+        if (pfContextAttr)
+        {
+            kerberos_CtxtAttrsGSSPItoSSPI(ret_flags, pfContextAttr);
+        }
+    }
+
+    if (target_name != GSS_C_NO_NAME)
+        p_gss_release_name(&minor_status, &target_name);
+
+    pOutput->pBuffers[output_token_idx].cbBuffer = (ULONG) output_token.length;
+    pOutput->pBuffers[output_token_idx].pvBuffer = output_token.value;
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *              InitializeSecurityContextA
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_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;
+    SEC_WCHAR *target = NULL;
+
+    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(pszTargetName != NULL)
+    {
+        int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName,
+            strlen(pszTargetName)+1, NULL, 0);
+        target = HeapAlloc(GetProcessHeap(), 0, target_size *
+                sizeof(SEC_WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1,
+            target, target_size);
+    }
+
+    ret = kerberos_InitializeSecurityContextW(phCredential, phContext, target,
+            fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
+            phNewContext, pOutput, pfContextAttr, ptsExpiry);
+
+    HeapFree(GetProcessHeap(), 0, target);
+    return ret;
+}
+
+/***********************************************************************
+ *              AcceptSecurityContext
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_AcceptSecurityContext(
+ PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
+ ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
+ PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
+{
+    int output_token_idx;
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+    gss_cred_id_t cred_handle;
+    gss_ctx_id_t context_handle;
+    OM_uint32 ret_flags;
+    gss_buffer_desc input_token;
+    gss_buffer_desc output_token;
+    OM_uint32 expiry_time;
+
+    TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput,
+     fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
+     ptsExpiry);
+
+    if (!phContext && !pInput)
+    {
+        if (!phCredential)
+            return SEC_E_INVALID_HANDLE;
+        cred_handle = kerberos_CredHandleSSPItoGSSAPI(phCredential);
+    }
+    else
+        cred_handle = GSS_C_NO_CREDENTIAL;
+
+    if (pInput)
+    {
+        int input_token_idx = kerberos_GetTokenBufferIndex(pInput);
+        if (input_token_idx == -1)
+            return SEC_E_INVALID_TOKEN;
+        input_token.length = pInput->pBuffers[input_token_idx].cbBuffer;
+        input_token.value = pInput->pBuffers[input_token_idx].pvBuffer;
+    }
+
+    output_token_idx = kerberos_GetTokenBufferIndex(pOutput);
+    if (output_token_idx == -1)
+        return SEC_E_INVALID_TOKEN;
+    output_token.length = pOutput->pBuffers[output_token_idx].cbBuffer;
+    output_token.value = pOutput->pBuffers[output_token_idx].pvBuffer;
+
+    /* FIXME: get target_name */
+    ret = p_gss_accept_sec_context(&minor_status, &context_handle, cred_handle,
+                                 &input_token, GSS_C_NO_CHANNEL_BINDINGS,
+                                 NULL, NULL, &output_token, &ret_flags,
+                                 &expiry_time, NULL);
+
+    if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED)
+    {
+        kerberos_ExpiryTimeToTimeStamp(expiry_time, ptsExpiry);
+        kerberos_CtxtHandleGSSAPItoSSPI(context_handle, phContext);
+    }
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *              CompleteAuthToken
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_CompleteAuthToken(PCtxtHandle phContext,
+ PSecBufferDesc pToken)
+{
+    /* We never need to call CompleteAuthToken anyway */
+    TRACE("%p %p\n", phContext, pToken);
+    if (!phContext)
+        return SEC_E_INVALID_HANDLE;
+
+    return SEC_E_OK;
+}
+
+/***********************************************************************
+ *              DeleteSecurityContext
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(PCtxtHandle phContext)
+{
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+    gss_buffer_desc output_buffer;
+    gss_ctx_id_t context_handle;
+
+    TRACE("%p\n", phContext);
+    if (!phContext)
+        return SEC_E_INVALID_HANDLE;
+
+    /* FIXME: is this correct? */
+    output_buffer.length = 0;
+    output_buffer.value = NULL;
+
+    context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext);
+    ret = p_gss_delete_sec_context(&minor_status, &context_handle, &output_buffer);
+
+    phContext->dwUpper = 0;
+    phContext->dwLower = 0;
+
+    /* From https://docs.oracle.com/cd/E19683-01/816-0214/6m6nf1opf/index.html
+
+    * This function is provided for compatibility with the GSS-API version 1.
+    *  Because gss_delete_sec_context() no longer returns a valid output_token
+    *  to be sent to gss_process_context_token(), applications using a newer
+    *  version of the GSS-API do not need to rely on this function.
+    *
+    *
+    if (ret == GSS_S_COMPLETE)
+    {
+
+        ret = gss_process_context_token(&minor_status, context_handle,
+                                        &output_buffer);
+    }*/
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *              QueryContextAttributesW
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesW(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer)
+{
+    TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
+    if (!phContext)
+        return SEC_E_INVALID_HANDLE;
+
+    switch(ulAttribute)
+    {
+#define _x(x) case (x) : FIXME(#x" stub\n"); break
+        _x(SECPKG_ATTR_ACCESS_TOKEN);
+        _x(SECPKG_ATTR_AUTHORITY);
+        _x(SECPKG_ATTR_DCE_INFO);
+#if 0
+        case SECPKG_ATTR_FLAGS:
+        {
+            PSecPkgContext_Flags spcf = (PSecPkgContext_Flags)pBuffer;
+            PNegoHelper helper = (PNegoHelper)phContext->dwLower;
+
+            spcf->Flags = 0;
+            if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
+                spcf->Flags |= ISC_RET_INTEGRITY;
+            if(helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL)
+                spcf->Flags |= ISC_RET_CONFIDENTIALITY;
+            return SEC_E_OK;
+        }
+#endif
+        _x(SECPKG_ATTR_KEY_INFO);
+        _x(SECPKG_ATTR_LIFESPAN);
+        _x(SECPKG_ATTR_NAMES);
+        _x(SECPKG_ATTR_NATIVE_NAMES);
+        _x(SECPKG_ATTR_NEGOTIATION_INFO);
+        _x(SECPKG_ATTR_PACKAGE_INFO);
+        _x(SECPKG_ATTR_PASSWORD_EXPIRY);
+        _x(SECPKG_ATTR_SESSION_KEY);
+#if 0
+        case SECPKG_ATTR_SIZES:
+        {
+            PSecPkgContext_Sizes spcs = (PSecPkgContext_Sizes)pBuffer;
+            spcs->cbMaxToken = NTLM_MAX_BUF;
+            spcs->cbMaxSignature = 16;
+            spcs->cbBlockSize = 0;
+            spcs->cbSecurityTrailer = 16;
+            return SEC_E_OK;
+        }
+#endif
+        _x(SECPKG_ATTR_STREAM_SIZES);
+        _x(SECPKG_ATTR_TARGET_INFORMATION);
+#undef _x
+        default:
+            TRACE("Unknown value %d passed for ulAttribute\n", ulAttribute);
+    }
+
+    return SEC_E_UNSUPPORTED_FUNCTION;
+}
+
+/***********************************************************************
+ *              QueryContextAttributesA
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(PCtxtHandle phContext,
+ ULONG ulAttribute, void *pBuffer)
+{
+    return kerberos_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
+}
+
+/***********************************************************************
+ *              ImpersonateSecurityContext
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_ImpersonateSecurityContext(PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p\n", phContext);
+    if (phContext)
+    {
+        ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+    {
+        ret = SEC_E_INVALID_HANDLE;
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *              RevertSecurityContext
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_RevertSecurityContext(PCtxtHandle phContext)
+{
+    SECURITY_STATUS ret;
+
+    TRACE("%p\n", phContext);
+    if (phContext)
+    {
+        ret = SEC_E_UNSUPPORTED_FUNCTION;
+    }
+    else
+    {
+        ret = SEC_E_INVALID_HANDLE;
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *              MakeSignature
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
+ PSecBufferDesc pMessage, ULONG MessageSeqNo)
+{
+    int token_idx, message_idx;
+    OM_uint32 minor_status;
+    OM_uint32 ret;
+    gss_buffer_desc token_buffer;
+    gss_buffer_desc message_buffer;
+    gss_ctx_id_t context_handle;
+    OM_uint32 qop = GSS_C_QOP_DEFAULT;
+
+    TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo);
+
+    if (!phContext)
+        return SEC_E_INVALID_HANDLE;
+
+    context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext);
+
+    if(fQOP)
+        FIXME("Ignoring fQOP 0x%08x\n", fQOP);
+
+    if(MessageSeqNo)
+        FIXME("Ignoring MessageSeqNo\n");
+
+    if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
+        return SEC_E_INVALID_TOKEN;
+
+    /* If we didn't find a SECBUFFER_TOKEN type buffer */
+    if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1)
+        return SEC_E_INVALID_TOKEN;
+
+    token_buffer.length = pMessage->pBuffers[token_idx].cbBuffer;
+    token_buffer.value = pMessage->pBuffers[token_idx].pvBuffer;
+
+    /* Note: gssapi doesn't support multiple buffers like SSPI does, so we only
+     * takes the first buffer */
+    for (message_idx = 0; message_idx < pMessage->cBuffers; ++message_idx)
+    {
+        if (pMessage->pBuffers[message_idx].BufferType & SECBUFFER_DATA)
+            break;
+    }
+    if (message_idx == pMessage->cBuffers)
+        return SEC_E_INVALID_TOKEN;
+
+    message_buffer.length = pMessage->pBuffers[token_idx].cbBuffer;
+    message_buffer.value = pMessage->pBuffers[token_idx].pvBuffer;
+
+    ret = p_gss_get_mic(&minor_status, context_handle, qop, &message_buffer, &token_buffer);
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *              VerifySignature
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(PCtxtHandle phContext,
+ PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
+{
+    int token_idx, message_idx;
+    OM_uint32 minor_status;
+    OM_uint32 ret;
+    gss_buffer_desc token_buffer;
+    gss_buffer_desc message_buffer;
+    gss_ctx_id_t context_handle;
+    gss_qop_t qop_state;
+
+    TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
+
+    if(!phContext)
+        return SEC_E_INVALID_HANDLE;
+
+    context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext);
+
+    if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
+        return SEC_E_INVALID_TOKEN;
+
+    if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1)
+        return SEC_E_INVALID_TOKEN;
+
+    if(MessageSeqNo)
+        FIXME("Ignoring MessageSeqNo\n");
+
+    /* If we didn't find a SECBUFFER_TOKEN type buffer */
+    if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1)
+        return SEC_E_INVALID_TOKEN;
+
+    token_buffer.length = pMessage->pBuffers[token_idx].cbBuffer;
+    token_buffer.value = pMessage->pBuffers[token_idx].pvBuffer;
+
+    /* Note: gssapi doesn't support multiple buffers like SSPI does, so we only
+     * takes the first buffer */
+    for (message_idx = 0; message_idx < pMessage->cBuffers; ++message_idx)
+    {
+        if (pMessage->pBuffers[message_idx].BufferType & SECBUFFER_DATA)
+            break;
+    }
+    if (message_idx == pMessage->cBuffers)
+        return SEC_E_INVALID_TOKEN;
+
+    message_buffer.length = pMessage->pBuffers[token_idx].cbBuffer;
+    message_buffer.value = pMessage->pBuffers[token_idx].pvBuffer;
+
+    ret = p_gss_verify_mic(&minor_status, context_handle, &message_buffer,
+                         &token_buffer, &qop_state);
+
+    *pfQOP = 0;
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *             FreeCredentialsHandle
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(
+        PCredHandle phCredential)
+{
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+
+    TRACE("(%p)\n", phCredential);
+
+    if (phCredential)
+    {
+        gss_cred_id_t cred_handle = kerberos_CredHandleSSPItoGSSAPI(phCredential);
+
+        HeapFree(GetProcessHeap(), 0, cred_handle);
+
+        phCredential->dwUpper = 0;
+        phCredential->dwLower = 0;
+
+        return kerberos_GSSAPIStatusToSecurityStatus(ret);
+    }
+    else
+        return SEC_E_OK;
+}
+
+/***********************************************************************
+ *             FreeContextBuffer (KERBEROS.@)
+ */
+SECURITY_STATUS WINAPI kerberos_FreeContextBuffer(PVOID pv)
+{
+    HeapFree(GetProcessHeap(), 0, pv);
+
+    return SEC_E_OK;
+}
+
+/***********************************************************************
+ *             EncryptMessage
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_EncryptMessage(PCtxtHandle phContext,
+        ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
+{
+    gss_ctx_id_t context_handle;
+    int token_idx, data_idx;
+    gss_qop_t qop_req = GSS_C_QOP_DEFAULT;
+    int conf_state;
+    gss_buffer_desc input_message_buffer;
+    gss_buffer_desc output_message_buffer;
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+
+    TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo);
+
+    if(!phContext)
+        return SEC_E_INVALID_HANDLE;
+    context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext);
+
+    if(fQOP && (fQOP != SECQOP_WRAP_NO_ENCRYPT))
+        FIXME("Ignoring fQOP 0x%x\n", fQOP);
+
+    if(MessageSeqNo)
+        FIXME("Ignoring MessageSeqNo\n");
+
+    if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
+        return SEC_E_INVALID_TOKEN;
+
+    if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1)
+        return SEC_E_INVALID_TOKEN;
+
+    if((data_idx = kerberos_GetDataBufferIndex(pMessage)) ==-1 )
+        return SEC_E_INVALID_TOKEN;
+
+    input_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer;
+    input_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer;
+
+    /* FIXME: does gss_wrap allow overlapping buffers? */
+    output_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer;
+    output_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer;
+
+    /* FIXME: sign data and store it in token */
+
+    ret = p_gss_wrap(&minor_status, context_handle,
+                   (fQOP == SECQOP_WRAP_NO_ENCRYPT) ? FALSE : TRUE, qop_req,
+                   &input_message_buffer, &conf_state, &output_message_buffer);
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+/***********************************************************************
+ *             DecryptMessage
+ */
+static SECURITY_STATUS SEC_ENTRY kerberos_DecryptMessage(PCtxtHandle phContext,
+        PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
+{
+    gss_ctx_id_t context_handle;
+    OM_uint32 ret;
+    OM_uint32 minor_status;
+    int token_idx, data_idx;
+    gss_buffer_desc input_message_buffer;
+    gss_buffer_desc output_message_buffer;
+    gss_qop_t qop_req;
+    int conf_state;
+
+    TRACE("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP);
+
+    if(!phContext)
+        return SEC_E_INVALID_HANDLE;
+
+    context_handle = kerberos_CtxtHandleSSPItoGSSAPI(phContext);
+
+    if(MessageSeqNo)
+        FIXME("Ignoring MessageSeqNo\n");
+
+    if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
+        return SEC_E_INVALID_TOKEN;
+
+    if((token_idx = kerberos_GetTokenBufferIndex(pMessage)) == -1)
+        return SEC_E_INVALID_TOKEN;
+
+    if((data_idx = kerberos_GetDataBufferIndex(pMessage)) ==-1)
+        return SEC_E_INVALID_TOKEN;
+
+    input_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer;
+    input_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer;
+
+    /* FIXME: does gss_wrap allow overlapping buffers? */
+    output_message_buffer.length = pMessage->pBuffers[data_idx].cbBuffer;
+    output_message_buffer.value = pMessage->pBuffers[data_idx].pvBuffer;
+
+    ret = p_gss_unwrap(&minor_status, context_handle, &input_message_buffer,
+                     &output_message_buffer, &conf_state, &qop_req);
+
+    *pfQOP = 0;
+
+    /* FIXME: verify data using token */
+
+    return kerberos_GSSAPIStatusToSecurityStatus(ret);
+}
+
+static SecurityFunctionTableA gssKerberosTableA = {
+    SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
+    kerberos_EnumerateSecurityPackagesA,    /* EnumerateSecurityPackagesA */
+    kerberos_QueryCredentialsAttributesA,   /* QueryCredentialsAttributesA */
+    kerberos_AcquireCredentialsHandleA,     /* AcquireCredentialsHandleA */
+    kerberos_FreeCredentialsHandle,         /* FreeCredentialsHandle */
+    NULL,   /* Reserved2 */
+    kerberos_InitializeSecurityContextA,    /* InitializeSecurityContextA */
+    kerberos_AcceptSecurityContext,         /* AcceptSecurityContext */
+    kerberos_CompleteAuthToken,             /* CompleteAuthToken */
+    kerberos_DeleteSecurityContext,         /* DeleteSecurityContext */
+    NULL,  /* ApplyControlToken */
+    kerberos_QueryContextAttributesA,       /* QueryContextAttributesA */
+    kerberos_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
+    kerberos_RevertSecurityContext,         /* RevertSecurityContext */
+    kerberos_MakeSignature,                 /* MakeSignature */
+    kerberos_VerifySignature,               /* VerifySignature */
+    kerberos_FreeContextBuffer,             /* FreeContextBuffer */
+    NULL,   /* QuerySecurityPackageInfoA */
+    NULL,   /* Reserved3 */
+    NULL,   /* Reserved4 */
+    NULL,   /* ExportSecurityContext */
+    NULL,   /* ImportSecurityContextA */
+    NULL,   /* AddCredentialsA */
+    NULL,   /* Reserved8 */
+    NULL,   /* QuerySecurityContextToken */
+    kerberos_EncryptMessage,                /* EncryptMessage */
+    kerberos_DecryptMessage,                /* DecryptMessage */
+    NULL,   /* SetContextAttributesA */
+};
+
+static SecurityFunctionTableW gssKerberosTableW = {
+    SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
+    kerberos_EnumerateSecurityPackagesW,    /* EnumerateSecurityPackagesW */
+    kerberos_QueryCredentialsAttributesW,   /* QueryCredentialsAttributesW */
+    kerberos_AcquireCredentialsHandleW,     /* AcquireCredentialsHandleW */
+    kerberos_FreeCredentialsHandle,         /* FreeCredentialsHandle */
+    NULL,   /* Reserved2 */
+    kerberos_InitializeSecurityContextW,    /* InitializeSecurityContextW */
+    kerberos_AcceptSecurityContext,         /* AcceptSecurityContext */
+    kerberos_CompleteAuthToken,             /* CompleteAuthToken */
+    kerberos_DeleteSecurityContext,         /* DeleteSecurityContext */
+    NULL,  /* ApplyControlToken */
+    kerberos_QueryContextAttributesW,       /* QueryContextAttributesW */
+    kerberos_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
+    kerberos_RevertSecurityContext,         /* RevertSecurityContext */
+    kerberos_MakeSignature,                 /* MakeSignature */
+    kerberos_VerifySignature,               /* VerifySignature */
+    kerberos_FreeContextBuffer,             /* FreeContextBuffer */
+    NULL,   /* QuerySecurityPackageInfoW */
+    NULL,   /* Reserved3 */
+    NULL,   /* Reserved4 */
+    NULL,   /* ExportSecurityContext */
+    NULL,   /* ImportSecurityContextW */
+    NULL,   /* AddCredentialsW */
+    NULL,   /* Reserved8 */
+    NULL,   /* QuerySecurityContextToken */
+    kerberos_EncryptMessage,                /* EncryptMessage */
+    kerberos_DecryptMessage,                /* DecryptMessage */
+    NULL,   /* SetContextAttributesW */
+};
+
+
+/***********************************************************************
+ *            InitSecurityInterfaceA (KERBEROS.@)
+ */
+PSecurityFunctionTableA WINAPI InitSecurityInterfaceA(void)
+{
+    if (!load_gssapi())
+    {
+        return NULL;
+    }
+
+    return &gssKerberosTableA;
+}
+
+/***********************************************************************
+ *            InitSecurityInterfaceW (KERBEROS.@)
+ */
+PSecurityFunctionTableW WINAPI InitSecurityInterfaceW(void)
+{
+    if (!load_gssapi())
+    {
+        return NULL;
+    }
+
+    return &gssKerberosTableW;
+}
diff --git a/wine/dlls/secur32/Makefile.in b/wine/dlls/secur32/Makefile.in
index 6548521..c9acdee 100644
--- a/wine/dlls/secur32/Makefile.in
+++ b/wine/dlls/secur32/Makefile.in
@@ -9,7 +9,6 @@ C_SRCS = \
 	base64_codec.c \
 	dispatcher.c \
 	hmac_md5.c \
-	kerberos.c \
 	lsa.c \
 	negotiate.c \
 	ntlm.c \
diff --git a/wine/dlls/secur32/kerberos.c b/wine/dlls/secur32/kerberos.c
deleted file mode 100644
index 753e974..0000000
--- a/wine/dlls/secur32/kerberos.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright 2005, 2006 Kai Blin
- * Copyright 2016 Jacek Caban for CodeWeavers
- *
- * 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 <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "rpc.h"
-#include "sspi.h"
-
-#include "secur32_priv.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(secur32);
-
-#define KERBEROS_MAX_BUF 12000
-
-/***********************************************************************
- *              QueryCredentialsAttributesA
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesA(CredHandle *phCredential, ULONG ulAttribute, void *pBuffer)
-{
-    FIXME("(%p %d %p)\n", phCredential, ulAttribute, pBuffer);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              QueryCredentialsAttributesW
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW(CredHandle *phCredential, ULONG ulAttribute, void *pBuffer)
-{
-    FIXME("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              AcquireCredentialsHandleW
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleW(SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
-        LUID *pLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pGetKeyArgument, CredHandle *phCredential, TimeStamp *ptsExpiry)
-{
-    FIXME("(%s %s 0x%08x %p %p %p %p %p %p)\n", debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
-          pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
-    return SEC_E_NO_CREDENTIALS;
-}
-
-/***********************************************************************
- *              AcquireCredentialsHandleA
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
-        LUID *pLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pGetKeyArgument, CredHandle *phCredential, TimeStamp *ptsExpiry)
-{
-    FIXME("(%s %s 0x%08x %p %p %p %p %p %p)\n", debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
-          pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              InitializeSecurityContextW
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW(CredHandle *phCredential, CtxtHandle *phContext, SEC_WCHAR *pszTargetName,
-        ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext,
-        SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry)
-{
-    FIXME("(%p %p %s 0x%08x %d %d %p %d %p %p %p %p)\n", phCredential, phContext, debugstr_w(pszTargetName),
-          fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              InitializeSecurityContextA
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(CredHandle *phCredential, CtxtHandle *phContext, SEC_CHAR *pszTargetName,
-        ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext,
-        SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry)
-{
-    FIXME("%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);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              AcceptSecurityContext
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_AcceptSecurityContext(CredHandle *phCredential, CtxtHandle *phContext, SecBufferDesc *pInput,
-        ULONG fContextReq, ULONG TargetDataRep, CtxtHandle *phNewContext, SecBufferDesc *pOutput, ULONG *pfContextAttr, TimeStamp *ptsExpiry)
-{
-    FIXME("(%p %p %p %d %d %p %p %p %p)\n", phCredential, phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput,
-          pfContextAttr, ptsExpiry);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              CompleteAuthToken
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_CompleteAuthToken(CtxtHandle *phContext, SecBufferDesc *pToken)
-{
-    FIXME("(%p %p)\n", phContext, pToken);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              DeleteSecurityContext
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(CtxtHandle *phContext)
-{
-    FIXME("(%p)\n", phContext);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              QueryContextAttributesW
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesW(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer)
-{
-    FIXME("(%p %d %p)\n", phContext, ulAttribute, pBuffer);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              QueryContextAttributesA
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer)
-{
-    FIXME("(%p %d %p)\n", phContext, ulAttribute, pBuffer);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              ImpersonateSecurityContext
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_ImpersonateSecurityContext(CtxtHandle *phContext)
-{
-    FIXME("(%p)\n", phContext);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              RevertSecurityContext
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_RevertSecurityContext(CtxtHandle *phContext)
-{
-    FIXME("(%p)\n", phContext);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              MakeSignature
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_MakeSignature(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo)
-{
-    FIXME("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *              VerifySignature
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, PULONG pfQOP)
-{
-    FIXME("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *             FreeCredentialsHandle
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(PCredHandle phCredential)
-{
-    FIXME("(%p)\n", phCredential);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *             EncryptMessage
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_EncryptMessage(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo)
-{
-    FIXME("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-/***********************************************************************
- *             DecryptMessage
- */
-static SECURITY_STATUS SEC_ENTRY kerberos_DecryptMessage(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, PULONG pfQOP)
-{
-    FIXME("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP);
-    return SEC_E_UNSUPPORTED_FUNCTION;
-}
-
-static const SecurityFunctionTableA kerberosTableA = {
-    1,
-    NULL,   /* EnumerateSecurityPackagesA */
-    kerberos_QueryCredentialsAttributesA,   /* QueryCredentialsAttributesA */
-    kerberos_AcquireCredentialsHandleA,     /* AcquireCredentialsHandleA */
-    kerberos_FreeCredentialsHandle,         /* FreeCredentialsHandle */
-    NULL,   /* Reserved2 */
-    kerberos_InitializeSecurityContextA,    /* InitializeSecurityContextA */
-    kerberos_AcceptSecurityContext,         /* AcceptSecurityContext */
-    kerberos_CompleteAuthToken,             /* CompleteAuthToken */
-    kerberos_DeleteSecurityContext,         /* DeleteSecurityContext */
-    NULL,  /* ApplyControlToken */
-    kerberos_QueryContextAttributesA,       /* QueryContextAttributesA */
-    kerberos_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
-    kerberos_RevertSecurityContext,         /* RevertSecurityContext */
-    kerberos_MakeSignature,                 /* MakeSignature */
-    kerberos_VerifySignature,               /* VerifySignature */
-    FreeContextBuffer,                      /* FreeContextBuffer */
-    NULL,   /* QuerySecurityPackageInfoA */
-    NULL,   /* Reserved3 */
-    NULL,   /* Reserved4 */
-    NULL,   /* ExportSecurityContext */
-    NULL,   /* ImportSecurityContextA */
-    NULL,   /* AddCredentialsA */
-    NULL,   /* Reserved8 */
-    NULL,   /* QuerySecurityContextToken */
-    kerberos_EncryptMessage,                /* EncryptMessage */
-    kerberos_DecryptMessage,                /* DecryptMessage */
-    NULL,   /* SetContextAttributesA */
-};
-
-static const SecurityFunctionTableW kerberosTableW = {
-    1,
-    NULL,   /* EnumerateSecurityPackagesW */
-    kerberos_QueryCredentialsAttributesW,   /* QueryCredentialsAttributesW */
-    kerberos_AcquireCredentialsHandleW,     /* AcquireCredentialsHandleW */
-    kerberos_FreeCredentialsHandle,         /* FreeCredentialsHandle */
-    NULL,   /* Reserved2 */
-    kerberos_InitializeSecurityContextW,    /* InitializeSecurityContextW */
-    kerberos_AcceptSecurityContext,         /* AcceptSecurityContext */
-    kerberos_CompleteAuthToken,             /* CompleteAuthToken */
-    kerberos_DeleteSecurityContext,         /* DeleteSecurityContext */
-    NULL,  /* ApplyControlToken */
-    kerberos_QueryContextAttributesW,       /* QueryContextAttributesW */
-    kerberos_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
-    kerberos_RevertSecurityContext,         /* RevertSecurityContext */
-    kerberos_MakeSignature,                 /* MakeSignature */
-    kerberos_VerifySignature,               /* VerifySignature */
-    FreeContextBuffer,                      /* FreeContextBuffer */
-    NULL,   /* QuerySecurityPackageInfoW */
-    NULL,   /* Reserved3 */
-    NULL,   /* Reserved4 */
-    NULL,   /* ExportSecurityContext */
-    NULL,   /* ImportSecurityContextW */
-    NULL,   /* AddCredentialsW */
-    NULL,   /* Reserved8 */
-    NULL,   /* QuerySecurityContextToken */
-    kerberos_EncryptMessage,                /* EncryptMessage */
-    kerberos_DecryptMessage,                /* DecryptMessage */
-    NULL,   /* SetContextAttributesW */
-};
-
-#define KERBEROS_COMMENT \
-    {'M','i','c','r','o','s','o','f','t',' ','K','e','r','b','e','r','o','s',' ','V','1','.','0',0}
-static CHAR kerberos_comment_A[] = KERBEROS_COMMENT;
-static WCHAR kerberos_comment_W[] = KERBEROS_COMMENT;
-
-#define KERBEROS_NAME {'K','e','r','b','e','r','o','s',0}
-static char kerberos_name_A[] = KERBEROS_NAME;
-static WCHAR kerberos_name_W[] = KERBEROS_NAME;
-
-#define CAPS \
-    ( SECPKG_FLAG_INTEGRITY \
-    | SECPKG_FLAG_PRIVACY \
-    | SECPKG_FLAG_TOKEN_ONLY \
-    | SECPKG_FLAG_DATAGRAM \
-    | SECPKG_FLAG_CONNECTION \
-    | SECPKG_FLAG_MULTI_REQUIRED \
-    | SECPKG_FLAG_EXTENDED_ERROR \
-    | SECPKG_FLAG_IMPERSONATION \
-    | SECPKG_FLAG_ACCEPT_WIN32_NAME \
-    | SECPKG_FLAG_NEGOTIABLE \
-    | SECPKG_FLAG_GSS_COMPATIBLE \
-    | SECPKG_FLAG_LOGON \
-    | SECPKG_FLAG_MUTUAL_AUTH \
-    | SECPKG_FLAG_DELEGATION \
-    | SECPKG_FLAG_READONLY_WITH_CHECKSUM \
-    | SECPKG_FLAG_RESTRICTED_TOKENS \
-    | SECPKG_FLAG_APPCONTAINER_CHECKS)
-
-static const SecPkgInfoW infoW = {
-    CAPS,
-    1,
-    RPC_C_AUTHN_GSS_KERBEROS,
-    KERBEROS_MAX_BUF,
-    kerberos_name_W,
-    kerberos_comment_W
-};
-
-static const SecPkgInfoA infoA = {
-    CAPS,
-    1,
-    RPC_C_AUTHN_GSS_KERBEROS,
-    KERBEROS_MAX_BUF,
-    kerberos_name_A,
-    kerberos_comment_A
-};
-
-void SECUR32_initKerberosSP(void)
-{
-    SecureProvider *provider = SECUR32_addProvider(&kerberosTableA, &kerberosTableW, NULL);
-    SECUR32_addPackages(provider, 1, &infoA, &infoW);
-}
diff --git a/wine/dlls/secur32/secur32.c b/wine/dlls/secur32/secur32.c
index f5d5746..b5bdaf2 100644
--- a/wine/dlls/secur32/secur32.c
+++ b/wine/dlls/secur32/secur32.c
@@ -439,7 +439,7 @@ SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
         ret->moduleName = SECUR32_strdupW(moduleName);
         ret->loaded = FALSE;
     }
-    
+
     LeaveCriticalSection(&cs);
     return ret;
 }
@@ -466,7 +466,7 @@ void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
         packageTable->numPackages = 0;
         list_init(&packageTable->table);
     }
-        
+
     for (i = 0; i < toAdd; i++)
     {
         SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
@@ -488,7 +488,6 @@ void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
 static void _tryLoadProvider(PWSTR moduleName)
 {
     HMODULE lib = LoadLibraryW(moduleName);
-
     if (lib)
     {
         INIT_SECURITY_INTERFACE_W pInitSecurityInterfaceW =
@@ -555,7 +554,7 @@ static const WCHAR securityProvidersKeyW[] = {
 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)
 {
     HKEY key;
@@ -565,12 +564,9 @@ static void SECUR32_initializeProviders(void)
     /* First load built-in providers */
     SECUR32_initSchannelSP();
     SECUR32_initNTLMSP();
-    SECUR32_initKerberosSP();
-    /* Load the Negotiate provider last so apps stumble over the working NTLM
-     * provider first. Attempting to fix bug #16905 while keeping the
-     * application reported on wine-users on 2006-09-12 working. */
-    SECUR32_initNegotiateSP();
+
     /* Now load providers from registry */
+    TRACE("Loading providers from registry...\n");
     apiRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, securityProvidersKeyW, 0,
      KEY_READ, &key);
     if (apiRet == ERROR_SUCCESS)
@@ -604,6 +600,11 @@ static void SECUR32_initializeProviders(void)
         }
         RegCloseKey(key);
     }
+
+    /* Load the Negotiate provider last so apps stumble over the working NTLM
+     * provider first. Attempting to fix bug #16905 while keeping the
+     * application reported on wine-users on 2006-09-12 working. */
+    SECUR32_initNegotiateSP();
 }
 
 SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
@@ -616,14 +617,14 @@ SecurePackage *SECUR32_findPackageW(PCWSTR packageName)
         LIST_FOR_EACH_ENTRY(ret, &packageTable->table, SecurePackage, entry)
         {
             matched = !lstrcmpiW(ret->infoW.Name, packageName);
-	    if (matched)
-		break;
+            if (matched)
+                break;
         }
-        
-	if (!matched)
-		return NULL;
 
-	if (ret->provider && !ret->provider->loaded)
+        if (!matched)
+            return NULL;
+
+        if (ret->provider && !ret->provider->loaded)
         {
             ret->provider->lib = LoadLibraryW(ret->provider->moduleName);
             if (ret->provider->lib)
@@ -913,7 +914,7 @@ SECURITY_STATUS WINAPI EnumerateSecurityPackagesA(PULONG pcPackages,
  *  nSize returns the number of characters written when lpNameBuffer is not
  *  NULL or the size of the buffer needed to hold the name when the buffer
  *  is too short or lpNameBuffer is NULL.
- * 
+ *
  *  It the buffer is too short, ERROR_INSUFFICIENT_BUFFER error will be set.
  */
 BOOLEAN WINAPI GetComputerObjectNameA(
diff --git a/wine/include/config.h.in b/wine/include/config.h.in
index 00503a3..7e4ddc5 100644
--- a/wine/include/config.h.in
+++ b/wine/include/config.h.in
@@ -285,6 +285,9 @@
 /* Define to 1 if you have the <gsm.h> header file. */
 #undef HAVE_GSM_H
 
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_KRB5_H
+
 /* Define to 1 if you have the <ieeefp.h> header file. */
 #undef HAVE_IEEEFP_H
 
@@ -1475,6 +1478,9 @@
 /* Define to the soname of the libgsm library. */
 #undef SONAME_LIBGSM
 
+/* Define to the soname of the libgssapi_krb5 library. */
+#undef SONAME_LIBGSSAPI_KRB5
+
 /* Define to the soname of the libhal library. */
 #undef SONAME_LIBHAL
 
diff --git a/wine/loader/wine.inf.in b/wine/loader/wine.inf.in
index 787ad7f..0a9f8c3 100644
--- a/wine/loader/wine.inf.in
+++ b/wine/loader/wine.inf.in
@@ -683,6 +683,8 @@ HKLM,Software\Policies,,16
 HKLM,Software\Registered Applications,,16
 HKLM,System\CurrentControlSet\Control\hivelist,,16
 HKLM,System\CurrentControlSet\Control\Lsa\Kerberos,,16
+HKLM,System\CurrentControlSet\Control\Lsa\Kerberos,,16
+HKLM,System\CurrentControlSet\Control\SecurityProviders,"SecurityProviders",,"kerberos"
 HKLM,System\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols\SSL 2.0\Client,"DisabledByDefault",0x10003,1
 HKLM,System\CurrentControlSet\Control\ServiceGroupOrder,"List",0x00010000,"TDI"
 HKLM,System\CurrentControlSet\Control\TimeZoneInformation,"StandardName",2,""
-- 
2.10.4

