On windows-sspi branch: Allocate SSPI/GSSAPI security context in pool and 
free them it automatically on pool cleanup.

* auth/auth_kerb.h
  (SERF__KERB_NO_CONTEXT): Removed.
  (serf__kerb_create_sec_context): New function declaration. Creates
   empty security context in pool and delete it on pool cleanup.
  (serf__kerb_init_sec_context): Add RESULT_POOL parameter to allocate
   output buffers.
* auth/auth_kerb_gss.c
  (): Remove stdlib.h include.
  (cleanup_ctx): New. Deletes GSS security context on pool cleanup.
  (cleanup_sec_buffer): New. Releases GSS buffer on pool cleanup.
  (serf__kerb_create_sec_context): New.
  (serf__kerb_init_sec_context): Add RESULT_POOL parameter. Do not 
   create security context on demand. Register pool cleanup handler to 
   release GSS output buffer.
  (serf__kerb_delete_sec_context, serf__kerb_release_buffer): Removed.
* auth/auth_kerb_sspi.c
  (cleanup_ctx): New. Deletes SSPI security context on pool cleanup.
  (cleanup_sec_buffer): New. Releases SSPI buffer on pool cleanup.
  (serf__kerb_create_sec_context): New. Allocate security context structure,
   acquire credentials from SSPI and register pool cleanup handler to delete
   security context.
  (serf__kerb_init_sec_context): Add RESULT_POOL parameter. Do not    
   create security context on demand. Register pool cleanup handler to 
   release SSPI output buffer.
  (serf__kerb_delete_sec_context, serf__kerb_release_buffer): Removed.
* auth/auth_kerb.c
  (gss_api_get_credentials): Use serf__kerb_init_sec_context's ability to
   allocate output token in specified pool.
  (cleanup_gss_info): Removed.
  (serf__init_kerb_connection): Use serf__kerb_create_sec_context to create
   initial security context. Do not register pool cleanup handler since
   serf__kerb_create_sec_context already done it.



git-svn-id: https://svn.apache.org/repos/asf/serf/branches/windows-sspi@1698876 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/auth/auth_kerb.c b/auth/auth_kerb.c
index 96c29c0..a332620 100644
--- a/auth/auth_kerb.c
+++ b/auth/auth_kerb.c
@@ -140,10 +140,11 @@
 
     /* Establish a security context to the server. */
     status = serf__kerb_init_sec_context
-        (&gss_info->gss_ctx,
+        (gss_info->gss_ctx,
          KRB_HTTP_SERVICE, hostname,
          &input_buf,
          &output_buf,
+         gss_info->pool,
          gss_info->pool
         );
 
@@ -161,11 +162,9 @@
     }
 
     /* Return the session key to our caller. */
-    *buf = apr_pmemdup(gss_info->pool, output_buf.value, output_buf.length);
+    *buf = output_buf.value;
     *buf_len = output_buf.length;
 
-    serf__kerb_release_buffer(&output_buf);
-
     return status;
 }
 
@@ -240,24 +239,6 @@
     return APR_SUCCESS;
 }
 
-/* Cleans the gssapi context object, when the pool used to create it gets
-   cleared or destroyed. */
-static apr_status_t
-cleanup_gss_info(void *data)
-{
-    gss_authn_info_t *gss_info = data;
-
-    if (gss_info->gss_ctx != SERF__KERB_NO_CONTEXT) {
-        if (serf__kerb_delete_sec_context(gss_info->gss_ctx)) {
-            return APR_EGENERAL;
-        }
-
-        gss_info->gss_ctx = SERF__KERB_NO_CONTEXT;
-    }
-
-    return APR_SUCCESS;
-}
-
 /* A new connection is created to a server that's known to use
    Kerberos. */
 apr_status_t
@@ -266,21 +247,24 @@
                            apr_pool_t *pool)
 {
     gss_authn_info_t *gss_info;
+    apr_status_t status;
 
     gss_info = apr_pcalloc(pool, sizeof(*gss_info));
     gss_info->pool = conn->pool;
     gss_info->state = gss_api_auth_not_started;
-    gss_info->gss_ctx = SERF__KERB_NO_CONTEXT;
+    status = serf__kerb_create_sec_context(&gss_info->gss_ctx, pool,
+                                           gss_info->pool);
+
+    if (status) {
+        return status;
+    }
+
     if (code == 401) {
         conn->authn_baton = gss_info;
     } else {
         conn->proxy_authn_baton = gss_info;
     }
 
-    apr_pool_cleanup_register(gss_info->pool, gss_info,
-                              cleanup_gss_info,
-                              apr_pool_cleanup_null);
-
     /* Make serf send the initial requests one by one */
     serf_connection_set_max_outstanding_requests(conn, 1);
 
diff --git a/auth/auth_kerb.h b/auth/auth_kerb.h
index 3e64c5a..71c28b0 100644
--- a/auth/auth_kerb.h
+++ b/auth/auth_kerb.h
@@ -35,25 +35,30 @@
 

 typedef struct serf__kerb_context_t serf__kerb_context_t;

 

-#define SERF__KERB_NO_CONTEXT ((serf__kerb_context_t*) NULL)

-

 typedef struct serf__kerb_buffer_t {

     apr_size_t length;

     void *value;

 } serf__kerb_buffer_t;

 

+/* Create outbound security context.

+ *

+ * All temporary allocations will be performed in SCRATCH_POOL, while security

+ * context will be allocated in result_pool and will be destroyed automatically

+ * on RESULT_POOL cleanup.

+ *

+ */

+apr_status_t

+serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,

+                              apr_pool_t *scratch_pool,

+                              apr_pool_t *result_pool);

+

 /* Initialize outbound security context.

  *

  * The function is used to build a security context between the client

  * application and a remote peer.

  *

- * CTX_P is pointer to existing context. On the first call value pointed by

- * CTX_P should be SERF__KERB_NO_CONTEXT. On exit this value will be set

- * to created security context.

- *

- * All temporary allocations will be performed in SCRATCH_POOL, but security

- * context allocated in heap directly and should be freed using

- * serf__kerb_delete_sec_context function().

+ * CTX is pointer to existing context created using

+ * serf__kerb_create_sec_context() function.

  *

  * SERVICE is name of Kerberos service name. Usually 'HTTP'. HOSTNAME is

  * canonical name of destination server. Caller should resolve server's alias

@@ -63,8 +68,10 @@
  * zero length on first call.

  *

  * OUTPUT_BUF will be populated with pointer to output data that should send

- * to destination server. This buffer should be freed using

- * serf__kerb_release_buffer function.

+ * to destination server. This buffer will be automatically freed on

+ * RESULT_POOL cleanup.

+ *

+ * All temporary allocations will be performed in SCRATCH_POOL.

  *

  * Return value:

  * - APR_EAGAIN The client must send the output token to the server and wait

@@ -78,21 +85,15 @@
  * Other returns values indicates error.

  */

 apr_status_t

-serf__kerb_init_sec_context(serf__kerb_context_t **ctx_p,

+serf__kerb_init_sec_context(serf__kerb_context_t *ctx,

                             const char *service,

                             const char *hostname,

                             serf__kerb_buffer_t *input_buf,

                             serf__kerb_buffer_t *output_buf,

-                            apr_pool_t *scratch_pool

+                            apr_pool_t *scratch_pool,

+                            apr_pool_t *result_pool

                             );

 

-/* The serf__kerb_delete_sec_context function deletes security context. */

-apr_status_t serf__kerb_delete_sec_context(serf__kerb_context_t *ctx);

-

-/* Free a memory buffer that was allocated as result of calls to

- * serf__kerb_init_sec_context(). */

-apr_status_t serf__kerb_release_buffer(serf__kerb_buffer_t *buf);

-

 #ifdef __cplusplus

 }

 #endif

diff --git a/auth/auth_kerb_gss.c b/auth/auth_kerb_gss.c
index 8759d62..fb0bc81 100644
--- a/auth/auth_kerb_gss.c
+++ b/auth/auth_kerb_gss.c
@@ -18,7 +18,6 @@
 #ifdef SERF_USE_GSSAPI

 #include <apr_strings.h>

 #include <gssapi/gssapi.h>

-#include <stdlib.h>

 

 struct serf__kerb_context_t

 {

@@ -29,21 +28,70 @@
     gss_OID gss_mech;

 };

 

+/* Cleans the GSS context object, when the pool used to create it gets

+   cleared or destroyed. */

+static apr_status_t

+cleanup_ctx(void *data)

+{

+    OM_uint32 min_stat;

+    serf__kerb_context_t *ctx = data;

+

+    if (ctx->gss_ctx != GSS_C_NO_CONTEXT) {

+        if (gss_delete_sec_context(&min_stat, &ctx->gss_ctx,

+                                   GSS_C_NO_BUFFER) == GSS_S_FAILURE)

+            return APR_EGENERAL;

+    }

+

+    return APR_SUCCESS;

+}

+

+static apr_status_t

+cleanup_sec_buffer(void *data)

+{

+    OM_uint32 min_stat;

+    gss_buffer_desc *gss_buf = data;

+

+    gss_release_buffer(&min_stat, gss_buf);

+

+    return APR_SUCCESS;

+}

+

 apr_status_t

-serf__kerb_init_sec_context(serf__kerb_context_t **ctx_p,

-                              const char *service,

-                              const char *hostname,

-                              serf__kerb_buffer_t *input_buf,

-                              serf__kerb_buffer_t *output_buf,

-                              apr_pool_t *scratch_pool

-                              )

+serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,

+                              apr_pool_t *scratch_pool,

+                              apr_pool_t *result_pool)

+{

+    serf__kerb_context_t *ctx;

+

+    ctx = apr_pcalloc(result_pool, sizeof(*ctx));

+

+    ctx->gss_ctx = GSS_C_NO_CONTEXT;

+    ctx->gss_mech = GSS_C_NO_OID;

+

+    apr_pool_cleanup_register(result_pool, ctx,

+                              cleanup_ctx,

+                              apr_pool_cleanup_null);

+

+    *ctx_p = ctx;

+

+    return APR_SUCCESS;

+}

+

+apr_status_t

+serf__kerb_init_sec_context(serf__kerb_context_t *ctx,

+                            const char *service,

+                            const char *hostname,

+                            serf__kerb_buffer_t *input_buf,

+                            serf__kerb_buffer_t *output_buf,

+                            apr_pool_t *scratch_pool,

+                            apr_pool_t *result_pool

+                            )

 {

     gss_buffer_desc gss_input_buf = GSS_C_EMPTY_BUFFER;

-    gss_buffer_desc gss_output_buf;

+    gss_buffer_desc *gss_output_buf_p;

     OM_uint32 gss_min_stat, gss_maj_stat;

     gss_name_t host_gss_name;

     gss_buffer_desc bufdesc;

-    serf__kerb_context_t *ctx = *ctx_p;

 

     /* Get the name for the HTTP service at the target host. */

     bufdesc.value = apr_pstrcat(scratch_pool, service, "@", hostname, NULL);

@@ -54,19 +102,13 @@
         return APR_EGENERAL;

     }

 

-    if (ctx == SERF__KERB_NO_CONTEXT)

-    {

-        ctx = malloc(sizeof(*ctx));

-        ctx->gss_ctx = GSS_C_NO_CONTEXT;

-        ctx->gss_mech = GSS_C_NO_OID;

-        *ctx_p = ctx;

-    }

-

     /* If the server sent us a token, pass it to gss_init_sec_token for

        validation. */

     gss_input_buf.value = input_buf->value;

     gss_input_buf.length = input_buf->length;

 

+    gss_output_buf_p = apr_pcalloc(result_pool, sizeof(*gss_output_buf_p));

+

     /* Establish a security context to the server. */

     gss_maj_stat = gss_init_sec_context

         (&gss_min_stat,             /* minor_status */

@@ -79,13 +121,17 @@
          GSS_C_NO_CHANNEL_BINDINGS, /* do not use channel bindings */

          &gss_input_buf,            /* server token, initially empty */

          &ctx->gss_mech,            /* actual mech type */

-         &gss_output_buf,           /* output_token */

+         gss_output_buf_p,           /* output_token */

          NULL,                      /* ret_flags */

          NULL                       /* not interested in remaining validity */

          );

 

-    output_buf->value = gss_output_buf.value;

-    output_buf->length = gss_output_buf.length;

+    apr_pool_cleanup_register(result_pool, gss_output_buf_p,

+                              cleanup_sec_buffer,

+                              apr_pool_cleanup_null);

+

+    output_buf->value = gss_output_buf_p->value;

+    output_buf->length = gss_output_buf_p->length;

 

     switch(gss_maj_stat) {

     case GSS_S_COMPLETE:

@@ -97,32 +143,4 @@
     }

 }

 

-apr_status_t serf__kerb_delete_sec_context(serf__kerb_context_t *ctx)

-{

-    OM_uint32 min_stat;

-

-    if (ctx->gss_ctx != GSS_C_NO_CONTEXT) {

-        if (gss_delete_sec_context(&min_stat, &ctx->gss_ctx,

-                                   GSS_C_NO_BUFFER) == GSS_S_FAILURE)

-            return APR_EGENERAL;

-    }

-

-    free(ctx);

-

-    return APR_SUCCESS;

-}

-

-apr_status_t serf__kerb_release_buffer(serf__kerb_buffer_t *buf)

-{

-    OM_uint32 min_stat;

-    gss_buffer_desc gss_buf;

-

-    gss_buf.length = buf->length;

-    gss_buf.value = buf->value;

-

-    gss_release_buffer(&min_stat, &gss_buf);

-

-    return APR_SUCCESS;

-}

-

 #endif /* SERF_USE_GSSAPI */

diff --git a/auth/auth_kerb_sspi.c b/auth/auth_kerb_sspi.c
index 6722832..3d32a02 100644
--- a/auth/auth_kerb_sspi.c
+++ b/auth/auth_kerb_sspi.c
@@ -29,13 +29,74 @@
     BOOL initalized;

 };

 

+/* Cleans the SSPI context object, when the pool used to create it gets

+   cleared or destroyed. */

+static apr_status_t

+cleanup_ctx(void *data)

+{

+    serf__kerb_context_t *ctx = data;

+

+    if (SecIsValidHandle(&ctx->sspi_context)) {

+        DeleteSecurityContext(&ctx->sspi_context);

+        SecInvalidateHandle(&ctx->sspi_context);

+    }

+

+    if (SecIsValidHandle(&ctx->sspi_credentials)) {

+        FreeCredentialsHandle(&ctx->sspi_context);

+        SecInvalidateHandle(&ctx->sspi_context);

+    }

+

+    return APR_SUCCESS;

+}

+

+static apr_status_t

+cleanup_sec_buffer(void *data)

+{

+    FreeContextBuffer(data);

+

+    return APR_SUCCESS;

+}

+

 apr_status_t

-serf__kerb_init_sec_context(serf__kerb_context_t **ctx_p,

+serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,

+                              apr_pool_t *scratch_pool,

+                              apr_pool_t *result_pool)

+{

+    SECURITY_STATUS sspi_status;

+    serf__kerb_context_t *ctx;

+

+    ctx = apr_pcalloc(result_pool, sizeof(*ctx));

+

+    SecInvalidateHandle(&ctx->sspi_context);

+    SecInvalidateHandle(&ctx->sspi_credentials);

+    ctx->initalized = FALSE;

+

+    apr_pool_cleanup_register(result_pool, ctx,

+                              cleanup_ctx,

+                              apr_pool_cleanup_null);

+

+    sspi_status = AcquireCredentialsHandle(

+        NULL, "Negotiate", SECPKG_CRED_OUTBOUND,

+        NULL, NULL, NULL, NULL,

+        &ctx->sspi_credentials, NULL);

+

+    if (FAILED(sspi_status)) {

+        return APR_EGENERAL;

+    }

+

+    *ctx_p = ctx;

+

+    return APR_SUCCESS;

+}

+

+apr_status_t

+serf__kerb_init_sec_context(serf__kerb_context_t *ctx,

                             const char *service,

                             const char *hostname,

                             serf__kerb_buffer_t *input_buf,

                             serf__kerb_buffer_t *output_buf,

-                            apr_pool_t *scratch_pool

+                            apr_pool_t *scratch_pool,

+                            apr_pool_t *result_pool

                             )

 {

     SECURITY_STATUS status;

@@ -44,27 +105,8 @@
     SecBufferDesc sspi_in_buffer_desc;

     SecBuffer sspi_out_buffer;

     SecBufferDesc sspi_out_buffer_desc;

-    serf__kerb_context_t *context = *ctx_p;

     char *target_name;

 

-    if (context == SERF__KERB_NO_CONTEXT) {

-        context = malloc(sizeof(*context));

-        SecInvalidateHandle(&context->sspi_context);

-        SecInvalidateHandle(&context->sspi_credentials);

-        context->initalized = FALSE;

-

-        status = AcquireCredentialsHandle(

-            NULL, "Negotiate", SECPKG_CRED_OUTBOUND,

-            NULL, NULL, NULL, NULL,

-            &context->sspi_credentials, NULL);

-

-        if (FAILED(status)) {

-            return APR_EGENERAL;

-        }

-

-        *ctx_p = context;

-    }

-

     target_name = apr_pstrcat(scratch_pool, service, "/", hostname, NULL);

 

     /* Prepare input buffer description. */

@@ -86,8 +128,8 @@
     sspi_out_buffer_desc.ulVersion = SECBUFFER_VERSION;

 

     status = InitializeSecurityContext(

-        &context->sspi_credentials,

-        context->initalized ? &context->sspi_context : NULL,

+        &ctx->sspi_credentials,

+        ctx->initalized ? &ctx->sspi_context : NULL,

         target_name,

         ISC_REQ_ALLOCATE_MEMORY

         | ISC_REQ_MUTUAL_AUTH

@@ -96,18 +138,24 @@
         SECURITY_NETWORK_DREP,

         &sspi_in_buffer_desc,

         0,                          /* Reserved2 */

-        &context->sspi_context,

+        &ctx->sspi_context,

         &sspi_out_buffer_desc,

         &actual_attr,

         NULL);

 

-    context->initalized = TRUE;

+    if (sspi_out_buffer.cbBuffer > 0) {

+        apr_pool_cleanup_register(result_pool, sspi_out_buffer.pvBuffer,

+                                  cleanup_sec_buffer,

+                                  apr_pool_cleanup_null);

+    }

+

+    ctx->initalized = TRUE;

 

     /* Finish authentication if SSPI requires so. */

     if (status == SEC_I_COMPLETE_NEEDED

         || status == SEC_I_COMPLETE_AND_CONTINUE)

     {

-        CompleteAuthToken(&context->sspi_context, &sspi_out_buffer_desc);

+        CompleteAuthToken(&ctx->sspi_context, &sspi_out_buffer_desc);

     }

 

     output_buf->value = sspi_out_buffer.pvBuffer;

@@ -127,34 +175,4 @@
     }

 }

 

-apr_status_t

-serf__kerb_release_buffer(serf__kerb_buffer_t *buf)

-{

-    if (buf->length > 0 && buf->value != NULL) {

-        FreeContextBuffer(buf->value);

-        buf->length = 0;

-        buf->value = NULL;

-    }

-

-    return APR_SUCCESS;

-}

-

-apr_status_t

-serf__kerb_delete_sec_context(serf__kerb_context_t *ctx)

-{

-    if (SecIsValidHandle(&ctx->sspi_context)) {

-        DeleteSecurityContext(&ctx->sspi_context);

-        SecInvalidateHandle(&ctx->sspi_context);

-    }

-

-    if (SecIsValidHandle(&ctx->sspi_credentials)) {

-        FreeCredentialsHandle(&ctx->sspi_context);

-        SecInvalidateHandle(&ctx->sspi_context);

-    }

-

-    free(ctx);

-

-    return APR_SUCCESS;

-}

-

 #endif /* SERF_USE_SSPI */
\ No newline at end of file