From 150359308e8250b96028ab789e685b97e536e753 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Fri, 25 Oct 2013 23:57:25 +0300 Subject: [PATCH] security: replace SPNEGO with internal negotiate There seem to be problems with SPNEGO: - some servers don't accept SPNEGO-wrapped tokens - GSSAPI doesn't process the final SPNEGO package correctly thus a SPNEGO security context never reaches READY state. Fall back to our internal Negotiate implementation, but use GSSAPI also for NTLM in the GSSAPI-only case. --- src/core/Makefile.am | 8 +--- src/core/sip-sec-gssapi.c | 107 ++++++------------------------------------- src/core/sip-sec-negotiate.c | 11 ++++- src/core/sip-sec.c | 2 - 4 files changed, 27 insertions(+), 101 deletions(-) diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 579fc1ff..4b2793e8 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -150,14 +150,10 @@ endif if SIP_SEC_GSSAPI libsipe_core_la_SOURCES += \ sip-sec-gssapi.h \ - sip-sec-gssapi.c -libsipe_core_la_CFLAGS += $(KRB5_CFLAGS) - -if !SIP_SEC_GSSAPI_ONLY -libsipe_core_la_SOURCES += \ + sip-sec-gssapi.c \ sip-sec-negotiate.h \ sip-sec-negotiate.c -endif +libsipe_core_la_CFLAGS += $(KRB5_CFLAGS) endif diff --git a/src/core/sip-sec-gssapi.c b/src/core/sip-sec-gssapi.c index 0bf8ab74..1365e68d 100644 --- a/src/core/sip-sec-gssapi.c +++ b/src/core/sip-sec-gssapi.c @@ -29,7 +29,7 @@ * - Kerberos-only: NTLM & SPNEGO are using SIPE internal implementation * [HAVE_GSSAPI_ONLY is not defined] * - * - pure GSSAPI: this modules handles Kerberos, NTLM & SPNEGO + * - pure GSSAPI: this modules handles Kerberos & NTLM * [HAVE_GSSAPI_ONLY is defined] */ @@ -68,15 +68,9 @@ static const gss_OID_desc gss_mech_ntlmssp = { GSS_NTLMSSP_OID_LENGTH, GSS_NTLMSSP_OID_STRING }; - -static const gss_OID_desc gss_mech_spnego = { - 6, - "\x2b\x06\x01\x05\x05\x02" -}; #endif -#define SIP_SEC_FLAG_GSSAPI_SIP_NTLM 0x00010000 -#define SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK 0x00020000 +#define SIP_SEC_FLAG_GSSAPI_SIP_NTLM 0x00010000 static void sip_sec_gssapi_print_gss_error0(char *func, OM_uint32 status, @@ -126,8 +120,7 @@ static gss_OID_set create_mechs_set(guint type) } #ifdef HAVE_GSSAPI_ONLY - if ((type == SIPE_AUTHENTICATION_TYPE_NEGOTIATE) || - (type == SIPE_AUTHENTICATION_TYPE_KERBEROS)) { + if (type == SIPE_AUTHENTICATION_TYPE_KERBEROS) { #else (void) type; /* keep compiler happy */ #endif @@ -143,8 +136,7 @@ static gss_OID_set create_mechs_set(guint type) #ifdef HAVE_GSSAPI_ONLY } - if ((type == SIPE_AUTHENTICATION_TYPE_NEGOTIATE) || - (type == SIPE_AUTHENTICATION_TYPE_NTLM)) { + if (type == SIPE_AUTHENTICATION_TYPE_NTLM) { ret = gss_add_oid_set_member(&minor, (gss_OID) &gss_mech_ntlmssp, &set); @@ -383,9 +375,6 @@ sip_sec_init_sec_context__gssapi(SipSecContext context, gss_buffer_desc input_token; gss_buffer_desc output_token; gss_name_t target_name; -#ifdef HAVE_GSSAPI_ONLY - gchar *hostbased_service_name = NULL; -#endif SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: started"); @@ -403,65 +392,19 @@ sip_sec_init_sec_context__gssapi(SipSecContext context, #ifdef HAVE_GSSAPI_ONLY switch(context->type) { case SIPE_AUTHENTICATION_TYPE_NTLM: - name_oid = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE; - mech_oid = (gss_OID) &gss_mech_ntlmssp; - input_token.value = (void *) service_name; + name_oid = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE; + mech_oid = (gss_OID) &gss_mech_ntlmssp; if (context->flags & SIP_SEC_FLAG_GSSAPI_SIP_NTLM) flags |= GSS_C_DATAGRAM_FLAG; break; case SIPE_AUTHENTICATION_TYPE_KERBEROS: #endif - name_oid = (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME; - mech_oid = (gss_OID) gss_mech_krb5; - input_token.value = (void *) service_name; + name_oid = (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME; + mech_oid = (gss_OID) gss_mech_krb5; #ifdef HAVE_GSSAPI_ONLY break; - case SIPE_AUTHENTICATION_TYPE_NEGOTIATE: { - gchar **type_service; - - /* - * Some servers do not accept SPNEGO for Negotiate. - * If come back here with an existing security context - * and NULL input token we will fall back to NTLM - */ - if (ctx->ctx_gssapi && (in_buff.value == NULL)) { - - /* Only try this once */ - if (context->flags & SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK) { - SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_init_sec_context__gssapi: SPNEGO-to-NTLM fallback failed"); - return(FALSE); - } - - SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: SPNEGO failed. Falling back to NTLM"); - drop_gssapi_context(context); - - context->flags |= SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK; - } - - /* Convert to hostbased so NTLM fallback can work */ - type_service = g_strsplit(service_name, "/", 2); - if (type_service[1]) { - gchar *type_lower = g_ascii_strdown(type_service[0], -1); - hostbased_service_name = g_strdup_printf("%s@%s", - type_lower, - type_service[1]); - g_free(type_lower); - input_token.value = (void *) hostbased_service_name; - } else { - input_token.value = (void *) service_name; - } - g_strfreev(type_service); - - name_oid = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE; - if (context->flags & SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK) - mech_oid = (gss_OID) &gss_mech_ntlmssp; - else - mech_oid = (gss_OID) &gss_mech_spnego; - } - break; - default: SIPE_DEBUG_ERROR("sip_sec_gssapi_initialize_context invoked for invalid type %d", context->type); @@ -470,6 +413,7 @@ sip_sec_init_sec_context__gssapi(SipSecContext context, #endif /* Import service name to GSS */ + input_token.value = (void *) service_name; input_token.length = strlen(input_token.value) + 1; ret = gss_import_name(&minor, @@ -477,10 +421,6 @@ sip_sec_init_sec_context__gssapi(SipSecContext context, name_oid, &target_name); -#ifdef HAVE_GSSAPI_ONLY - g_free(hostbased_service_name); -#endif - if (GSS_ERROR(ret)) { sip_sec_gssapi_print_gss_error("gss_import_name", ret, minor); SIPE_DEBUG_ERROR("sip_sec_init_sec_context__gssapi: failed to construct target name (ret=%d)", (int)ret); @@ -635,31 +575,14 @@ sip_sec_destroy_sec_context__gssapi(SipSecContext context) static const gchar * sip_sec_context_name__gssapi(SipSecContext context) { - const gchar *name = "Kerberos"; - -#ifdef HAVE_GSSAPI_ONLY - switch(context->type) { - case SIPE_AUTHENTICATION_TYPE_NTLM: - name = "NTLM"; - break; - - case SIPE_AUTHENTICATION_TYPE_NEGOTIATE: - if (context->flags & SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK) - name = "NTLM"; - else - name = "Negotiate"; - break; - - default: -#endif - name = "Kerberos"; -#ifdef HAVE_GSSAPI_ONLY - break; - } -#else +#ifndef HAVE_GSSAPI_ONLY (void) context; /* keep compiler happy */ +#else + if (context->type == SIPE_AUTHENTICATION_TYPE_NTLM) + return("NTLM"); + else #endif - return(name); + return("Kerberos"); } SipSecContext diff --git a/src/core/sip-sec-negotiate.c b/src/core/sip-sec-negotiate.c index 44ad4300..9f4198eb 100644 --- a/src/core/sip-sec-negotiate.c +++ b/src/core/sip-sec-negotiate.c @@ -25,6 +25,10 @@ * It is a wrapper that will always try Kerberos first and fall back to NTLM. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include "sipe-common.h" @@ -222,7 +226,12 @@ sip_sec_create_context__negotiate(SIPE_UNUSED_PARAMETER guint type) SipSecContext krb5 = sip_sec_create_context__gssapi(SIPE_AUTHENTICATION_TYPE_KERBEROS); if (krb5) { - SipSecContext ntlm = sip_sec_create_context__ntlm(SIPE_AUTHENTICATION_TYPE_NTLM); + SipSecContext ntlm = +#ifdef HAVE_GSSAPI_ONLY + sip_sec_create_context__gssapi(SIPE_AUTHENTICATION_TYPE_NTLM); +#else + sip_sec_create_context__ntlm(SIPE_AUTHENTICATION_TYPE_NTLM); +#endif if (ntlm) { context = g_malloc0(sizeof(struct _context_negotiate)); diff --git a/src/core/sip-sec.c b/src/core/sip-sec.c index 8296cf92..aba1bf12 100644 --- a/src/core/sip-sec.c +++ b/src/core/sip-sec.c @@ -87,8 +87,6 @@ /* SIPE_AUTHENTICATION_TYPE_NEGOTIATE */ #if SIP_SEC_WINDOWS_SSPI #define sip_sec_create_context__Negotiate sip_sec_create_context__sspi -#elif defined(HAVE_GSSAPI_ONLY) -#define sip_sec_create_context__Negotiate sip_sec_create_context__gssapi #elif defined(HAVE_GSSAPI_GSSAPI_H) #include "sip-sec-negotiate.h" #define sip_sec_create_context__Negotiate sip_sec_create_context__negotiate -- 2.11.4.GIT