[01/10] secur32: Implement AcquireCredentialsHandle for Kerberos.
Hans Leidekker
hans at codeweavers.com
Mon Oct 23 04:09:16 CDT 2017
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
configure.ac | 18 +++
dlls/secur32/Makefile.in | 2 +-
dlls/secur32/kerberos.c | 276 +++++++++++++++++++++++++++++++++++++++++---
dlls/secur32/secur32.c | 1 +
dlls/secur32/secur32_priv.h | 1 +
5 files changed, 282 insertions(+), 16 deletions(-)
diff --git a/configure.ac b/configure.ac
index 3f5f89f935..48b2c7fdb1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,6 +53,7 @@ AC_ARG_WITH(glu, AS_HELP_STRING([--without-glu],[do not use the GLU librar
AC_ARG_WITH(gnutls, AS_HELP_STRING([--without-gnutls],[do not use GnuTLS (schannel support)]))
AC_ARG_WITH(gsm, AS_HELP_STRING([--without-gsm],[do not use libgsm (GSM 06.10 codec support)]),
[if test "x$withval" = "xno"; then ac_cv_header_gsm_h=no; ac_cv_header_gsm_gsm_h=no; fi])
+AC_ARG_WITH(gssapi, AS_HELP_STRING([--without-gssapi],[do not use GSSAPI (Kerberos SSP support)]))
AC_ARG_WITH(gstreamer, AS_HELP_STRING([--without-gstreamer],[do not use GStreamer (codecs support)]))
AC_ARG_WITH(hal, AS_HELP_STRING([--without-hal],[do not use HAL (dynamic device support)]))
AC_ARG_WITH(jpeg, AS_HELP_STRING([--without-jpeg],[do not use JPEG]))
@@ -1643,6 +1644,23 @@ fi
WINE_NOTICE_WITH(krb5,[test "x$ac_cv_lib_soname_krb5" = "x"],
[libkrb5 ${notice_platform}development files not found, Kerberos won't be supported.])
+dnl **** Check for gssapi ****
+if test "x$with_gssapi" != "xno"
+then
+ WINE_PACKAGE_FLAGS(GSSAPI,[krb5-gssapi],,
+ [`${KRB5_CONFIG:-krb5-config} --cflags gssapi 2>/dev/null`],
+ [`${KRB5_CONFIG:-krb5-config} --libs gssapi 2>/dev/null`],
+ [AC_CHECK_HEADERS([gssapi/gssapi.h gssapi/gssapi_ext.h])
+ if test "$ac_cv_header_gssapi_gssapi_h" = "yes" -a "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"
+ then
+ WINE_CHECK_SONAME(gssapi_krb5, gss_init_sec_context,,[GSSAPI_LIBS=""],[$GSSAPI_LIBS])
+ else
+ GSSAPI_CFLAGS=""
+ fi])
+fi
+WINE_WARNING_WITH(gssapi,[test "x$ac_cv_lib_soname_gssapi_krb5" = "x"],
+ [libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support.])
+
dnl **** Check for libjpeg ****
if test "x$with_jpeg" != "xno"
then
diff --git a/dlls/secur32/Makefile.in b/dlls/secur32/Makefile.in
index 6548521f53..16870b4c86 100644
--- a/dlls/secur32/Makefile.in
+++ b/dlls/secur32/Makefile.in
@@ -2,7 +2,7 @@ MODULE = secur32.dll
IMPORTLIB = secur32
IMPORTS = netapi32 advapi32
DELAYIMPORTS = crypt32
-EXTRAINCL = $(GNUTLS_CFLAGS)
+EXTRAINCL = $(GNUTLS_CFLAGS) $(GSSAPI_CFLAGS)
EXTRALIBS = $(SECURITY_LIBS)
C_SRCS = \
diff --git a/dlls/secur32/kerberos.c b/dlls/secur32/kerberos.c
index 753e9748d2..67404b72f2 100644
--- a/dlls/secur32/kerberos.c
+++ b/dlls/secur32/kerberos.c
@@ -1,6 +1,8 @@
/*
* Copyright 2005, 2006 Kai Blin
+ * Copyright 2008 Robert Shearman for CodeWeavers
* Copyright 2016 Jacek Caban for CodeWeavers
+ * Copyright 2017 Hans Leidekker for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,9 +19,15 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include <assert.h>
+#include "config.h"
+#include "wine/port.h"
+
#include <stdarg.h>
#include <stdio.h>
+#ifdef SONAME_LIBGSSAPI_KRB5
+# include <gssapi/gssapi.h>
+# include <gssapi/gssapi_ext.h>
+#endif
#include "windef.h"
#include "winbase.h"
@@ -27,12 +35,119 @@
#include "sspi.h"
#include "secur32_priv.h"
-
#include "wine/debug.h"
+#include "wine/library.h"
WINE_DEFAULT_DEBUG_CHANNEL(secur32);
-#define KERBEROS_MAX_BUF 12000
+#ifdef SONAME_LIBGSSAPI_KRB5
+
+WINE_DECLARE_DEBUG_CHANNEL(winediag);
+static void *libgssapi_krb5_handle;
+
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
+MAKE_FUNCPTR(gss_acquire_cred);
+MAKE_FUNCPTR(gss_import_name);
+MAKE_FUNCPTR(gss_release_name);
+#undef MAKE_FUNCPTR
+
+static BOOL load_gssapi_krb5(void)
+{
+ if (!(libgssapi_krb5_handle = wine_dlopen( SONAME_LIBGSSAPI_KRB5, RTLD_NOW, NULL, 0 )))
+ {
+ ERR_(winediag)( "Failed to load libgssapi_krb5, Kerberos SSP support will not be available.\n" );
+ return FALSE;
+ }
+
+#define LOAD_FUNCPTR(f) \
+ if (!(p##f = wine_dlsym( libgssapi_krb5_handle, #f, NULL, 0 ))) \
+ { \
+ ERR( "Failed to load %s\n", #f ); \
+ goto fail; \
+ }
+
+ LOAD_FUNCPTR(gss_acquire_cred)
+ LOAD_FUNCPTR(gss_import_name)
+ LOAD_FUNCPTR(gss_release_name)
+#undef LOAD_FUNCPTR
+
+ return TRUE;
+
+fail:
+ wine_dlclose( libgssapi_krb5_handle, NULL, 0 );
+ libgssapi_krb5_handle = NULL;
+ return FALSE;
+}
+
+static void unload_gssapi_krb5(void)
+{
+ wine_dlclose( libgssapi_krb5_handle, NULL, 0 );
+ libgssapi_krb5_handle = NULL;
+}
+
+static inline void credhandle_gss_to_sspi( gss_cred_id_t handle, gss_name_t principal, CredHandle *cred )
+{
+ cred->dwLower = (DWORD_PTR)handle;
+ cred->dwUpper = (DWORD_PTR)principal;
+}
+
+static SECURITY_STATUS status_gss_to_sspi( 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_INVALID_TOKEN;
+ case GSS_S_DEFECTIVE_CREDENTIAL: return SEC_E_NO_CREDENTIALS;
+ 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%08x to SECURITY_STATUS\n", status );
+ return SEC_E_INTERNAL_ERROR;
+ }
+}
+
+static void expirytime_gss_to_sspi( OM_uint32 expirytime, TimeStamp *timestamp )
+{
+ SYSTEMTIME time;
+ FILETIME filetime;
+ ULARGE_INTEGER tmp;
+
+ GetLocalTime( &time );
+ SystemTimeToFileTime( &time, &filetime );
+ tmp.QuadPart = ((ULONGLONG)filetime.dwLowDateTime | (ULONGLONG)filetime.dwHighDateTime << 32) + expirytime;
+ timestamp->LowPart = tmp.QuadPart;
+ timestamp->HighPart = tmp.QuadPart >> 32;
+}
+
+static SECURITY_STATUS name_sspi_to_gss( const SEC_WCHAR *name_str, gss_name_t *name )
+{
+ OM_uint32 ret, minor_status;
+ gss_OID type = GSS_C_NO_OID; /* FIXME: detect the appropriate value for this ourselves? */
+ gss_buffer_desc buf;
+
+ buf.length = WideCharToMultiByte( CP_UNIXCP, 0, name_str, -1, NULL, 0, NULL, NULL );
+ if (!(buf.value = HeapAlloc( GetProcessHeap(), 0, buf.length ))) return SEC_E_INSUFFICIENT_MEMORY;
+ WideCharToMultiByte( CP_UNIXCP, 0, name_str, -1, buf.value, buf.length, NULL, NULL );
+ buf.length--;
+
+ ret = pgss_import_name( &minor_status, &buf, type, name );
+ TRACE( "gss_import_name returned %08x minor status %08x\n", ret, minor_status );
+
+ HeapFree( GetProcessHeap(), 0, buf.value );
+ return status_gss_to_sspi( ret );
+}
+#endif
/***********************************************************************
* QueryCredentialsAttributesA
@@ -55,23 +170,135 @@ static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW(CredHandle
/***********************************************************************
* 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)
+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;
+#ifdef SONAME_LIBGSSAPI_KRB5
+ OM_uint32 ret, minor_status, expiry_time;
+ gss_name_t principal = GSS_C_NO_NAME;
+ gss_cred_usage_t cred_usage;
+ gss_cred_id_t cred_handle;
+
+ 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)
+ {
+ 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:
+ return SEC_E_UNKNOWN_CREDENTIALS;
+ }
+
+ if (pszPrincipal && ((ret = name_sspi_to_gss( pszPrincipal, &principal )) != SEC_E_OK)) return ret;
+
+ ret = pgss_acquire_cred( &minor_status, principal, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, cred_usage,
+ &cred_handle, NULL, &expiry_time );
+ TRACE( "gss_acquire_cred returned %08x minor status %08x\n", ret, minor_status );
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED)
+ {
+ credhandle_gss_to_sspi( cred_handle, principal, phCredential );
+ expirytime_gss_to_sspi( expiry_time, ptsExpiry );
+ }
+ else if (principal != GSS_C_NO_NAME) pgss_release_name( &minor_status, &principal );
+
+ return status_gss_to_sspi( ret );
+#else
+ 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 );
+ FIXME( "Wine was built without Kerberos support.\n" );
+ return SEC_E_UNSUPPORTED_FUNCTION;
+#endif
}
/***********************************************************************
* 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)
+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;
+ SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY;
+ int len_user = 0, len_domain = 0, len_passwd = 0;
+ SEC_WCHAR *principal = NULL, *package = NULL, *user = NULL, *domain = NULL, *passwd = NULL;
+ SEC_WINNT_AUTH_IDENTITY_W *authdata = NULL;
+ SEC_WINNT_AUTH_IDENTITY_A *id = 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 (pszPrincipal)
+ {
+ int len = MultiByteToWideChar( CP_ACP, 0, pszPrincipal, -1, NULL, 0 );
+ if (!(principal = HeapAlloc( GetProcessHeap(), 0, len * sizeof(SEC_WCHAR) ))) goto done;
+ MultiByteToWideChar( CP_ACP, 0, pszPrincipal, -1, principal, len );
+ }
+ if (pszPackage)
+ {
+ int len = MultiByteToWideChar( CP_ACP, 0, pszPackage, -1, NULL, 0 );
+ if (!(package = HeapAlloc( GetProcessHeap(), 0, len * sizeof(SEC_WCHAR) ))) goto done;
+ MultiByteToWideChar( CP_ACP, 0, pszPackage, -1, package, len );
+ }
+ if (pAuthData)
+ {
+ id = (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData;
+ if (id->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
+ {
+ if (!(authdata = HeapAlloc( GetProcessHeap(), 0, sizeof(SEC_WINNT_AUTH_IDENTITY_W) ))) goto done;
+ if (id->UserLength)
+ {
+ len_user = MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, NULL, 0 );
+ if (!(user = HeapAlloc( GetProcessHeap(), 0, len_user * sizeof(SEC_WCHAR) ))) goto done;
+ MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, user, len_user );
+ }
+ if (id->DomainLength)
+ {
+ len_domain = MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, NULL, 0 );
+ if (!(domain = HeapAlloc( GetProcessHeap(), 0, len_domain * sizeof(SEC_WCHAR) ))) goto done;
+ MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, domain, len_domain );
+ }
+ if (id->PasswordLength)
+ {
+ len_passwd = MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, NULL, 0 );
+ if (!(passwd = HeapAlloc( GetProcessHeap(), 0, len_passwd * sizeof(SEC_WCHAR) ))) goto done;
+ MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, passwd, len_passwd );
+ }
+ authdata->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+ authdata->User = user;
+ authdata->UserLength = len_user;
+ authdata->Domain = domain;
+ authdata->DomainLength = len_domain;
+ authdata->Password = passwd;
+ authdata->PasswordLength = len_passwd;
+ }
+ else authdata = (PSEC_WINNT_AUTH_IDENTITY_W)id;
+ }
+
+ ret = kerberos_AcquireCredentialsHandleW( principal, package, fCredentialUse, pLogonID, authdata, pGetKeyFn,
+ pGetKeyArgument, phCredential, ptsExpiry );
+
+done:
+ if (authdata != (SEC_WINNT_AUTH_IDENTITY_W *)id) HeapFree( GetProcessHeap(), 0, authdata );
+ HeapFree( GetProcessHeap(), 0, package );
+ HeapFree( GetProcessHeap(), 0, principal );
+ HeapFree( GetProcessHeap(), 0, user );
+ HeapFree( GetProcessHeap(), 0, domain );
+ HeapFree( GetProcessHeap(), 0, passwd );
+ return ret;
}
/***********************************************************************
@@ -270,6 +497,8 @@ static const SecurityFunctionTableW kerberosTableW = {
NULL, /* SetContextAttributesW */
};
+#define KERBEROS_MAX_BUF 12000
+
#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;
@@ -316,8 +545,25 @@ static const SecPkgInfoA infoA = {
kerberos_comment_A
};
+void SECUR32_deinitKerberosSP(void)
+{
+#ifdef SONAME_LIBGSSAPI_KRB5
+ unload_gssapi_krb5();
+#endif
+}
+
void SECUR32_initKerberosSP(void)
{
- SecureProvider *provider = SECUR32_addProvider(&kerberosTableA, &kerberosTableW, NULL);
- SECUR32_addPackages(provider, 1, &infoA, &infoW);
+ SecureProvider *provider;
+
+#ifdef SONAME_LIBGSSAPI_KRB5
+ if (!load_gssapi_krb5()) return;
+#endif
+ if (!(provider = SECUR32_addProvider( &kerberosTableA, &kerberosTableW, NULL )))
+ {
+ ERR( "Failed to add Kerberos provider.\n" );
+ SECUR32_deinitKerberosSP();
+ return;
+ }
+ SECUR32_addPackages( provider, 1, &infoA, &infoW );
}
diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c
index 1e12f3c543..5b65cf791d 100644
--- a/dlls/secur32/secur32.c
+++ b/dlls/secur32/secur32.c
@@ -677,6 +677,7 @@ static void SECUR32_freeProviders(void)
EnterCriticalSection(&cs);
SECUR32_deinitSchannelSP();
+ SECUR32_deinitKerberosSP();
if (packageTable)
{
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index 9a60d65788..7e16b50404 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -139,6 +139,7 @@ void SECUR32_initNTLMSP(void) DECLSPEC_HIDDEN;
void SECUR32_initKerberosSP(void) DECLSPEC_HIDDEN;
/* Cleanup functions for built-in providers */
+void SECUR32_deinitKerberosSP(void) DECLSPEC_HIDDEN;
void SECUR32_deinitSchannelSP(void) DECLSPEC_HIDDEN;
/* Functions from dispatcher.c used elsewhere in the code */
--
2.11.0
More information about the wine-patches
mailing list