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