From 9259953aa52bd78011764ffdbf1236d49b81baee Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Mon, 21 Oct 2013 15:59:11 +0300 Subject: [PATCH] security: add API to return context name SPNEGO authentication scheme (RFC 4559) requires wrapping of raw NTLM messages. Only wrapped NTLM messages should be sent with the "Authorization: Negotiate" header. sip-sec-negotiate.c does *NOT* implement SPNEGO. Instead we send raw NTLM messages and therefore should use "Authorization: NTLM" header. Add a new sip-sec.c API that returns the current name of the security context, so that sipe-http-request.c can generate the correct header. --- src/core/sip-sec-basic.c | 7 +++++++ src/core/sip-sec-krb5.c | 7 +++++++ src/core/sip-sec-mech.h | 3 +++ src/core/sip-sec-negotiate.c | 16 ++++++++++++++++ src/core/sip-sec-ntlm.c | 7 +++++++ src/core/sip-sec-sspi.c | 8 ++++++++ src/core/sip-sec-tls-dsk.c | 7 +++++++ src/core/sip-sec.c | 8 ++++++++ src/core/sip-sec.h | 11 ++++++++++- src/core/sipe-http-request.c | 6 +----- 10 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/core/sip-sec-basic.c b/src/core/sip-sec-basic.c index aa3f3208..55fa5f39 100644 --- a/src/core/sip-sec-basic.c +++ b/src/core/sip-sec-basic.c @@ -104,6 +104,12 @@ sip_sec_destroy_sec_context__basic(SipSecContext context) g_free(ctx); } +static const gchar * +sip_sec_context_name__basic(SIPE_UNUSED_PARAMETER SipSecContext context) +{ + return("Basic"); +} + SipSecContext sip_sec_create_context__basic(SIPE_UNUSED_PARAMETER guint type) { @@ -115,6 +121,7 @@ sip_sec_create_context__basic(SIPE_UNUSED_PARAMETER guint type) context->common.destroy_context_func = sip_sec_destroy_sec_context__basic; context->common.make_signature_func = sip_sec_make_signature__basic; context->common.verify_signature_func = sip_sec_verify_signature__basic; + context->common.context_name_func = sip_sec_context_name__basic; return((SipSecContext) context); } diff --git a/src/core/sip-sec-krb5.c b/src/core/sip-sec-krb5.c index 45c0e683..4788291c 100644 --- a/src/core/sip-sec-krb5.c +++ b/src/core/sip-sec-krb5.c @@ -385,6 +385,12 @@ sip_sec_destroy_sec_context__krb5(SipSecContext context) g_free(context); } +static const gchar * +sip_sec_context_name__krb5(SIPE_UNUSED_PARAMETER SipSecContext context) +{ + return("Kerberos"); +} + SipSecContext sip_sec_create_context__krb5(SIPE_UNUSED_PARAMETER guint type) { @@ -396,6 +402,7 @@ sip_sec_create_context__krb5(SIPE_UNUSED_PARAMETER guint type) context->common.destroy_context_func = sip_sec_destroy_sec_context__krb5; context->common.make_signature_func = sip_sec_make_signature__krb5; context->common.verify_signature_func = sip_sec_verify_signature__krb5; + context->common.context_name_func = sip_sec_context_name__krb5; context->cred_krb5 = GSS_C_NO_CREDENTIAL; context->ctx_krb5 = GSS_C_NO_CONTEXT; diff --git a/src/core/sip-sec-mech.h b/src/core/sip-sec-mech.h index 6606d69c..3622973e 100644 --- a/src/core/sip-sec-mech.h +++ b/src/core/sip-sec-mech.h @@ -61,6 +61,8 @@ typedef gboolean const gchar *message, SipSecBuffer signature); +typedef const gchar *(*sip_sec_context_name_func)(SipSecContext context); + typedef gboolean (*sip_sec_password_func)(void); @@ -70,6 +72,7 @@ struct sip_sec_context { sip_sec_destroy_context_func destroy_context_func; sip_sec_make_signature_func make_signature_func; sip_sec_verify_signature_func verify_signature_func; + sip_sec_context_name_func context_name_func; guint type; /** Security Context expiration interval in seconds */ guint expires; diff --git a/src/core/sip-sec-negotiate.c b/src/core/sip-sec-negotiate.c index 99dd6dbe..14ddb863 100644 --- a/src/core/sip-sec-negotiate.c +++ b/src/core/sip-sec-negotiate.c @@ -199,6 +199,21 @@ sip_sec_destroy_sec_context__negotiate(SipSecContext context) g_free(ctx); } +/* + * This module doesn't implement SPNEGO (RFC 4559) but instead returns raw + * NTLM. Therefore we should not use "Authorization: Negotiate" for NTLM + * although Microsoft servers *do* accept them. + */ +static const gchar * +sip_sec_context_name__negotiate(SipSecContext context) +{ + context_negotiate ctx = (context_negotiate) context; + if (ctx->krb5) + return("Negotiate"); + else + return("NTLM"); +} + SipSecContext sip_sec_create_context__negotiate(guint type) { @@ -217,6 +232,7 @@ sip_sec_create_context__negotiate(guint type) context->common.destroy_context_func = sip_sec_destroy_sec_context__negotiate; context->common.make_signature_func = sip_sec_make_signature__negotiate; context->common.verify_signature_func = sip_sec_verify_signature__negotiate; + context->common.context_name_func = sip_sec_context_name__negotiate; context->krb5 = krb5; context->ntlm = ntlm; } else { diff --git a/src/core/sip-sec-ntlm.c b/src/core/sip-sec-ntlm.c index af03e00e..e65f2a0e 100644 --- a/src/core/sip-sec-ntlm.c +++ b/src/core/sip-sec-ntlm.c @@ -1902,6 +1902,12 @@ sip_sec_destroy_sec_context__ntlm(SipSecContext context) g_free(ctx); } +static const gchar * +sip_sec_context_name__ntlm(SIPE_UNUSED_PARAMETER SipSecContext context) +{ + return("NTLM"); +} + SipSecContext sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type) { @@ -1913,6 +1919,7 @@ sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type) context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm; context->common.make_signature_func = sip_sec_make_signature__ntlm; context->common.verify_signature_func = sip_sec_verify_signature__ntlm; + context->common.context_name_func = sip_sec_context_name__ntlm; return((SipSecContext) context); } diff --git a/src/core/sip-sec-sspi.c b/src/core/sip-sec-sspi.c index c471e432..0b710f1a 100644 --- a/src/core/sip-sec-sspi.c +++ b/src/core/sip-sec-sspi.c @@ -398,6 +398,13 @@ sip_sec_verify_signature__sspi(SipSecContext context, return TRUE; } +/* SSPI implements SPNEGO (RFC 4559) */ +static const gchar * +sip_sec_context_name__sspi(SipSecContext context) +{ + return(mech_names[context->type]); +} + SipSecContext sip_sec_create_context__sspi(guint type) { @@ -409,6 +416,7 @@ sip_sec_create_context__sspi(guint type) context->common.destroy_context_func = sip_sec_destroy_sec_context__sspi; context->common.make_signature_func = sip_sec_make_signature__sspi; context->common.verify_signature_func = sip_sec_verify_signature__sspi; + context->common.context_name_func = sip_sec_context_name__sspi; return((SipSecContext) context); } diff --git a/src/core/sip-sec-tls-dsk.c b/src/core/sip-sec-tls-dsk.c index faa8d86c..fbc5da92 100644 --- a/src/core/sip-sec-tls-dsk.c +++ b/src/core/sip-sec-tls-dsk.c @@ -212,6 +212,12 @@ sip_sec_destroy_sec_context__tls_dsk(SipSecContext context) g_free(ctx); } +static const gchar * +sip_sec_context_name__tls_dsk(SIPE_UNUSED_PARAMETER SipSecContext context) +{ + return("TLS-DSK"); +} + SipSecContext sip_sec_create_context__tls_dsk(SIPE_UNUSED_PARAMETER guint type) { @@ -223,6 +229,7 @@ sip_sec_create_context__tls_dsk(SIPE_UNUSED_PARAMETER guint type) context->common.destroy_context_func = sip_sec_destroy_sec_context__tls_dsk; context->common.make_signature_func = sip_sec_make_signature__tls_dsk; context->common.verify_signature_func = sip_sec_verify_signature__tls_dsk; + context->common.context_name_func = sip_sec_context_name__tls_dsk; return((SipSecContext) context); } diff --git a/src/core/sip-sec.c b/src/core/sip-sec.c index dc87ce5a..2b444370 100644 --- a/src/core/sip-sec.c +++ b/src/core/sip-sec.c @@ -206,6 +206,14 @@ gboolean sip_sec_context_is_ready(SipSecContext context) return(context && (context->flags & SIP_SEC_FLAG_COMMON_READY)); } +const gchar *sip_sec_context_name(SipSecContext context) +{ + if (context) + return((*context->context_name_func)(context)); + else + return(NULL); +} + guint sip_sec_context_type(SipSecContext context) { if (context) diff --git a/src/core/sip-sec.h b/src/core/sip-sec.h index 880b02d0..eb1920d4 100644 --- a/src/core/sip-sec.h +++ b/src/core/sip-sec.h @@ -79,11 +79,20 @@ sip_sec_init_context_step(SipSecContext context, gboolean sip_sec_context_is_ready(SipSecContext context); /** + * Return authentication name of a security context + * + * @param context (in) security context. May be @c NULL. + * + * @return string or @c NULL + */ +const gchar *sip_sec_context_name(SipSecContext context); + +/** * Return type of a security context * * @param context (in) security context. May be @c NULL. * - * @return @c context type or SIPE_SIPE_AUTHENTICATION_TYPE_UNSET + * @return context type or @c SIPE_SIPE_AUTHENTICATION_TYPE_UNSET */ guint sip_sec_context_type(SipSecContext context); diff --git a/src/core/sipe-http-request.c b/src/core/sipe-http-request.c index 8ce0973c..21ed191d 100644 --- a/src/core/sipe-http-request.c +++ b/src/core/sipe-http-request.c @@ -263,7 +263,6 @@ static gboolean sipe_http_request_response_unauthorized(struct sipe_core_private struct sipmsg *msg) { const gchar *header = NULL; - const gchar *name; guint type; gboolean failed = TRUE; @@ -274,7 +273,6 @@ static gboolean sipe_http_request_response_unauthorized(struct sipe_core_private header = sipmsg_find_auth_header(msg, "Negotiate"); if (header) { type = SIPE_AUTHENTICATION_TYPE_NEGOTIATE; - name = "Negotiate"; } else #else #define DEBUG_STRING " and NTLM" @@ -283,14 +281,12 @@ static gboolean sipe_http_request_response_unauthorized(struct sipe_core_private { header = sipmsg_find_auth_header(msg, "NTLM"); type = SIPE_AUTHENTICATION_TYPE_NTLM; - name = "NTLM"; } /* only fall back to "Basic" after everything else fails */ if (!header) { header = sipmsg_find_auth_header(msg, "Basic"); type = SIPE_AUTHENTICATION_TYPE_BASIC; - name = "Basic"; } if (header) { @@ -323,7 +319,7 @@ static gboolean sipe_http_request_response_unauthorized(struct sipe_core_private /* generate authorization header */ req->authorization = g_strdup_printf("Authorization: %s %s\r\n", - name, + sip_sec_context_name(conn_public->context), token ? token : ""); g_free(token); -- 2.11.4.GIT