summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c')
-rw-r--r--third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c b/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c
new file mode 100644
index 0000000..906f457
--- /dev/null
+++ b/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2010 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "netlogon.h"
+#include <nameser.h>
+
+static OM_uint32
+_netlogon_encode_dns_string(OM_uint32 *minor_status,
+ const gss_buffer_t str,
+ gss_buffer_t buffer)
+{
+ int ret;
+
+ memset(buffer->value, 0, buffer->length);
+
+ ret = ns_name_compress((const char *)str->value,
+ (uint8_t *)buffer->value, buffer->length,
+ NULL, NULL);
+ if (ret < 0) {
+ *minor_status = errno;
+ return GSS_S_FAILURE;
+ }
+
+ buffer->length = ret;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+_netlogon_make_initial_auth_message(OM_uint32 *minor_status,
+ gssnetlogon_ctx ctx,
+ gss_buffer_t output_token)
+{
+ uint32_t flags = 0;
+#define MAX_NL_NAMES 5
+ gss_buffer_desc names[MAX_NL_NAMES];
+ uint8_t comp_names[3][MAXHOSTNAMELEN * 2];
+ size_t n = 0, i = 0, len;
+ OM_uint32 ret;
+ uint8_t *p;
+
+ if (ctx->TargetName->NetbiosName.length) {
+ flags |= NL_FLAG_NETBIOS_DOMAIN_NAME;
+ names[n] = ctx->TargetName->NetbiosName; /* OEM encoding */
+ names[n].length++;
+ n++;
+ }
+ if (ctx->SourceName->NetbiosName.length) {
+ flags |= NL_FLAG_NETBIOS_COMPUTER_NAME;
+ names[n] = ctx->SourceName->NetbiosName; /* OEM encoding */
+ names[n].length++;
+ n++;
+ }
+ if (ctx->TargetName->DnsName.length) {
+ flags |= NL_FLAG_DNS_DOMAIN_NAME;
+ names[n].value = comp_names[i++];
+ names[n].length = MAXHOSTNAMELEN * 2;
+ ret = _netlogon_encode_dns_string(minor_status,
+ &ctx->TargetName->DnsName,
+ &names[n]);
+ if (GSS_ERROR(ret))
+ return ret;
+ n++;
+ }
+ if (ctx->SourceName->DnsName.length) {
+ flags |= NL_FLAG_DNS_HOST_NAME;
+ names[n].value = comp_names[i++];
+ names[n].length = MAXHOSTNAMELEN * 2;
+ ret = _netlogon_encode_dns_string(minor_status,
+ &ctx->SourceName->DnsName,
+ &names[n]);
+ if (GSS_ERROR(ret))
+ return ret;
+ n++;
+ }
+ if (ctx->SourceName->NetbiosName.length) {
+ flags |= NL_FLAG_UTF8_COMPUTER_NAME;
+ names[n].value = comp_names[i++];
+ names[n].length = MAXHOSTNAMELEN * 2;
+ ret = _netlogon_encode_dns_string(minor_status,
+ &ctx->SourceName->NetbiosName,
+ &names[n]);
+ if (GSS_ERROR(ret))
+ return ret;
+ n++;
+ }
+
+ for (i = 0, len = NL_AUTH_MESSAGE_LENGTH; i < n; i++) {
+ len += names[i].length;
+ }
+
+ output_token->value = malloc(len);
+ if (output_token->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = (uint8_t *)output_token->value;
+ _gss_mg_encode_le_uint32(NL_NEGOTIATE_REQUEST_MESSAGE, p);
+ _gss_mg_encode_le_uint32(flags, p + 4);
+ p += 8;
+
+ for (i = 0; i < n; i++) {
+ assert(names[i].length != 0);
+ assert(((char *)names[i].value)[names[i].length - 1] == '\0');
+ memcpy(p, names[i].value, names[i].length);
+ p += names[i].length;
+ }
+
+ output_token->length = len;
+ assert(p == (uint8_t *)output_token->value + len);
+
+ *minor_status = 0;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+_netlogon_read_initial_auth_message(OM_uint32 *minor_status,
+ gssnetlogon_ctx ctx,
+ const gss_buffer_t input_token)
+{
+ NL_AUTH_MESSAGE msg;
+ const uint8_t *p = (const uint8_t *)input_token->value;
+
+ if (ctx->State != NL_AUTH_NEGOTIATE) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ if (input_token->length < NL_AUTH_MESSAGE_LENGTH)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ _gss_mg_decode_le_uint32(&p[0], &msg.MessageType);
+ _gss_mg_decode_le_uint32(&p[4], &msg.Flags);
+
+ if (msg.MessageType != NL_NEGOTIATE_RESPONSE_MESSAGE ||
+ msg.Flags != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ ctx->State = NL_AUTH_ESTABLISHED;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+_netlogon_alloc_context(OM_uint32 *minor_status,
+ gssnetlogon_ctx *pContext)
+{
+ gssnetlogon_ctx ctx;
+
+ ctx = (gssnetlogon_ctx)calloc(1, sizeof(*ctx));
+ if (ctx == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ ctx->State = NL_AUTH_NEGOTIATE;
+ ctx->LocallyInitiated = 1;
+ ctx->MessageBlockSize = 1;
+
+ HEIMDAL_MUTEX_init(&ctx->Mutex);
+
+ *pContext = ctx;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_netlogon_init_sec_context(OM_uint32 * minor_status,
+ gss_const_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ gss_const_name_t target_name,
+ const gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ const gss_channel_bindings_t input_chan_bindings,
+ const gss_buffer_t input_token,
+ gss_OID * actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec)
+{
+ const gssnetlogon_cred cred = (const gssnetlogon_cred)initiator_cred_handle;
+ gssnetlogon_ctx ctx = (gssnetlogon_ctx)*context_handle;
+ const gssnetlogon_name target = (const gssnetlogon_name)target_name;
+ OM_uint32 ret;
+
+ *minor_status = 0;
+
+ output_token->value = NULL;
+ output_token->length = 0;
+
+ /* Validate arguments */
+ if (cred == NULL)
+ return GSS_S_NO_CRED;
+ else if (target == NULL)
+ return GSS_S_BAD_NAME;
+
+ if (ctx == NULL) {
+ if (input_token->length != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ ret = _netlogon_alloc_context(minor_status, &ctx);
+ if (GSS_ERROR(ret))
+ goto cleanup;
+
+ HEIMDAL_MUTEX_lock(&ctx->Mutex);
+ *context_handle = (gss_ctx_id_t)ctx;
+
+ ctx->GssFlags = req_flags & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
+ GSS_C_INTEG_FLAG | GSS_C_DCE_STYLE);
+ ctx->SignatureAlgorithm = cred->SignatureAlgorithm;
+ ctx->SealAlgorithm = cred->SealAlgorithm;
+
+ ret = _netlogon_duplicate_name(minor_status, (gss_name_t)cred->Name,
+ (gss_name_t *)&ctx->SourceName);
+ if (GSS_ERROR(ret))
+ goto cleanup;
+
+ ret = _netlogon_duplicate_name(minor_status, (gss_name_t)target,
+ (gss_name_t *)&ctx->TargetName);
+ if (GSS_ERROR(ret))
+ goto cleanup;
+
+ memcpy(ctx->SessionKey, cred->SessionKey, sizeof(cred->SessionKey));
+
+ ret = _netlogon_make_initial_auth_message(minor_status, ctx,
+ output_token);
+ if (GSS_ERROR(ret))
+ goto cleanup;
+ } else {
+ HEIMDAL_MUTEX_lock(&ctx->Mutex);
+ ret = _netlogon_read_initial_auth_message(minor_status, ctx,
+ input_token);
+ }
+
+ if (ret_flags != NULL)
+ *ret_flags = ctx->GssFlags;
+ if (time_rec != NULL)
+ *time_rec = GSS_C_INDEFINITE;
+ if (actual_mech_type != NULL)
+ *actual_mech_type = GSS_NETLOGON_MECHANISM;
+
+cleanup:
+ HEIMDAL_MUTEX_unlock(&ctx->Mutex);
+
+ if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
+ OM_uint32 tmp;
+ _netlogon_delete_sec_context(&tmp, context_handle, NULL);
+ }
+
+ return ret;
+}
+