- Christian Krause filed bug #2221237
authorDaniel Stenberg <daniel@haxx.se>
Mon, 8 Dec 2008 13:52:20 +0000 (13:52 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 8 Dec 2008 13:52:20 +0000 (13:52 +0000)
  (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
RELEASE-NOTES
lib/http.c
lib/urldata.h

diff --git a/CHANGES b/CHANGES
index 57aa101..1e466d5 100644 (file)
--- 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)
index c417765..0cc307b 100644 (file)
@@ -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:
 
index 70bf61e..f7b3610 100644 (file)
@@ -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;
       }
     }
   }
index 7073775..aafa26e 100644 (file)
@@ -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;