From 7a60f61299e495cd519133184dd0857532ea6518 Mon Sep 17 00:00:00 2001
From: Adam Tkac <atkac@redhat.com>
Date: Tue, 19 Jul 2011 19:10:43 +0200
Subject: [PATCH] Add new CURLOPT_GSSAPI_DELEGATION option.

Curl_gss_init_sec_context got new parameter - SessionHandle.

Signed-off-by: Adam Tkac <atkac@redhat.com>
cherry-picked from commit ebf42c4be76df40ec6d3bf32f229bbb274e2c32f
---
 RELEASE-NOTES                   |    3 ++-
 docs/libcurl/curl_easy_setopt.3 |    4 ++++
 include/curl/curl.h             |    3 +++
 lib/curl_gssapi.c               |   10 ++++++++--
 lib/curl_gssapi.h               |    2 ++
 lib/http_negotiate.c            |   16 +++++++++-------
 lib/krb5.c                      |    3 ++-
 lib/socks_gssapi.c              |    3 ++-
 lib/url.c                       |    6 ++++++
 lib/urldata.h                   |    2 ++
 10 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 7322687..b7f536b 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -2,7 +2,7 @@ Curl and libcurl 7.19.7
 
  Public curl releases:         113
  Command line options:         132
- curl_easy_setopt() options:   163
+ curl_easy_setopt() options:   164
  Public functions in libcurl:  58
  Known libcurl bindings:       38
  Contributors:                 732
@@ -13,6 +13,7 @@ This release includes the following changes:
  o SYST handling on FTP for OS/400 FTP server cases
  o libcurl refuses to read a single HTTP header longer than 100K
  o added the --crlfile option to curl
+ o Added CURLOPT_GSSAPI_DELEGATION
 
 This release includes the following bugfixes:
 
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 40447ca..f384986 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -1723,6 +1723,10 @@ of these, 'private' will be used. Set the string to NULL to disable kerberos
 support for FTP.
 
 (This option was known as CURLOPT_KRB4LEVEL up to 7.16.3)
+.IP CURLOPT_GSSAPI_DELEGATION
+Set the parameter to 1 to allow GSSAPI credential delegation.  The delegation
+is disabled by default since 7.21.7.
+(Added in 7.21.8)
 .SH SSH OPTIONS
 .IP CURLOPT_SSH_AUTH_TYPES
 Pass a long set to a bitmask consisting of one or more of
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 761e69a..8280004 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1280,6 +1280,9 @@ typedef enum {
   /* set the SSH host key callback custom pointer */
   CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
 
+  /* allow GSSAPI credential delegation */
+  CINIT(GSSAPI_DELEGATION, LONG, 210),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c
index 3b6b189..6b47987 100644
--- a/lib/curl_gssapi.c
+++ b/lib/curl_gssapi.c
@@ -27,6 +27,7 @@
 #include "curl_gssapi.h"
 
 OM_uint32 Curl_gss_init_sec_context(
+    const struct SessionHandle *data,
     OM_uint32 * minor_status,
     gss_ctx_id_t * context,
     gss_name_t target_name,
@@ -35,13 +36,18 @@ OM_uint32 Curl_gss_init_sec_context(
     gss_buffer_t output_token,
     OM_uint32 * ret_flags)
 {
+  OM_uint32 req_flags;
+
+  req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
+  if (data->set.gssapi_delegation)
+    req_flags |= GSS_C_DELEG_FLAG;
+
   return gss_init_sec_context(minor_status,
                               GSS_C_NO_CREDENTIAL, /* cred_handle */
                               context,
                               target_name,
                               GSS_C_NO_OID, /* mech_type */
-                              /* req_flags */
-                              GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+                              req_flags,
                               0, /* time_req */
                               input_chan_bindings,
                               input_token,
diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h
index c5fbefe..6b04373 100644
--- a/lib/curl_gssapi.h
+++ b/lib/curl_gssapi.h
@@ -21,6 +21,7 @@
  ***************************************************************************/
 
 #include "setup.h"
+#include "urldata.h"
 
 #ifdef HAVE_GSSAPI
 
@@ -40,6 +41,7 @@
 /* Common method for using gss api */
 
 OM_uint32 Curl_gss_init_sec_context(
+    const struct SessionHandle *data,
     OM_uint32 * minor_status,
     gss_ctx_id_t * context,
     gss_name_t target_name,
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
index 28152b1..2a6dd0e 100644
--- a/lib/http_negotiate.c
+++ b/lib/http_negotiate.c
@@ -135,8 +135,9 @@ log_gss_error(struct connectdata *conn, OM_uint32 error_status, const char *pref
 int Curl_input_negotiate(struct connectdata *conn, bool proxy,
                          const char *header)
 {
-  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
-    &conn->data->state.negotiate;
+  struct SessionHandle *data = conn->data;
+  struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg:
+    &data->state.negotiate;
   OM_uint32 major_status, minor_status, minor_status2;
   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
@@ -172,7 +173,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
     /* We finished succesfully our part of authentication, but server
      * rejected it (since we're again here). Exit with an error since we
      * can't invent anything better */
-    Curl_cleanup_negotiate(conn->data);
+    Curl_cleanup_negotiate(data);
     return -1;
   }
 
@@ -221,7 +222,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
                                     NULL)) {
           free(spnegoToken);
           spnegoToken = NULL;
-          infof(conn->data, "Parse SPNEGO Target Token failed\n");
+          infof(data, "Parse SPNEGO Target Token failed\n");
         }
         else {
           free(input_token.value);
@@ -233,13 +234,14 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
           input_token.length = mechTokenLength;
           free(mechToken);
           mechToken = NULL;
-          infof(conn->data, "Parse SPNEGO Target Token succeeded\n");
+          infof(data, "Parse SPNEGO Target Token succeeded\n");
         }
     }
 #endif
   }
 
-  major_status = Curl_gss_init_sec_context(&minor_status,
+  major_status = Curl_gss_init_sec_context(data,
+                                           &minor_status,
                                            &neg_ctx->context,
                                            neg_ctx->server_name,
                                            GSS_C_NO_CHANNEL_BINDINGS,
@@ -250,7 +252,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
     gss_release_buffer(&minor_status2, &input_token);
   neg_ctx->status = major_status;
   if(GSS_ERROR(major_status)) {
-    /* Curl_cleanup_negotiate(conn->data) ??? */
+    /* Curl_cleanup_negotiate(data) ??? */
     log_gss_error(conn, minor_status,
                   "gss_init_sec_context() failed: ");
     return -1;
diff --git a/lib/krb5.c b/lib/krb5.c
index 68fd9e3..0ec496d 100644
--- a/lib/krb5.c
+++ b/lib/krb5.c
@@ -220,7 +220,8 @@ krb5_auth(void *app_data, struct connectdata *conn)
          taken care by a final gss_release_buffer. */
       gss_release_buffer(&min, &output_buffer);
       ret = AUTH_OK;
-      maj = Curl_gss_init_sec_context(&min,
+      maj = Curl_gss_init_sec_context(data,
+                                      &min,
                                       context,
                                       gssname,
                                       &chan,
diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c
index e2c88ed..c754cf0 100644
--- a/lib/socks_gssapi.c
+++ b/lib/socks_gssapi.c
@@ -185,7 +185,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   /* As long as we need to keep sending some context info, and there's no  */
   /* errors, keep sending it...                                            */
   for(;;) {
-    gss_major_status = Curl_gss_init_sec_context(&gss_minor_status,
+    gss_major_status = Curl_gss_init_sec_context(data,
+                                                 &gss_minor_status,
                                                  &gss_context,
                                                  server,
                                                  NULL,
diff --git a/lib/url.c b/lib/url.c
index 42c2530..b62bb53 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1929,6 +1929,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
                        va_arg(param, char *));
     data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]);
     break;
+  case CURLOPT_GSSAPI_DELEGATION:
+    /*
+     * allow GSSAPI credential delegation
+     */
+    data->set.gssapi_delegation = (bool)(0 != va_arg(param, long));
+    break;
   case CURLOPT_SSL_VERIFYPEER:
     /*
      * Enable peer SSL verifying.
diff --git a/lib/urldata.h b/lib/urldata.h
index 014cb98..71d65fb 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1575,6 +1575,8 @@ struct UserDefined {
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   long socks5_gssapi_nec; /* flag to support nec socks5 server */
 #endif
+
+  bool gssapi_delegation;	/* allow GSSAPI credential delegation */
 };
 
 struct Names {
-- 
1.7.6.1

