[libsoup/wip/tpopela/negotiate: 15/16] Make the libgssapi a hard dependency of libsoup
- From: Tomas Popela <tpopela src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/wip/tpopela/negotiate: 15/16] Make the libgssapi a hard dependency of libsoup
- Date: Fri, 30 Oct 2015 07:54:57 +0000 (UTC)
commit 0092a0acb02701469dc2d140ccbc3ed6ea42ebc9
Author: Tomas Popela <tpopela redhat com>
Date: Wed Oct 21 15:42:12 2015 +0200
Make the libgssapi a hard dependency of libsoup
configure.ac | 1 -
examples/get.c | 13 ++-
libsoup/Makefile.am | 23 +---
libsoup/libsoup-gssapi-2.4.sym | 5 -
libsoup/soup-auth-manager.c | 7 +-
libsoup/soup-auth-negotiate.c | 314 +++++++++++++++++++++++++++++++---------
libsoup/soup-auth-negotiate.h | 4 +
libsoup/soup-auth.h | 2 +
libsoup/soup-gssapi.c | 240 ------------------------------
libsoup/soup-gssapi.h | 41 -----
10 files changed, 272 insertions(+), 378 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 7d46af3..06f7542 100644
--- a/configure.ac
+++ b/configure.ac
@@ -330,7 +330,6 @@ if test "x$KRB5_CONFIG" != "xnone"; then
AC_DEFINE(HAVE_GSSAPI, 1, [Whether or not gssapi libs are available])
fi
fi
-AM_CONDITIONAL(BUILD_LIBSOUP_GSSAPI, test $KRB5_CONFIG != none)
dnl ****************************************************
dnl *** Warnings to show if using GCC ***
diff --git a/examples/get.c b/examples/get.c
index 6f761af..63ac0b4 100644
--- a/examples/get.c
+++ b/examples/get.c
@@ -4,6 +4,10 @@
* Copyright (C) 2013 Igalia, S.L.
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
@@ -89,7 +93,10 @@ get_url (const char *url)
}
static const char *ca_file, *proxy;
-static gboolean synchronous, ntlm, negotiate;
+static gboolean synchronous, ntlm;
+#if HAVE_GSSAPI
+static gboolean negotiate;
+#endif
static GOptionEntry entries[] = {
{ "ca-file", 'c', 0,
@@ -104,9 +111,11 @@ static GOptionEntry entries[] = {
{ "ntlm", 'n', 0,
G_OPTION_ARG_NONE, &ntlm,
"Use NTLM authentication", NULL },
+#if HAVE_GSSAPI
{ "negotiate", 'N', 0,
G_OPTION_ARG_NONE, &negotiate,
"Use Negotiate authentication", NULL },
+#endif
{ "output", 'o', 0,
G_OPTION_ARG_STRING, &output_file_path,
"Write the received data to FILE instead of stdout", "FILE" },
@@ -186,10 +195,12 @@ main (int argc, char **argv)
soup_uri_free (proxy_uri);
}
+#if HAVE_GSSAPI
if (negotiate) {
soup_session_add_feature_by_type(session,
SOUP_TYPE_AUTH_NEGOTIATE);
}
+#endif
if (!synchronous)
loop = g_main_loop_new (NULL, TRUE);
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 00ac40b..510c3c3 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -99,7 +99,8 @@ libsoup_2_4_la_LIBADD = \
$(GLIB_LIBS) \
$(LIBWS2_32) \
$(XML_LIBS) \
- $(SQLITE_LIBS)
+ $(SQLITE_LIBS) \
+ $(KRB5_LIBS)
libsoup_2_4_la_SOURCES = \
gconstructor.h \
@@ -245,26 +246,6 @@ libsoup_gnome_2_4_la_SOURCES = \
endif
-if BUILD_LIBSOUP_GSSAPI
-
-lib_LTLIBRARIES += libsoup-gssapi-2.4.la
-
-libsoup_gssapi_2_4_la_LDFLAGS = \
- -version-info $(SOUP_CURRENT):$(SOUP_REVISION):$(SOUP_AGE) \
- -no-undefined \
- -export-symbols $(srcdir)/libsoup-gssapi-2.4.sym
-
-EXTRA_DIST += libsoup-gssapi-2.4.sym
-
-libsoup_gssapi_2_4_la_LIBADD = \
- $(KRB5_LIBS) \
- $(GLIB_LIBS)
-
-libsoup_gssapi_2_4_la_SOURCES = \
- soup-gssapi.c
-
-endif
-
GLIB_GENERATED = soup-enum-types.c soup-enum-types.h
BUILT_SOURCES = \
$(GLIB_GENERATED) \
diff --git a/libsoup/soup-auth-manager.c b/libsoup/soup-auth-manager.c
index c17b4e1..95a0c38 100644
--- a/libsoup/soup-auth-manager.c
+++ b/libsoup/soup-auth-manager.c
@@ -13,13 +13,16 @@
#include "soup-auth-manager.h"
#include "soup.h"
-#include "soup-auth-negotiate.h"
#include "soup-connection-auth.h"
#include "soup-message-private.h"
#include "soup-message-queue.h"
#include "soup-path-map.h"
#include "soup-session-private.h"
+#if HAVE_GSSAPI
+#include "soup-auth-negotiate.h"
+#endif
+
/**
* SECTION:soup-auth-manager
* @short_description: HTTP client-side authentication handler
@@ -486,8 +489,10 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
} else
uri = soup_message_get_uri (msg);
+#if HAVE_GSSAPI
if (SOUP_IS_AUTH_NEGOTIATE (auth))
return;
+#endif
/* If a password is specified explicitly in the URI, use it
* even if the auth had previously already been authenticated.
diff --git a/libsoup/soup-auth-negotiate.c b/libsoup/soup-auth-negotiate.c
index 7727b74..013f9a4 100644
--- a/libsoup/soup-auth-negotiate.c
+++ b/libsoup/soup-auth-negotiate.c
@@ -9,47 +9,60 @@
#include <config.h>
#endif
-#ifdef HAVE_GSSAPI
-# include <gssapi/gssapi.h>
-#endif
+#if HAVE_GSSAPI
#include <string.h>
-#include <stdio.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
#include "soup-auth-negotiate.h"
-#include "soup-gssapi.h"
#include "soup-headers.h"
#include "soup-message.h"
#include "soup-message-private.h"
#include "soup-misc.h"
#include "soup-uri.h"
+#define AUTH_GSS_ERROR -1
+#define AUTH_GSS_COMPLETE 1
+#define AUTH_GSS_CONTINUE 0
+
+typedef enum {
+ SOUP_NEGOTIATE_NEW,
+ SOUP_NEGOTIATE_RECEIVED_CHALLENGE, /* received intial negotiate header */
+ SOUP_NEGOTIATE_SENT_RESPONSE, /* sent response to server */
+ SOUP_NEGOTIATE_FAILED
+} SoupNegotiateState;
+
+typedef struct {
+ SoupNegotiateState state;
+
+ gss_ctx_id_t context;
+ gss_name_t server_name;
+
+ gchar *response_header;
+} SoupNegotiateConnectionState;
+
static gboolean soup_gss_build_response (SoupNegotiateConnectionState *conn,
SoupAuth *auth, GError **err);
static void parse_trusted_uris (void);
static gboolean check_auth_trusted_uri (SoupAuthNegotiate *negotiate,
SoupMessage *msg);
+static void soup_gss_client_cleanup (SoupNegotiateConnectionState *conn);
+static gboolean soup_gss_client_init (SoupNegotiateConnectionState *conn,
+ const char *host, GError **err);
+static gboolean soup_gss_client_inquire_cred (SoupAuth *auth, GError **err);
+static gchar * soup_gss_client_get_name (SoupAuth *auth, GError **err);
+static int soup_gss_client_step (SoupNegotiateConnectionState *conn,
+ const char *host, GError **err);
-G_DEFINE_TYPE (SoupAuthNegotiate, soup_auth_negotiate, SOUP_TYPE_CONNECTION_AUTH)
-
-/* Function pointers to dlopen'ed libsoup-gssapi */
-struct {
- void (*client_cleanup)(SoupNegotiateConnectionState *conn);
- char * (*client_get_name)(SoupAuth *auth,
- GError **err);
- int (*client_init)(SoupNegotiateConnectionState *conn,
- const char *host,
- GError **err);
- int (*client_inquire_cred)(SoupAuth *auth,
- GError **err);
- int (*client_step)(SoupNegotiateConnectionState *conn,
- const char *challenge,
- GError **err);
-} soup_gssapi_syms;
-gboolean have_gssapi;
+static const char spnego_OID[] = "\x2b\x06\x01\x05\x05\x02";
+static const gss_OID_desc gss_mech_spnego = { 6, (void *) &spnego_OID };
static GSList *trusted_uris;
+G_DEFINE_TYPE (SoupAuthNegotiate, soup_auth_negotiate, SOUP_TYPE_CONNECTION_AUTH)
+
static void
soup_auth_negotiate_init (SoupAuthNegotiate *negotiate)
{
@@ -67,8 +80,8 @@ soup_auth_negotiate_free_connection_state (SoupConnectionAuth *auth,
{
SoupNegotiateConnectionState *conn = state;
- if (have_gssapi)
- soup_gssapi_syms.client_cleanup (conn);
+ soup_gss_client_cleanup (conn);
+
g_free (conn->response_header);
}
@@ -139,8 +152,7 @@ soup_auth_negotiate_is_authenticated (SoupAuth *auth)
gboolean has_credentials = FALSE;
GError *err = NULL;
- if (have_gssapi)
- has_credentials = soup_gssapi_syms.client_inquire_cred (auth, &err);
+ has_credentials = soup_gss_client_inquire_cred (auth, &err);
if (err)
g_warning ("%s", err->message);
@@ -170,7 +182,7 @@ check_server_response (SoupMessage *msg, gpointer state)
goto out;
}
- ret = soup_gssapi_syms.client_step (conn, auth_headers + 10, &err);
+ ret = soup_gss_client_step (conn, auth_headers + 10, &err);
if (ret != AUTH_GSS_COMPLETE) {
g_warning ("%s", err->message);
@@ -226,34 +238,6 @@ soup_auth_negotiate_is_connection_ready (SoupConnectionAuth *auth,
return conn->state != SOUP_NEGOTIATE_FAILED;
}
-static gboolean
-soup_gssapi_load (void)
-{
- GModule *gssapi;
- const char *modulename = PACKAGE "-gssapi-2.4." G_MODULE_SUFFIX;
-
- if (!g_module_supported ())
- return FALSE;
-
- gssapi = g_module_open (modulename, G_MODULE_BIND_LOCAL);
- if (!gssapi) {
- g_warning ("Failed to load %s - negotiate support will "
- "be disabled.", modulename);
- return FALSE;
- }
-
-#define GSSAPI_BIND_SYMBOL(name) \
- g_return_val_if_fail (g_module_symbol (gssapi, "soup_gss_" #name, (gpointer)&soup_gssapi_syms.name),
FALSE)
-
- GSSAPI_BIND_SYMBOL(client_cleanup);
- GSSAPI_BIND_SYMBOL(client_get_name);
- GSSAPI_BIND_SYMBOL(client_init);
- GSSAPI_BIND_SYMBOL(client_inquire_cred);
- GSSAPI_BIND_SYMBOL(client_step);
-#undef GSSPI_BIND_SYMBOL
- return TRUE;
-}
-
static void
soup_auth_negotiate_class_init (SoupAuthNegotiateClass *auth_negotiate_class)
{
@@ -275,26 +259,15 @@ soup_auth_negotiate_class_init (SoupAuthNegotiateClass *auth_negotiate_class)
conn_auth_class->is_connection_ready = soup_auth_negotiate_is_connection_ready;
parse_trusted_uris ();
- have_gssapi = soup_gssapi_load();
}
static gboolean
soup_gss_build_response (SoupNegotiateConnectionState *conn, SoupAuth *auth, GError **err)
{
- if (!have_gssapi) {
- if (err && *err == NULL) {
- g_set_error (err,
- SOUP_HTTP_ERROR,
- SOUP_STATUS_GSSAPI_FAILED,
- "GSSAPI unavailable");
- }
- return FALSE;
- }
-
- if (!soup_gssapi_syms.client_init (conn, soup_auth_get_host (SOUP_AUTH (auth)), err))
+ if (!soup_gss_client_init (conn, soup_auth_get_host (SOUP_AUTH (auth)), err))
return FALSE;
- if (soup_gssapi_syms.client_step (conn, "", err) != AUTH_GSS_CONTINUE)
+ if (soup_gss_client_step (conn, "", err) != AUTH_GSS_CONTINUE)
return FALSE;
return TRUE;
@@ -391,3 +364,208 @@ check_auth_trusted_uri (SoupAuthNegotiate *negotiate, SoupMessage *msg)
return matched ? TRUE : FALSE;
}
+
+static void
+soup_gss_error (OM_uint32 err_maj, OM_uint32 err_min, GError **err)
+{
+ OM_uint32 maj_stat, min_stat, msg_ctx = 0;
+ gss_buffer_desc status;
+ gchar *buf_maj = NULL, *buf_min = NULL;
+
+ do {
+ maj_stat = gss_display_status (&min_stat,
+ err_maj,
+ GSS_C_GSS_CODE,
+ (gss_OID) &gss_mech_spnego,
+ &msg_ctx,
+ &status);
+ if (GSS_ERROR (maj_stat))
+ break;
+
+ buf_maj = g_strdup ((gchar *) status.value);
+ gss_release_buffer (&min_stat, &status);
+
+ maj_stat = gss_display_status (&min_stat,
+ err_min,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status);
+ if (!GSS_ERROR (maj_stat)) {
+ buf_min = g_strdup ((gchar *) status.value);
+ gss_release_buffer (&min_stat, &status);
+ }
+
+ if (err && *err == NULL) {
+ g_set_error (err,
+ SOUP_HTTP_ERROR,
+ SOUP_STATUS_GSSAPI_FAILED,
+ "%s %s",
+ buf_maj,
+ buf_min ? buf_min : "");
+ }
+ g_free (buf_maj);
+ g_free (buf_min);
+ buf_min = buf_maj = NULL;
+ } while (!GSS_ERROR (maj_stat) && msg_ctx != 0);
+}
+
+static gboolean
+soup_gss_client_inquire_cred (SoupAuth *auth, GError **err)
+{
+ gboolean ret = FALSE;
+ OM_uint32 maj_stat, min_stat;
+
+ maj_stat = gss_inquire_cred (&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (GSS_ERROR (maj_stat))
+ soup_gss_error (maj_stat, min_stat, err);
+
+ ret = maj_stat == GSS_S_COMPLETE;
+
+ return ret;
+}
+
+static gchar *
+soup_gss_client_get_name (SoupAuth *auth, GError **err)
+{
+ gchar *name = NULL;
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t gss_name;
+ gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
+
+ maj_stat = gss_inquire_cred (&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &gss_name,
+ NULL,
+ NULL,
+ NULL);
+
+ if (GSS_ERROR (maj_stat)) {
+ soup_gss_error (maj_stat, min_stat, err);
+ goto out;
+ }
+
+ if (maj_stat != GSS_S_COMPLETE)
+ goto out;
+
+ maj_stat = gss_display_name (&min_stat,
+ gss_name,
+ &out,
+ NULL);
+
+ if (GSS_ERROR (maj_stat)) {
+ soup_gss_error (maj_stat, min_stat, err);
+ goto out;
+ }
+
+ if (maj_stat == GSS_S_COMPLETE)
+ name = g_strndup (out.value, out.length);
+
+ maj_stat = gss_release_buffer (&min_stat, &out);
+ out:
+ maj_stat = gss_release_name (&min_stat, &gss_name);
+
+ return name;
+}
+
+static gboolean
+soup_gss_client_init (SoupNegotiateConnectionState *conn, const gchar *host, GError **err)
+{
+ OM_uint32 maj_stat, min_stat;
+ gchar *service = NULL;
+ gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+ gboolean ret = FALSE;
+ gchar *h;
+
+ conn->server_name = GSS_C_NO_NAME;
+ conn->context = GSS_C_NO_CONTEXT;
+
+ h = g_ascii_strdown (host, -1);
+ service = g_strconcat ("HTTP@", h, NULL);
+ token.length = strlen (service);
+ token.value = (gchar *) service;
+
+ maj_stat = gss_import_name (&min_stat,
+ &token,
+ (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
+ &conn->server_name);
+
+ if (GSS_ERROR (maj_stat)) {
+ soup_gss_error (maj_stat, min_stat, err);
+ ret = FALSE;
+ goto out;
+ }
+
+ ret = TRUE;
+out:
+ g_free (h);
+ g_free (service);
+ return ret;
+}
+
+static gint
+soup_gss_client_step (SoupNegotiateConnectionState *conn, const gchar *challenge, GError **err)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
+ gint ret = AUTH_GSS_CONTINUE;
+
+ g_clear_pointer (&conn->response_header, g_free);
+
+ if (challenge && *challenge) {
+ size_t len;
+ in.value = g_base64_decode (challenge, &len);
+ in.length = len;
+ }
+
+ maj_stat = gss_init_sec_context (&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &conn->context,
+ conn->server_name,
+ (gss_OID) &gss_mech_spnego,
+ GSS_C_MUTUAL_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &in,
+ NULL,
+ &out,
+ NULL,
+ NULL);
+
+ if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
+ soup_gss_error (maj_stat, min_stat, err);
+ ret = AUTH_GSS_ERROR;
+ goto out;
+ }
+
+ ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
+ if (out.length) {
+ gchar *response = g_base64_encode ((const guchar *) out.value, out.length);
+ conn->response_header = g_strconcat ("Negotiate ", response, NULL);
+ g_free (response);
+ maj_stat = gss_release_buffer (&min_stat, &out);
+ }
+
+out:
+ if (out.value)
+ gss_release_buffer (&min_stat, &out);
+ if (in.value)
+ g_free (in.value);
+ return ret;
+}
+
+G_MODULE_EXPORT void
+soup_gss_client_cleanup (SoupNegotiateConnectionState *conn)
+{
+ OM_uint32 min_stat;
+
+ gss_release_name (&min_stat, &conn->server_name);
+}
+#endif /* HAVE_GSSAPI */
diff --git a/libsoup/soup-auth-negotiate.h b/libsoup/soup-auth-negotiate.h
index dbdfc3c..d6d373f 100644
--- a/libsoup/soup-auth-negotiate.h
+++ b/libsoup/soup-auth-negotiate.h
@@ -6,6 +6,8 @@
#ifndef SOUP_AUTH_NEGOTIATE_H
#define SOUP_AUTH_NEGOTIATE_H 1
+#if HAVE_GSSAPI
+
#include "soup-connection-auth.h"
#define SOUP_AUTH_NEGOTIATE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_AUTH_NEGOTIATE,
SoupAuthNegotiate))
@@ -24,4 +26,6 @@ typedef struct {
} SoupAuthNegotiateClass;
+#endif /* HAVE_GSSAPI */
+
#endif /* SOUP_AUTH_NEGOTIATE_H */
diff --git a/libsoup/soup-auth.h b/libsoup/soup-auth.h
index 8db2ccc..e471587 100644
--- a/libsoup/soup-auth.h
+++ b/libsoup/soup-auth.h
@@ -99,8 +99,10 @@ GType soup_auth_basic_get_type (void);
GType soup_auth_digest_get_type (void);
#define SOUP_TYPE_AUTH_NTLM (soup_auth_ntlm_get_type ())
GType soup_auth_ntlm_get_type (void);
+#if HAVE_GSSAPI
#define SOUP_TYPE_AUTH_NEGOTIATE (soup_auth_negotiate_get_type ())
GType soup_auth_negotiate_get_type (void);
+#endif
/* Deprecated SoupPasswordManager-related APIs: all are now no-ops */
SOUP_AVAILABLE_IN_2_28
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]