From 74dd0183e4e56b07cedfa87eae7a8fb3166f01e8 Mon Sep 17 00:00:00 2001 From: Lorry Date: Tue, 28 Aug 2012 15:30:14 +0100 Subject: Tarball conversion --- auth/auth_kerb_sspi.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 auth/auth_kerb_sspi.c (limited to 'auth/auth_kerb_sspi.c') diff --git a/auth/auth_kerb_sspi.c b/auth/auth_kerb_sspi.c new file mode 100644 index 0000000..db28ab1 --- /dev/null +++ b/auth/auth_kerb_sspi.c @@ -0,0 +1,210 @@ +/* Copyright 2010 Justin Erenkrantz and Greg Stein + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "auth_kerb.h" + +#ifdef SERF_USE_SSPI +#include +#include + +#define SECURITY_WIN32 +#include + +struct serf__kerb_context_t +{ + CredHandle sspi_credentials; + CtxtHandle sspi_context; + 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_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; +} + +static apr_status_t +get_canonical_hostname(const char **canonname, + const char *hostname, + apr_pool_t *pool) +{ + struct addrinfo hints; + struct addrinfo *addrinfo; + + ZeroMemory(&hints, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + + if (getaddrinfo(hostname, NULL, &hints, &addrinfo)) { + return apr_get_netos_error(); + } + + if (addrinfo) { + *canonname = apr_pstrdup(pool, addrinfo->ai_canonname); + } + else { + *canonname = apr_pstrdup(pool, hostname); + } + + freeaddrinfo(addrinfo); + 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 + ) +{ + SECURITY_STATUS status; + ULONG actual_attr; + SecBuffer sspi_in_buffer; + SecBufferDesc sspi_in_buffer_desc; + SecBuffer sspi_out_buffer; + SecBufferDesc sspi_out_buffer_desc; + char *target_name; + apr_status_t apr_status; + const char *canonname; + + apr_status = get_canonical_hostname(&canonname, hostname, scratch_pool); + if (apr_status) { + return apr_status; + } + target_name = apr_pstrcat(scratch_pool, service, "/", canonname, NULL); + + /* Prepare input buffer description. */ + sspi_in_buffer.BufferType = SECBUFFER_TOKEN; + sspi_in_buffer.pvBuffer = input_buf->value; + sspi_in_buffer.cbBuffer = input_buf->length; + + sspi_in_buffer_desc.cBuffers = 1; + sspi_in_buffer_desc.pBuffers = &sspi_in_buffer; + sspi_in_buffer_desc.ulVersion = SECBUFFER_VERSION; + + /* Output buffers. Output buffer will be allocated by system. */ + sspi_out_buffer.BufferType = SECBUFFER_TOKEN; + sspi_out_buffer.pvBuffer = NULL; + sspi_out_buffer.cbBuffer = 0; + + sspi_out_buffer_desc.cBuffers = 1; + sspi_out_buffer_desc.pBuffers = &sspi_out_buffer; + sspi_out_buffer_desc.ulVersion = SECBUFFER_VERSION; + + status = InitializeSecurityContext( + &ctx->sspi_credentials, + ctx->initalized ? &ctx->sspi_context : NULL, + target_name, + ISC_REQ_ALLOCATE_MEMORY + | ISC_REQ_MUTUAL_AUTH + | ISC_REQ_CONFIDENTIALITY, + 0, /* Reserved1 */ + SECURITY_NETWORK_DREP, + &sspi_in_buffer_desc, + 0, /* Reserved2 */ + &ctx->sspi_context, + &sspi_out_buffer_desc, + &actual_attr, + NULL); + + 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(&ctx->sspi_context, &sspi_out_buffer_desc); + } + + output_buf->value = sspi_out_buffer.pvBuffer; + output_buf->length = sspi_out_buffer.cbBuffer; + + switch(status) { + case SEC_I_COMPLETE_AND_CONTINUE: + case SEC_I_CONTINUE_NEEDED: + return APR_EAGAIN; + + case SEC_I_COMPLETE_NEEDED: + case SEC_E_OK: + return APR_SUCCESS; + + default: + return APR_EGENERAL; + } +} + +#endif /* SERF_USE_SSPI */ \ No newline at end of file -- cgit v1.2.1