From 42365aa7ef58f0a466f2e4ee42718c358b5a9937 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 8 Dec 2008 13:52:20 +0000 Subject: - Christian Krause filed bug #2221237 (http://curl.haxx.se/bug/view.cgi?id=2221237) that identified an infinite loop during GSS authentication given some specific conditions. With his patience and great feedback I managed to narrow down the problem and eventually fix it although I can't test any of this myself! --- CHANGES | 7 +++++++ RELEASE-NOTES | 1 + lib/http.c | 50 +++++++++++++++++++++++++++++++++----------------- lib/urldata.h | 3 +++ 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index 57aa101e3..1e466d59c 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,13 @@ Changelog +Daniel Stenberg (8 Dec 2008) +- Christian Krause filed bug #2221237 + (http://curl.haxx.se/bug/view.cgi?id=2221237) that identified an infinite + loop during GSS authentication given some specific conditions. With his + patience and great feedback I managed to narrow down the problem and + eventually fix it although I can't test any of this myself! + Daniel Fandrich (3 Dec 2008) - Fixed the getifaddrs version of Curl_if2ip to work on systems without IPv6 support (e.g. Minix) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index c41776500..0cc307b02 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -24,6 +24,7 @@ This release includes the following bugfixes: o fix SCP/SFTP busyloop by using a new libssh2 0.19 function o bad fclose() after a fatal error in cookie code o curl_multi_remove_handle() when the handle was in use in a HTTP pipeline + o GSS authentication infinite loop problem This release includes the following known bugs: diff --git a/lib/http.c b/lib/http.c index 70bf61e39..f7b3610c6 100644 --- a/lib/http.c +++ b/lib/http.c @@ -507,8 +507,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) static CURLcode output_auth_headers(struct connectdata *conn, struct auth *authstatus, - const char *request, - const char *path, + const char *request, + const char *path, bool proxy) { struct SessionHandle *data = conn->data; @@ -529,6 +529,7 @@ output_auth_headers(struct connectdata *conn, if(result) return result; authstatus->done = TRUE; + data->state.negotiate.state = GSS_AUTHSENT; } else #endif @@ -545,9 +546,9 @@ output_auth_headers(struct connectdata *conn, if(authstatus->picked == CURLAUTH_DIGEST) { auth="Digest"; result = Curl_output_digest(conn, - proxy, - (const unsigned char *)request, - (const unsigned char *)path); + proxy, + (const unsigned char *)request, + (const unsigned char *)path); if(result) return result; } @@ -562,7 +563,7 @@ output_auth_headers(struct connectdata *conn, auth="Basic"; result = http_output_basic(conn, proxy); if(result) - return result; + return result; } /* NOTE: this function should set 'done' TRUE, as the other auth functions work that way */ @@ -571,9 +572,9 @@ output_auth_headers(struct connectdata *conn, if(auth) { infof(data, "%s auth using %s with user '%s'\n", - proxy?"Proxy":"Server", auth, - proxy?(conn->proxyuser?conn->proxyuser:""): - (conn->user?conn->user:"")); + proxy?"Proxy":"Server", auth, + proxy?(conn->proxyuser?conn->proxyuser:""): + (conn->user?conn->user:"")); authstatus->multi = (bool)(!authstatus->done); } else @@ -707,24 +708,39 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, * If the provided authentication is wanted as one out of several accepted * types (using &), we OR this authentication type to the authavail * variable. + * + * Note: + * + * ->picked is first set to the 'want' value (one or more bits) before the + * request is sent, and then it is again set _after_ all response 401/407 + * headers have been received but then only to a single preferred method + * (bit). + * */ #ifdef HAVE_GSSAPI if(checkprefix("GSS-Negotiate", start) || checkprefix("Negotiate", start)) { + int neg; *availp |= CURLAUTH_GSSNEGOTIATE; authp->avail |= CURLAUTH_GSSNEGOTIATE; - if(authp->picked == CURLAUTH_GSSNEGOTIATE) { - /* if exactly this is wanted, go */ - int neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start); + + if(data->state.negotiate.state == GSS_AUTHSENT) { + /* if we sent GSS authentication in the outgoing request and we get this + back, we're in trouble */ + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + else { + neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start); if(neg == 0) { DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(data->change.url); - data->state.authproblem = (data->req.newurl == NULL); - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authproblem = FALSE; + /* we received GSS auth info and we dealt with it fine */ + data->state.negotiate.state = GSS_AUTHRECV; } } } diff --git a/lib/urldata.h b/lib/urldata.h index 707377560..aafa26eab 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -299,6 +299,9 @@ struct ntlmdata { #ifdef HAVE_GSSAPI struct negotiatedata { + /* when doing Negotiate we first need to receive an auth token and then we + need to send our header */ + enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state; bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */ const char* protocol; /* "GSS-Negotiate" or "Negotiate" */ OM_uint32 status; -- cgit v1.2.3