diff --git a/configure b/configure index 5966ebd1a2f..96225801ca0 100755 --- a/configure +++ b/configure @@ -648,6 +648,8 @@ PNG_LIBS PNG_CFLAGS JPEG_LIBS JPEG_CFLAGS +GSSAPI_LIBS +GSSAPI_CFLAGS KRB5_LIBS KRB5_CFLAGS FONTCONFIG_LIBS @@ -838,6 +840,7 @@ with_gphoto with_glu with_gnutls with_gsm +with_gssapi with_gstreamer with_hal with_jpeg @@ -1732,6 +1735,8 @@ FONTCONFIG_CFLAGS FONTCONFIG_LIBS KRB5_CFLAGS KRB5_LIBS +GSSAPI_CFLAGS +GSSAPI_LIBS JPEG_CFLAGS JPEG_LIBS PNG_CFLAGS @@ -2399,6 +2404,7 @@ Optional Packages: --without-glu do not use the GLU library --without-gnutls do not use GnuTLS (schannel support) --without-gsm do not use libgsm (GSM 06.10 codec support) + --without-gssapi do not use GSSAPI (Kerberos SSP support) --without-gstreamer do not use GStreamer (codecs support) --without-hal do not use HAL (dynamic device support) --without-jpeg do not use JPEG @@ -2499,6 +2505,9 @@ Some influential environment variables: Linker flags for fontconfig, overriding pkg-config KRB5_CFLAGS C compiler flags for krb5, overriding pkg-config KRB5_LIBS Linker flags for krb5, overriding pkg-config + GSSAPI_CFLAGS + C compiler flags for krb5-gssapi, overriding pkg-config + GSSAPI_LIBS Linker flags for krb5-gssapi, overriding pkg-config JPEG_CFLAGS C compiler flags for libjpeg, overriding pkg-config JPEG_LIBS Linker flags for libjpeg, overriding pkg-config PNG_CFLAGS C compiler flags for libpng, overriding pkg-config @@ -3602,6 +3611,12 @@ if test "${with_gsm+set}" = set; then : fi +# Check whether --with-gssapi was given. +if test "${with_gssapi+set}" = set; then : + withval=$with_gssapi; +fi + + # Check whether --with-gstreamer was given. if test "${with_gstreamer+set}" = set; then : withval=$with_gstreamer; @@ -13867,6 +13882,111 @@ esac fi +if test "x$with_gssapi" != "xno" +then + if ${GSSAPI_CFLAGS:+false} :; then : + if ${PKG_CONFIG+:} false; then : + GSSAPI_CFLAGS=`$PKG_CONFIG --cflags krb5-gssapi 2>/dev/null` +fi +fi +test "$cross_compiling" = yes || GSSAPI_CFLAGS=${GSSAPI_CFLAGS:-`${KRB5_CONFIG:-krb5-config} --cflags gssapi 2>/dev/null`} +if ${GSSAPI_LIBS:+false} :; then : + if ${PKG_CONFIG+:} false; then : + GSSAPI_LIBS=`$PKG_CONFIG --libs krb5-gssapi 2>/dev/null` +fi +fi +test "$cross_compiling" = yes || GSSAPI_LIBS=${GSSAPI_LIBS:-`${KRB5_CONFIG:-krb5-config} --libs gssapi 2>/dev/null`} + +$as_echo "$as_me:${as_lineno-$LINENO}: krb5-gssapi cflags: $GSSAPI_CFLAGS" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: krb5-gssapi libs: $GSSAPI_LIBS" >&5 +ac_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $GSSAPI_CFLAGS" +for ac_header in gssapi/gssapi.h gssapi/gssapi_ext.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + if test "$ac_cv_header_gssapi_gssapi_h" = "yes" -a "$ac_cv_header_gssapi_gssapi_ext_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 $GSSAPI_LIBS $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; } + GSSAPI_CFLAGS="" +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 + else + GSSAPI_CFLAGS="" + fi +CPPFLAGS=$ac_save_CPPFLAGS +test -z "$GSSAPI_CFLAGS" || GSSAPI_CFLAGS=`echo " $GSSAPI_CFLAGS" | sed 's/ -I\([^/]\)/ -I\$(top_builddir)\/\1/g'` +test -z "$GSSAPI_LIBS" || GSSAPI_LIBS=`echo " $GSSAPI_LIBS" | sed 's/ -L\([^/]\)/ -L\$(top_builddir)\/\1/g'` + +fi +if test "x$ac_cv_lib_soname_gssapi_krb5" = "x"; then : + case "x$with_gssapi" in + x) as_fn_append wine_notices "|libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support." ;; + xno) ;; + *) as_fn_error $? "libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support. +This is an error since --with-gssapi was requested." "$LINENO" 5 ;; +esac + +fi + if test "x$with_jpeg" != "xno" then if ${JPEG_CFLAGS:+false} :; then : @@ -18127,6 +18247,8 @@ FONTCONFIG_CFLAGS = $FONTCONFIG_CFLAGS FONTCONFIG_LIBS = $FONTCONFIG_LIBS KRB5_CFLAGS = $KRB5_CFLAGS KRB5_LIBS = $KRB5_LIBS +GSSAPI_CFLAGS = $GSSAPI_CFLAGS +GSSAPI_LIBS = $GSSAPI_LIBS JPEG_CFLAGS = $JPEG_CFLAGS JPEG_LIBS = $JPEG_LIBS PNG_CFLAGS = $PNG_CFLAGS diff --git a/configure.ac b/configure.ac index 3942e15e9ae..cb7a4d36d82 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,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])) @@ -1665,6 +1666,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_CFLAGS=""],[$GSSAPI_LIBS]) + else + GSSAPI_CFLAGS="" + fi]) +fi +WINE_NOTICE_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/kerberos/Makefile.in b/dlls/kerberos/Makefile.in index 253e9447164..f67ba567fb0 100644 --- a/dlls/kerberos/Makefile.in +++ b/dlls/kerberos/Makefile.in @@ -1,5 +1,5 @@ MODULE = kerberos.dll -EXTRAINCL = $(KRB5_CFLAGS) +EXTRAINCL = $(KRB5_CFLAGS) $(GSSAPI_CFLAGS) C_SRCS = \ krb5_ap.c diff --git a/dlls/kerberos/krb5_ap.c b/dlls/kerberos/krb5_ap.c index 502b41efa3f..06a0ad4a2d3 100644 --- a/dlls/kerberos/krb5_ap.c +++ b/dlls/kerberos/krb5_ap.c @@ -1,5 +1,7 @@ /* * Copyright 2017 Dmitry Timoshkov + * Copyright 2008 Robert Shearman for CodeWeavers + * Copyright 2017 Hans Leidekker for CodeWeavers * * Kerberos5 Authentication Package * @@ -25,6 +27,10 @@ #ifdef HAVE_KRB5_KRB5_H #include #endif +#ifdef SONAME_LIBGSSAPI_KRB5 +# include +# include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -106,6 +112,12 @@ static void load_krb5(void) #endif /* SONAME_LIBKRB5 */ +static const char *debugstr_us( const UNICODE_STRING *us ) +{ + if (!us) return ""; + return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) ); +} + static NTSTATUS NTAPI kerberos_LsaApInitializePackage(ULONG package_id, PLSA_DISPATCH_TABLE dispatch, PLSA_STRING database, PLSA_STRING confidentiality, PLSA_STRING *package_name) { @@ -144,21 +156,6 @@ static NTSTATUS NTAPI kerberos_LsaApCallPackageUntrusted(PLSA_CLIENT_REQUEST req return STATUS_NOT_IMPLEMENTED; } -static NTSTATUS NTAPI kerberos_SpInitialize(ULONG_PTR package_id, SECPKG_PARAMETERS *params, - LSA_SECPKG_FUNCTION_TABLE *lsa_function_table) -{ - FIXME("%lu,%p,%p: stub\n", package_id, params, lsa_function_table); - - return STATUS_SUCCESS; -} - -static NTSTATUS NTAPI kerberos_SpShutdown(void) -{ - TRACE("\n"); - - return STATUS_SUCCESS; -} - static NTSTATUS NTAPI kerberos_SpGetInfo(SecPkgInfoW *info) { static WCHAR kerberos_name_W[] = {'K','e','r','b','e','r','o','s',0}; @@ -183,6 +180,193 @@ static NTSTATUS NTAPI kerberos_SpGetInfo(SecPkgInfoW *info) return STATUS_SUCCESS; } +#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, LSA_SEC_HANDLE *cred ) +{ + *cred = (LSA_SEC_HANDLE)handle; +} + +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 UNICODE_STRING *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->Buffer, name_str->Length / sizeof(WCHAR), NULL, 0, NULL, NULL ) + 1; + if (!(buf.value = HeapAlloc( GetProcessHeap(), 0, buf.length ))) return SEC_E_INSUFFICIENT_MEMORY; + WideCharToMultiByte( CP_UNIXCP, 0, name_str->Buffer, name_str->Length / sizeof(WCHAR), 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 /* SONAME_LIBGSSAPI_KRB5 */ + +static NTSTATUS NTAPI kerberos_SpAcquireCredentialsHandle( + UNICODE_STRING *principal_us, ULONG credential_use, LUID *logon_id, void *auth_data, + void *get_key_fn, void *get_key_arg, LSA_SEC_HANDLE *credential, TimeStamp *ts_expiry ) +{ +#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 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us), credential_use, + logon_id, auth_data, get_key_fn, get_key_arg, credential, ts_expiry ); + + if (auth_data) + { + FIXME( "specific credentials not supported\n" ); + return SEC_E_UNKNOWN_CREDENTIALS; + } + + switch (credential_use) + { + 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 (principal_us && ((ret = name_sspi_to_gss( principal_us, &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, credential ); + expirytime_gss_to_sspi( expiry_time, ts_expiry ); + } + + if (principal != GSS_C_NO_NAME) pgss_release_name( &minor_status, &principal ); + + return status_gss_to_sspi( ret ); +#else + FIXME( "(%s 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us), credential_use, + logon_id, auth_data, get_key_fn, get_key_arg, credential, ts_expiry ); + FIXME( "Wine was built without Kerberos support.\n" ); + return SEC_E_UNSUPPORTED_FUNCTION; +#endif +} + +static NTSTATUS NTAPI kerberos_SpInitialize(ULONG_PTR package_id, SECPKG_PARAMETERS *params, + LSA_SECPKG_FUNCTION_TABLE *lsa_function_table) +{ + TRACE("%lu,%p,%p\n", package_id, params, lsa_function_table); + +#ifdef SONAME_LIBGSSAPI_KRB5 + if (load_gssapi_krb5()) return STATUS_SUCCESS; +#endif + + return STATUS_UNSUCCESSFUL; +} + +static NTSTATUS NTAPI kerberos_SpShutdown(void) +{ + TRACE("\n"); + +#ifdef SONAME_LIBGSSAPI_KRB5 + unload_gssapi_krb5(); +#endif + + return STATUS_SUCCESS; +} + static SECPKG_FUNCTION_TABLE kerberos_table = { kerberos_LsaApInitializePackage, /* InitializePackage */ @@ -197,7 +381,7 @@ static SECPKG_FUNCTION_TABLE kerberos_table = kerberos_SpShutdown, kerberos_SpGetInfo, NULL, /* AcceptCredentials */ - NULL, /* SpAcquireCredentialsHandle */ + kerberos_SpAcquireCredentialsHandle, NULL, /* SpQueryCredentialsAttributes */ NULL, /* FreeCredentialsHandle */ NULL, /* SaveCredentials */ diff --git a/include/config.h.in b/include/config.h.in index 4db349c7d77..6a158159c85 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -285,6 +285,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GSM_H +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_EXT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_H + /* Define to 1 if you have the header file. */ #undef HAVE_IEEEFP_H @@ -1479,6 +1485,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