summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/gssapi
diff options
context:
space:
mode:
authorHeimdal Import User <samba-bugs@samba.org>2005-07-11 01:16:55 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:19:33 -0500
commit954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9 (patch)
treefc11a048c8a582e2ca66415ff04dacf74f9abf22 /source4/heimdal/lib/gssapi
parent7ead5ab06cea9f33e954a4579163262f97ea06ff (diff)
downloadsamba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.tar.gz
samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.tar.bz2
samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.zip
r8302: import mini HEIMDAL into the tree
(This used to be commit 118be28a7aef233799956615a99d1a2a74dac175)
Diffstat (limited to 'source4/heimdal/lib/gssapi')
-rw-r--r--source4/heimdal/lib/gssapi/8003.c246
-rw-r--r--source4/heimdal/lib/gssapi/accept_sec_context.c1118
-rw-r--r--source4/heimdal/lib/gssapi/acquire_cred.c376
-rw-r--r--source4/heimdal/lib/gssapi/add_oid_set_member.c69
-rw-r--r--source4/heimdal/lib/gssapi/address_to_krb5addr.c76
-rw-r--r--source4/heimdal/lib/gssapi/arcfour.c660
-rw-r--r--source4/heimdal/lib/gssapi/arcfour.h74
-rwxr-xr-xsource4/heimdal/lib/gssapi/ccache_name.c80
-rwxr-xr-xsource4/heimdal/lib/gssapi/cfx.c841
-rwxr-xr-xsource4/heimdal/lib/gssapi/cfx.h104
-rw-r--r--source4/heimdal/lib/gssapi/compat.c154
-rw-r--r--source4/heimdal/lib/gssapi/context_time.c87
-rw-r--r--source4/heimdal/lib/gssapi/copy_ccache.c134
-rw-r--r--source4/heimdal/lib/gssapi/create_emtpy_oid_set.c52
-rw-r--r--source4/heimdal/lib/gssapi/decapsulate.c209
-rw-r--r--source4/heimdal/lib/gssapi/delete_sec_context.c77
-rw-r--r--source4/heimdal/lib/gssapi/display_name.c73
-rw-r--r--source4/heimdal/lib/gssapi/display_status.c208
-rw-r--r--source4/heimdal/lib/gssapi/duplicate_name.c59
-rw-r--r--source4/heimdal/lib/gssapi/encapsulate.c153
-rw-r--r--source4/heimdal/lib/gssapi/external.c270
-rw-r--r--source4/heimdal/lib/gssapi/get_mic.c302
-rw-r--r--source4/heimdal/lib/gssapi/gssapi.h826
-rw-r--r--source4/heimdal/lib/gssapi/gssapi_locl.h295
-rw-r--r--source4/heimdal/lib/gssapi/import_name.c229
-rw-r--r--source4/heimdal/lib/gssapi/init.c111
-rw-r--r--source4/heimdal/lib/gssapi/init_sec_context.c1261
-rw-r--r--source4/heimdal/lib/gssapi/inquire_cred.c123
-rw-r--r--source4/heimdal/lib/gssapi/release_buffer.c48
-rw-r--r--source4/heimdal/lib/gssapi/release_cred.c73
-rw-r--r--source4/heimdal/lib/gssapi/release_name.c50
-rw-r--r--source4/heimdal/lib/gssapi/release_oid_set.c49
-rwxr-xr-xsource4/heimdal/lib/gssapi/sequence.c189
-rwxr-xr-xsource4/heimdal/lib/gssapi/spnego.asn142
-rw-r--r--source4/heimdal/lib/gssapi/test_oid_set_member.c55
-rw-r--r--source4/heimdal/lib/gssapi/unwrap.c413
-rw-r--r--source4/heimdal/lib/gssapi/verify_mic.c336
-rw-r--r--source4/heimdal/lib/gssapi/wrap.c533
38 files changed, 10055 insertions, 0 deletions
diff --git a/source4/heimdal/lib/gssapi/8003.c b/source4/heimdal/lib/gssapi/8003.c
new file mode 100644
index 0000000000..b60d2608e2
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/8003.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: 8003.c,v 1.17 2005/04/01 08:55:36 lha Exp $");
+
+krb5_error_code
+gssapi_encode_om_uint32(OM_uint32 n, u_char *p)
+{
+ p[0] = (n >> 0) & 0xFF;
+ p[1] = (n >> 8) & 0xFF;
+ p[2] = (n >> 16) & 0xFF;
+ p[3] = (n >> 24) & 0xFF;
+ return 0;
+}
+
+krb5_error_code
+gssapi_encode_be_om_uint32(OM_uint32 n, u_char *p)
+{
+ p[0] = (n >> 24) & 0xFF;
+ p[1] = (n >> 16) & 0xFF;
+ p[2] = (n >> 8) & 0xFF;
+ p[3] = (n >> 0) & 0xFF;
+ return 0;
+}
+
+krb5_error_code
+gssapi_decode_om_uint32(u_char *p, OM_uint32 *n)
+{
+ *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+ return 0;
+}
+
+krb5_error_code
+gssapi_decode_be_om_uint32(u_char *p, OM_uint32 *n)
+{
+ *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+ return 0;
+}
+
+static krb5_error_code
+hash_input_chan_bindings (const gss_channel_bindings_t b,
+ u_char *p)
+{
+ u_char num[4];
+ MD5_CTX md5;
+
+ MD5_Init(&md5);
+ gssapi_encode_om_uint32 (b->initiator_addrtype, num);
+ MD5_Update (&md5, num, sizeof(num));
+ gssapi_encode_om_uint32 (b->initiator_address.length, num);
+ MD5_Update (&md5, num, sizeof(num));
+ if (b->initiator_address.length)
+ MD5_Update (&md5,
+ b->initiator_address.value,
+ b->initiator_address.length);
+ gssapi_encode_om_uint32 (b->acceptor_addrtype, num);
+ MD5_Update (&md5, num, sizeof(num));
+ gssapi_encode_om_uint32 (b->acceptor_address.length, num);
+ MD5_Update (&md5, num, sizeof(num));
+ if (b->acceptor_address.length)
+ MD5_Update (&md5,
+ b->acceptor_address.value,
+ b->acceptor_address.length);
+ gssapi_encode_om_uint32 (b->application_data.length, num);
+ MD5_Update (&md5, num, sizeof(num));
+ if (b->application_data.length)
+ MD5_Update (&md5,
+ b->application_data.value,
+ b->application_data.length);
+ MD5_Final (p, &md5);
+ return 0;
+}
+
+/*
+ * create a checksum over the chanel bindings in
+ * `input_chan_bindings', `flags' and `fwd_data' and return it in
+ * `result'
+ */
+
+OM_uint32
+gssapi_krb5_create_8003_checksum (
+ OM_uint32 *minor_status,
+ const gss_channel_bindings_t input_chan_bindings,
+ OM_uint32 flags,
+ const krb5_data *fwd_data,
+ Checksum *result)
+{
+ u_char *p;
+
+ /*
+ * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value
+ * field's format) */
+ result->cksumtype = CKSUMTYPE_GSSAPI;
+ if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG))
+ result->checksum.length = 24 + 4 + fwd_data->length;
+ else
+ result->checksum.length = 24;
+ result->checksum.data = malloc (result->checksum.length);
+ if (result->checksum.data == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = result->checksum.data;
+ gssapi_encode_om_uint32 (16, p);
+ p += 4;
+ if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) {
+ memset (p, 0, 16);
+ } else {
+ hash_input_chan_bindings (input_chan_bindings, p);
+ }
+ p += 16;
+ gssapi_encode_om_uint32 (flags, p);
+ p += 4;
+
+ if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) {
+
+ *p++ = (1 >> 0) & 0xFF; /* DlgOpt */ /* == 1 */
+ *p++ = (1 >> 8) & 0xFF; /* DlgOpt */ /* == 0 */
+ *p++ = (fwd_data->length >> 0) & 0xFF; /* Dlgth */
+ *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */
+ memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length);
+
+ p += fwd_data->length;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * verify the checksum in `cksum' over `input_chan_bindings'
+ * returning `flags' and `fwd_data'
+ */
+
+OM_uint32
+gssapi_krb5_verify_8003_checksum(
+ OM_uint32 *minor_status,
+ const gss_channel_bindings_t input_chan_bindings,
+ const Checksum *cksum,
+ OM_uint32 *flags,
+ krb5_data *fwd_data)
+{
+ unsigned char hash[16];
+ unsigned char *p;
+ OM_uint32 length;
+ int DlgOpt;
+ static unsigned char zeros[16];
+
+ if (cksum == NULL) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+
+ /* XXX should handle checksums > 24 bytes */
+ if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+
+ p = cksum->checksum.data;
+ gssapi_decode_om_uint32(p, &length);
+ if(length != sizeof(hash)) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+
+ p += 4;
+
+ if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
+ && memcmp(p, zeros, sizeof(zeros)) != 0) {
+ if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+ if(memcmp(hash, p, sizeof(hash)) != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+ }
+
+ p += sizeof(hash);
+
+ gssapi_decode_om_uint32(p, flags);
+ p += 4;
+
+ if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) {
+ if(cksum->checksum.length < 28) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+
+ DlgOpt = (p[0] << 0) | (p[1] << 8);
+ p += 2;
+ if (DlgOpt != 1) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+
+ fwd_data->length = (p[0] << 0) | (p[1] << 8);
+ p += 2;
+ if(cksum->checksum.length < 28 + fwd_data->length) {
+ *minor_status = 0;
+ return GSS_S_BAD_BINDINGS;
+ }
+ fwd_data->data = malloc(fwd_data->length);
+ if (fwd_data->data == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(fwd_data->data, p, fwd_data->length);
+ }
+
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/accept_sec_context.c b/source4/heimdal/lib/gssapi/accept_sec_context.c
new file mode 100644
index 0000000000..6672f3fc67
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/accept_sec_context.c
@@ -0,0 +1,1118 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: accept_sec_context.c,v 1.53 2005/05/29 15:12:41 lha Exp $");
+
+HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
+krb5_keytab gssapi_krb5_keytab;
+
+OM_uint32
+gsskrb5_register_acceptor_identity (const char *identity)
+{
+ krb5_error_code ret;
+
+ ret = gssapi_krb5_init();
+ if(ret)
+ return GSS_S_FAILURE;
+
+ HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
+
+ if(gssapi_krb5_keytab != NULL) {
+ krb5_kt_close(gssapi_krb5_context, gssapi_krb5_keytab);
+ gssapi_krb5_keytab = NULL;
+ }
+ if (identity == NULL) {
+ ret = krb5_kt_default(gssapi_krb5_context, &gssapi_krb5_keytab);
+ } else {
+ char *p;
+
+ asprintf(&p, "FILE:%s", identity);
+ if(p == NULL) {
+ HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
+ return GSS_S_FAILURE;
+ }
+ ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab);
+ free(p);
+ }
+ HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
+ if(ret)
+ return GSS_S_FAILURE;
+ return GSS_S_COMPLETE;
+}
+
+void
+gsskrb5_is_cfx(gss_ctx_id_t context_handle, int *is_cfx)
+{
+ krb5_keyblock *key;
+ int acceptor = (context_handle->more_flags & LOCAL) == 0;
+
+ if (acceptor) {
+ if (context_handle->auth_context->local_subkey)
+ key = context_handle->auth_context->local_subkey;
+ else
+ key = context_handle->auth_context->remote_subkey;
+ } else {
+ if (context_handle->auth_context->remote_subkey)
+ key = context_handle->auth_context->remote_subkey;
+ else
+ key = context_handle->auth_context->local_subkey;
+ }
+ if (key == NULL)
+ key = context_handle->auth_context->keyblock;
+
+ if (key == NULL)
+ return;
+
+ switch (key->keytype) {
+ case ETYPE_DES_CBC_CRC:
+ case ETYPE_DES_CBC_MD4:
+ case ETYPE_DES_CBC_MD5:
+ case ETYPE_DES3_CBC_MD5:
+ case ETYPE_DES3_CBC_SHA1:
+ case ETYPE_ARCFOUR_HMAC_MD5:
+ case ETYPE_ARCFOUR_HMAC_MD5_56:
+ break;
+ default :
+ *is_cfx = 1;
+ if ((acceptor && context_handle->auth_context->local_subkey) ||
+ (!acceptor && context_handle->auth_context->remote_subkey))
+ context_handle->more_flags |= ACCEPTOR_SUBKEY;
+ break;
+ }
+}
+
+
+static OM_uint32
+gsskrb5_accept_delegated_token
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ gss_cred_id_t * delegated_cred_handle)
+{
+ krb5_data *fwd_data = &(*context_handle)->fwd_data;
+ OM_uint32 *flags = &(*context_handle)->flags;
+ krb5_principal principal = (*context_handle)->source;
+ krb5_ccache ccache = NULL;
+ krb5_error_code kret;
+ int32_t ac_flags, ret;
+ gss_cred_id_t handle = NULL;
+
+ if (delegated_cred_handle == NULL) {
+ /* XXX Create a new delegated_cred_handle? */
+
+ ret = 0;
+
+ kret = krb5_cc_default (gssapi_krb5_context, &ccache);
+ if (kret) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ goto end_fwd;
+ }
+ } else {
+
+ *delegated_cred_handle = NULL;
+
+ handle = calloc(1, sizeof(*handle));
+ if (handle == NULL) {
+ ret = GSS_S_FAILURE;
+ *minor_status = ENOMEM;
+ krb5_set_error_string(gssapi_krb5_context, "out of memory");
+ gssapi_krb5_set_error_string();
+ *flags &= ~GSS_C_DELEG_FLAG;
+ goto end_fwd;
+ }
+ if ((ret = gss_duplicate_name(minor_status, principal,
+ &handle->principal)) != 0) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ ret = 0;
+ goto end_fwd;
+ }
+ kret = krb5_cc_gen_new (gssapi_krb5_context,
+ &krb5_mcc_ops,
+ &handle->ccache);
+ if (kret) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ ret = 0;
+ goto end_fwd;
+ }
+ ccache = handle->ccache;
+
+ ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
+ if (ret) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ goto end_fwd;
+ }
+ ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+ &handle->mechanisms);
+ if (ret) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ goto end_fwd;
+ }
+ }
+
+ kret = krb5_cc_initialize(gssapi_krb5_context, ccache, principal);
+ if (kret) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ ret = 0;
+ goto end_fwd;
+ }
+
+ krb5_auth_con_removeflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_DO_TIME,
+ &ac_flags);
+ kret = krb5_rd_cred2(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ ccache,
+ fwd_data);
+ if (kret)
+ gssapi_krb5_set_error_string();
+ krb5_auth_con_setflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ ac_flags);
+ if (kret) {
+ *flags &= ~GSS_C_DELEG_FLAG;
+ ret = GSS_S_FAILURE;
+ *minor_status = kret;
+ goto end_fwd;
+ }
+ end_fwd:
+ /* if there was some kind of failure, clean up internal structures */
+ if ((*flags & GSS_C_DELEG_FLAG) == 0) {
+ if (handle) {
+ if (handle->principal)
+ gss_release_name(minor_status, &handle->principal);
+ if (handle->mechanisms)
+ gss_release_oid_set(NULL, &handle->mechanisms);
+ if (handle->ccache)
+ krb5_cc_destroy(gssapi_krb5_context, handle->ccache);
+ free(handle);
+ handle = NULL;
+ }
+ }
+ if (delegated_cred_handle == NULL) {
+ if (ccache)
+ krb5_cc_close(gssapi_krb5_context, ccache);
+ }
+ if (handle)
+ *delegated_cred_handle = handle;
+
+ return ret;
+}
+
+static OM_uint32
+gsskrb5_acceptor_ready(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ gss_cred_id_t * delegated_cred_handle)
+{
+ OM_uint32 ret;
+ int32_t seq_number;
+ int is_cfx = 0;
+ u_int32_t flags = (*context_handle)->flags;
+
+ krb5_auth_getremoteseqnumber (gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &seq_number);
+
+ gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+ ret = _gssapi_msg_order_create(minor_status,
+ &(*context_handle)->order,
+ _gssapi_msg_order_f(flags),
+ seq_number, 0, is_cfx);
+ if (ret) return ret;
+
+ if (!(flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(flags)) {
+ krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ seq_number);
+ }
+
+ /*
+ * We should handle the delegation ticket, in case it's there
+ */
+ if ((*context_handle)->fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) {
+ ret = gsskrb5_accept_delegated_token(minor_status,
+ context_handle,
+ delegated_cred_handle);
+ if (ret) return ret;
+ }
+
+ (*context_handle)->state = ACCEPTOR_READY;
+ (*context_handle)->more_flags |= OPEN;
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gsskrb5_acceptor_start(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle)
+{
+ krb5_error_code kret;
+ OM_uint32 ret = GSS_S_COMPLETE;
+ krb5_data indata;
+ krb5_flags ap_options;
+ OM_uint32 flags;
+ krb5_ticket *ticket = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_keyblock *keyblock = NULL;
+ int no_wrap = 0;
+
+ /*
+ * TODO: check the channel_bindings
+ */
+
+ /*
+ * We need a sequence number
+ */
+ krb5_auth_con_addflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE,
+ NULL);
+
+ /*
+ * We need remove the decapsulate only when GSS_C_DCE_STYLE isn't in use
+ */
+ ret = gssapi_krb5_decapsulate(minor_status,
+ input_token,&indata,
+ "\x01\x00",
+ GSS_KRB5_MECHANISM);
+ if (ret) {
+ /* No OID wrapping apparently available. */
+ no_wrap = 1;
+ indata.length = input_token->length;
+ indata.data = input_token->value;
+ }
+
+ /*
+ * We need to get our keytab
+ */
+ if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
+ if (gssapi_krb5_keytab != NULL) {
+ keytab = gssapi_krb5_keytab;
+ }
+ } else {
+ keytab = acceptor_cred_handle->keytab;
+ }
+
+ /*
+ * We need to check the ticket and create the AP-REP packet
+ */
+ kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
+ &(*context_handle)->auth_context,
+ &indata,
+ (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
+ keytab,
+ &ap_options,
+ &ticket,
+ &keyblock);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ /*
+ * We need to remember some data on the context_handle
+ */
+ (*context_handle)->ticket = ticket;
+ (*context_handle)->service_keyblock = keyblock;
+ (*context_handle)->lifetime = ticket->ticket.endtime;
+
+ /*
+ * We need to copy the principal names to the context and the calling layer
+ */
+ kret = krb5_copy_principal(gssapi_krb5_context,
+ ticket->client,
+ &(*context_handle)->source);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_copy_principal(gssapi_krb5_context,
+ ticket->server,
+ &(*context_handle)->target);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ /*
+ * We need to setup some compat stuff, this assumes that context_handle->target is already set
+ */
+ ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
+ if (ret) return ret;
+
+ /*
+ * We need to get the flags out of the 8003 checksum
+ */
+ {
+ krb5_authenticator authenticator;
+
+ kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &authenticator);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ ret = gssapi_krb5_verify_8003_checksum(minor_status,
+ input_chan_bindings,
+ authenticator->cksum,
+ &flags,
+ &(*context_handle)->fwd_data);
+ krb5_free_authenticator(gssapi_krb5_context, &authenticator);
+ if (ret) return ret;
+ }
+
+ /* And remember them for later */
+ (*context_handle)->flags = flags;
+
+ if(flags & GSS_C_MUTUAL_FLAG) {
+ int is_cfx = 0;
+ krb5_data outbuf;
+
+ gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+ if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
+ kret = krb5_auth_con_addflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_USE_SUBKEY,
+ NULL);
+ (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
+ }
+
+ kret = krb5_mk_rep(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &outbuf);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ if (!(flags & GSS_C_DCE_STYLE)) {
+ ret = gssapi_krb5_encapsulate(minor_status,
+ &outbuf,
+ output_token,
+ "\x02\x00",
+ GSS_KRB5_MECHANISM);
+ krb5_data_free (&outbuf);
+ if (ret) return ret;
+ } else {
+ output_token->length = outbuf.length;
+ output_token->value = outbuf.data;
+ }
+ }
+
+ /*
+ * We need to set the return value for the calling layer
+ */
+ if (ret_flags) *ret_flags = flags;
+
+ if (time_rec) {
+ ret = gssapi_lifetime_left(minor_status,
+ (*context_handle)->lifetime,
+ time_rec);
+ if (ret) return ret;
+ }
+
+ if (src_name) {
+ kret = krb5_copy_principal(gssapi_krb5_context,
+ (*context_handle)->source,
+ src_name);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /*
+ * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
+ */
+ if (flags & GSS_C_DCE_STYLE) {
+ (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
+ return GSS_S_CONTINUE_NEEDED;
+ }
+
+ return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+}
+
+static OM_uint32
+gsskrb5_acceptor_wait_for_dcestyle(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle)
+{
+ OM_uint32 ret;
+ krb5_error_code kret;
+ krb5_data inbuf;
+ OM_uint32 r_seq_number;
+ OM_uint32 l_seq_number;
+
+ /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */
+ inbuf.length = input_token->length;
+ inbuf.data = input_token->value;
+
+ /*
+ * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number,
+ * and then reset the remote seq_number to the old value
+ */
+ {
+ kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &l_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &r_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ l_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /* We need to verify the AP_REP, but we need to flag that this
+ is DCE_STYLE, so don't check the timestamps this time
+ */
+ {
+ krb5_ap_rep_enc_part *repl;
+
+ kret = _krb5_rd_rep_type(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &inbuf,
+ &repl,
+ TRUE);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
+ }
+
+ /* We need to check the liftime */
+ {
+ OM_uint32 lifetime_rec;
+
+ ret = gssapi_lifetime_left(minor_status,
+ (*context_handle)->lifetime,
+ &lifetime_rec);
+ if (ret) return ret;
+
+ if (lifetime_rec == 0) {
+ return GSS_S_CONTEXT_EXPIRED;
+ }
+
+ if (time_rec) *time_rec = lifetime_rec;
+ }
+
+ /* We need to give the caller the flags which are in use */
+ if (ret_flags) *ret_flags = (*context_handle)->flags;
+
+ if (src_name) {
+ kret = krb5_copy_principal(gssapi_krb5_context,
+ (*context_handle)->source,
+ src_name);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /*
+ * After the krb5_rd_rep() the remote and local seq_number should be the same,
+ * because the client just replies the seq_number from our AP-REP in its AP-REP,
+ * but then the client uses the seq_number from its AP-REQ for GSS_wrap()
+ */
+ {
+ OM_uint32 tmp_r_seq_number;
+ OM_uint32 l_seq_number;
+
+ kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &tmp_r_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &l_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ /*
+ * Here we check if the client has responsed with our local seq_number,
+ */
+ if (tmp_r_seq_number != l_seq_number) {
+ return GSS_S_UNSEQ_TOKEN;
+ }
+ }
+
+ /*
+ * We need to reset the remote seq_number, because the client will use,
+ * the old one for the GSS_wrap() calls
+ */
+ {
+ kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ r_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+}
+
+static OM_uint32
+gsskrb5_accept_sec_context(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle)
+{
+ OM_uint32 ret;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ ret = _gsskrb5_create_ctx(minor_status,
+ context_handle,
+ input_chan_bindings,
+ ACCEPTOR_START);
+ if (ret) return ret;
+ }
+
+ if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM;
+
+ HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+
+ switch ((*context_handle)->state) {
+ case ACCEPTOR_START:
+ ret = gsskrb5_acceptor_start(minor_status,
+ context_handle,
+ acceptor_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ break;
+ case ACCEPTOR_WAIT_FOR_DCESTYLE:
+ ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
+ context_handle,
+ acceptor_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ break;
+ case ACCEPTOR_READY:
+ /* this function should not be called after it has returned GSS_S_COMPLETE */
+ ret = GSS_S_BAD_STATUS;
+ break;
+ default:
+ /* TODO: is this correct here? --metze */
+ ret = GSS_S_BAD_STATUS;
+ break;
+ }
+
+ HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
+
+ return ret;
+}
+
+static OM_uint32
+code_NegTokenArg(OM_uint32 *minor_status,
+ const NegTokenTarg *targ,
+ krb5_data *data,
+ u_char **ret_buf)
+{
+ OM_uint32 ret;
+ u_char *buf;
+ size_t buf_size, buf_len;
+
+ buf_size = 1024;
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ do {
+ ret = encode_NegTokenTarg(buf + buf_size - 1,
+ buf_size,
+ targ, &buf_len);
+ if (ret == 0) {
+ size_t tmp;
+
+ ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
+ buf_size - buf_len,
+ buf_len,
+ ASN1_C_CONTEXT,
+ CONS,
+ 1,
+ &tmp);
+ if (ret == 0)
+ buf_len += tmp;
+ }
+ if (ret) {
+ if (ret == ASN1_OVERFLOW) {
+ u_char *tmp;
+
+ buf_size *= 2;
+ tmp = realloc (buf, buf_size);
+ if (tmp == NULL) {
+ *minor_status = ENOMEM;
+ free(buf);
+ return GSS_S_FAILURE;
+ }
+ buf = tmp;
+ } else {
+ *minor_status = ret;
+ free(buf);
+ return GSS_S_FAILURE;
+ }
+ }
+ } while (ret == ASN1_OVERFLOW);
+
+ data->data = buf + buf_size - buf_len;
+ data->length = buf_len;
+ *ret_buf = buf;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+send_reject (OM_uint32 *minor_status,
+ gss_buffer_t output_token)
+{
+ NegTokenTarg targ;
+ krb5_data data;
+ u_char *buf;
+ OM_uint32 ret;
+
+ ALLOC(targ.negResult, 1);
+ if (targ.negResult == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ *(targ.negResult) = reject;
+ targ.supportedMech = NULL;
+ targ.responseToken = NULL;
+ targ.mechListMIC = NULL;
+
+ ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
+ free_NegTokenTarg(&targ);
+ if (ret)
+ return ret;
+
+#if 0
+ ret = _gssapi_encapsulate(minor_status,
+ &data,
+ output_token,
+ GSS_SPNEGO_MECHANISM);
+#else
+ output_token->value = malloc(data.length);
+ if (output_token->value == NULL) {
+ *minor_status = ENOMEM;
+ ret = GSS_S_FAILURE;
+ } else {
+ output_token->length = data.length;
+ memcpy(output_token->value, data.data, output_token->length);
+ }
+#endif
+ free(buf);
+ if (ret)
+ return ret;
+ return GSS_S_BAD_MECH;
+}
+
+static OM_uint32
+send_accept (OM_uint32 *minor_status,
+ OM_uint32 major_status,
+ gss_buffer_t output_token,
+ gss_buffer_t mech_token,
+ gss_ctx_id_t context_handle,
+ const MechTypeList *mechtypelist)
+{
+ NegTokenTarg targ;
+ krb5_data data;
+ u_char *buf;
+ OM_uint32 ret;
+ gss_buffer_desc mech_buf, mech_mic_buf;
+ krb5_boolean require_mic;
+
+ memset(&targ, 0, sizeof(targ));
+ ALLOC(targ.negResult, 1);
+ if (targ.negResult == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ *(targ.negResult) = accept_completed;
+
+ ALLOC(targ.supportedMech, 1);
+ if (targ.supportedMech == NULL) {
+ free_NegTokenTarg(&targ);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
+ GSS_KRB5_MECHANISM->length,
+ targ.supportedMech,
+ NULL);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ if (mech_token != NULL && mech_token->length != 0) {
+ ALLOC(targ.responseToken, 1);
+ if (targ.responseToken == NULL) {
+ free_NegTokenTarg(&targ);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ targ.responseToken->length = mech_token->length;
+ targ.responseToken->data = mech_token->value;
+ mech_token->length = 0;
+ mech_token->value = NULL;
+ } else {
+ targ.responseToken = NULL;
+ }
+
+ ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle,
+ &require_mic);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ return ret;
+ }
+
+ if (major_status == GSS_S_COMPLETE && require_mic) {
+ size_t buf_len;
+
+ ALLOC(targ.mechListMIC, 1);
+ if (targ.mechListMIC == NULL) {
+ free_NegTokenTarg(&targ);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
+ mechtypelist, &buf_len, ret);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ return ret;
+ }
+ if (mech_buf.length != buf_len)
+ abort();
+
+ ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf,
+ &mech_mic_buf);
+ free (mech_buf.value);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ return ret;
+ }
+
+ targ.mechListMIC->length = mech_mic_buf.length;
+ targ.mechListMIC->data = mech_mic_buf.value;
+ } else
+ targ.mechListMIC = NULL;
+
+ ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
+ free_NegTokenTarg(&targ);
+ if (ret)
+ return ret;
+
+#if 0
+ ret = _gssapi_encapsulate(minor_status,
+ &data,
+ output_token,
+ GSS_SPNEGO_MECHANISM);
+#else
+ output_token->value = malloc(data.length);
+ if (output_token->value == NULL) {
+ *minor_status = ENOMEM;
+ ret = GSS_S_FAILURE;
+ } else {
+ output_token->length = data.length;
+ memcpy(output_token->value, data.data, output_token->length);
+ }
+#endif
+ free(buf);
+ if (ret)
+ return ret;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+spnego_accept_sec_context
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token_buffer,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle
+ )
+{
+ OM_uint32 ret, ret2;
+ NegTokenInit ni;
+ size_t ni_len;
+ int i;
+ int found = 0;
+ krb5_data data;
+ size_t len, taglen;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ ret = _gssapi_decapsulate (minor_status,
+ input_token_buffer,
+ &data,
+ GSS_SPNEGO_MECHANISM);
+ if (ret)
+ return ret;
+
+ ret = der_match_tag_and_length(data.data, data.length,
+ ASN1_C_CONTEXT, CONS, 0, &len, &taglen);
+ if (ret)
+ return ret;
+
+ if(len > data.length - taglen)
+ return ASN1_OVERRUN;
+
+ ret = decode_NegTokenInit((const char *)data.data + taglen, len,
+ &ni, &ni_len);
+ if (ret)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (ni.mechTypes == NULL) {
+ free_NegTokenInit(&ni);
+ return send_reject (minor_status, output_token);
+ }
+
+ for (i = 0; !found && i < ni.mechTypes->len; ++i) {
+ char mechbuf[17];
+ size_t mech_len;
+
+ ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
+ sizeof(mechbuf),
+ &ni.mechTypes->val[i],
+ &mech_len);
+ if (ret) {
+ free_NegTokenInit(&ni);
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (mech_len == GSS_KRB5_MECHANISM->length
+ && memcmp(GSS_KRB5_MECHANISM->elements,
+ mechbuf + sizeof(mechbuf) - mech_len,
+ mech_len) == 0)
+ found = 1;
+ }
+ if (found) {
+ gss_buffer_desc ibuf, obuf;
+ gss_buffer_t ot = NULL;
+ OM_uint32 minor;
+
+ if (ni.mechToken != NULL) {
+ ibuf.length = ni.mechToken->length;
+ ibuf.value = ni.mechToken->data;
+
+ ret = gsskrb5_accept_sec_context(&minor,
+ context_handle,
+ acceptor_cred_handle,
+ &ibuf,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ &obuf,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+ ot = &obuf;
+ } else {
+ free_NegTokenInit(&ni);
+ send_reject (minor_status, output_token);
+ return ret;
+ }
+ }
+ ret2 = send_accept (minor_status, ret, output_token, ot,
+ *context_handle, ni.mechTypes);
+ if (ret2 != GSS_S_COMPLETE)
+ ret = ret2;
+ if (ot != NULL)
+ gss_release_buffer(&minor, ot);
+ free_NegTokenInit(&ni);
+ return ret;
+ } else {
+ free_NegTokenInit(&ni);
+ return send_reject (minor_status, output_token);
+ }
+}
+
+OM_uint32
+gss_accept_sec_context(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle)
+{
+ ssize_t mech_len;
+ const u_char *p;
+
+ GSSAPI_KRB5_INIT ();
+
+ *minor_status = 0;
+
+ if (src_name) *src_name = GSS_C_NO_NAME;
+ if (actual_mech_type) *actual_mech_type = GSS_C_NO_OID;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (ret_flags) *ret_flags = 0;
+ if (time_rec) *time_rec = 0;
+ if (delegated_cred_handle) *delegated_cred_handle = NULL;
+
+ mech_len = gssapi_krb5_get_mech(input_token->value,
+ input_token->length,
+ &p);
+
+ /* This could be 'dce style' kerberos, where the OID is missing :-( */
+ if ((mech_len < 0) || (mech_len == GSS_KRB5_MECHANISM->length
+ && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)) {
+ return gsskrb5_accept_sec_context(minor_status,
+ context_handle,
+ acceptor_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ } else if (mech_len == GSS_SPNEGO_MECHANISM->length
+ && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0) {
+ return spnego_accept_sec_context(minor_status,
+ context_handle,
+ acceptor_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ }
+
+ return GSS_S_BAD_MECH;
+}
diff --git a/source4/heimdal/lib/gssapi/acquire_cred.c b/source4/heimdal/lib/gssapi/acquire_cred.c
new file mode 100644
index 0000000000..6ded413626
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/acquire_cred.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: acquire_cred.c,v 1.22 2005/01/05 02:32:26 lukeh Exp $");
+
+static krb5_error_code
+get_keytab(krb5_context context, krb5_keytab *keytab)
+{
+ char kt_name[256];
+ krb5_error_code kret;
+
+ HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
+
+ if (gssapi_krb5_keytab != NULL) {
+ kret = krb5_kt_get_name(context,
+ gssapi_krb5_keytab,
+ kt_name, sizeof(kt_name));
+ if (kret == 0)
+ kret = krb5_kt_resolve(context, kt_name, keytab);
+ } else
+ kret = krb5_kt_default(context, keytab);
+
+ HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
+
+ return (kret);
+}
+
+static OM_uint32 acquire_initiator_cred
+ (OM_uint32 * minor_status,
+ krb5_context context,
+ krb5_keytab keytab,
+ krb5_ccache ccache,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t handle,
+ gss_OID_set * actual_mechs,
+ OM_uint32 * time_rec
+ )
+{
+ OM_uint32 ret;
+ krb5_creds cred;
+ krb5_principal def_princ;
+ krb5_get_init_creds_opt *opt;
+ krb5_error_code kret;
+ krb5_boolean made_ccache = FALSE;
+ krb5_boolean made_keytab = FALSE;
+
+ def_princ = NULL;
+ ret = GSS_S_FAILURE;
+ memset(&cred, 0, sizeof(cred));
+
+ if (ccache == NULL) {
+ kret = krb5_cc_default(context, &ccache);
+ if (kret)
+ goto end;
+ made_ccache = TRUE;
+ }
+ kret = krb5_cc_get_principal(context, ccache,
+ &def_princ);
+ if (kret != 0) {
+ /* we'll try to use a keytab below */
+ krb5_cc_destroy(context, ccache);
+ made_ccache = FALSE;
+ ccache = NULL;
+ kret = 0;
+ } else if (handle->principal == NULL) {
+ kret = krb5_copy_principal(context, def_princ,
+ &handle->principal);
+ if (kret)
+ goto end;
+ } else if (handle->principal != NULL &&
+ krb5_principal_compare(context, handle->principal,
+ def_princ) == FALSE) {
+ /* Before failing, lets check the keytab */
+ krb5_free_principal(context, def_princ);
+ def_princ = NULL;
+ }
+ if (def_princ == NULL) {
+ /* We have no existing credentials cache,
+ * so attempt to get a TGT using a keytab.
+ */
+ if (handle->principal == NULL) {
+ kret = krb5_get_default_principal(context,
+ &handle->principal);
+ if (kret)
+ goto end;
+ }
+ if (keytab != NULL) {
+ kret = get_keytab(context, &keytab);
+ if (kret)
+ goto end;
+ made_keytab = TRUE;
+ }
+ kret = krb5_get_init_creds_opt_alloc(context, &opt);
+ if (kret)
+ goto end;
+ kret = krb5_get_init_creds_keytab(context, &cred,
+ handle->principal, keytab, 0, NULL, opt);
+ krb5_get_init_creds_opt_free(opt);
+ if (kret)
+ goto end;
+ if (ccache == NULL) {
+ kret = krb5_cc_gen_new(context, &krb5_mcc_ops,
+ &ccache);
+ if (kret)
+ goto end;
+ made_ccache = TRUE;
+ }
+ kret = krb5_cc_initialize(context, ccache, cred.client);
+ if (kret)
+ goto end;
+ kret = krb5_cc_store_cred(context, ccache, &cred);
+ if (kret)
+ goto end;
+ handle->lifetime = cred.times.endtime;
+ } else {
+ krb5_creds in_cred, *out_cred;
+ krb5_const_realm realm;
+
+ memset(&in_cred, 0, sizeof(in_cred));
+ in_cred.client = handle->principal;
+
+ realm = krb5_principal_get_realm(context,
+ handle->principal);
+ if (realm == NULL) {
+ kret = KRB5_PRINC_NOMATCH; /* XXX */
+ goto end;
+ }
+
+ kret = krb5_make_principal(context, &in_cred.server,
+ realm, KRB5_TGS_NAME, realm, NULL);
+ if (kret)
+ goto end;
+
+ kret = krb5_get_credentials(context, 0,
+ ccache, &in_cred, &out_cred);
+ krb5_free_principal(context, in_cred.server);
+ if (kret)
+ goto end;
+
+ handle->lifetime = out_cred->times.endtime;
+ krb5_free_creds(context, out_cred);
+ }
+
+ handle->ccache = ccache;
+ handle->made_ccache = made_ccache;
+ ret = GSS_S_COMPLETE;
+
+end:
+ if (cred.client != NULL)
+ krb5_free_cred_contents(context, &cred);
+ if (def_princ != NULL)
+ krb5_free_principal(context, def_princ);
+ if (made_keytab)
+ krb5_kt_close(context, keytab);
+ if (ret != GSS_S_COMPLETE) {
+ if (made_ccache)
+ krb5_cc_close(context, ccache);
+ if (kret != 0) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ }
+ }
+ return (ret);
+}
+
+static OM_uint32 acquire_acceptor_cred
+ (OM_uint32 * minor_status,
+ krb5_context context,
+ krb5_keytab keytab,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t handle,
+ gss_OID_set * actual_mechs,
+ OM_uint32 * time_rec
+ )
+{
+ OM_uint32 ret;
+ krb5_error_code kret;
+
+ kret = 0;
+ ret = GSS_S_FAILURE;
+ if (keytab == NULL) {
+ kret = get_keytab(context, &handle->keytab);
+ if (kret)
+ goto end;
+ handle->made_keytab = TRUE;
+ } else {
+ handle->keytab = keytab;
+ handle->made_keytab = FALSE;
+ }
+ ret = GSS_S_COMPLETE;
+
+end:
+ if (ret != GSS_S_COMPLETE) {
+ if (handle->made_keytab)
+ krb5_kt_close(context, handle->keytab);
+ if (kret != 0) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ }
+ }
+ return (ret);
+}
+
+OM_uint32 gsskrb5_acquire_cred
+ (OM_uint32 * minor_status,
+ struct krb5_keytab_data *keytab,
+ struct krb5_ccache_data *ccache,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t * output_cred_handle,
+ gss_OID_set * actual_mechs,
+ OM_uint32 * time_rec
+ )
+{
+ gss_cred_id_t handle;
+ OM_uint32 ret;
+
+ if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
+ *minor_status = GSS_KRB5_S_G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ GSSAPI_KRB5_INIT ();
+
+ *output_cred_handle = NULL;
+ if (time_rec)
+ *time_rec = 0;
+ if (actual_mechs)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (desired_mechs) {
+ int present = 0;
+
+ ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+ desired_mechs, &present);
+ if (ret)
+ return ret;
+ if (!present) {
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
+ }
+ }
+
+ handle = (gss_cred_id_t)malloc(sizeof(*handle));
+ if (handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+
+ memset(handle, 0, sizeof (*handle));
+ HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
+
+ if (desired_name != GSS_C_NO_NAME) {
+ ret = gss_duplicate_name(minor_status, desired_name,
+ &handle->principal);
+ if (ret != GSS_S_COMPLETE) {
+ HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+ free(handle);
+ return (ret);
+ }
+ }
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
+ ret = acquire_initiator_cred(minor_status, gssapi_krb5_context,
+ keytab, ccache,
+ desired_name, time_req,
+ desired_mechs, cred_usage,
+ handle, actual_mechs, time_rec);
+ if (ret != GSS_S_COMPLETE) {
+ HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+ krb5_free_principal(gssapi_krb5_context, handle->principal);
+ free(handle);
+ return (ret);
+ }
+ }
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
+ ret = acquire_acceptor_cred(minor_status, gssapi_krb5_context,
+ keytab, time_req,
+ desired_mechs, cred_usage,
+ handle, actual_mechs, time_rec);
+ if (ret != GSS_S_COMPLETE) {
+ HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+ krb5_free_principal(gssapi_krb5_context, handle->principal);
+ free(handle);
+ return (ret);
+ }
+ }
+ ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
+ if (ret == GSS_S_COMPLETE)
+ ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+ &handle->mechanisms);
+ if (ret == GSS_S_COMPLETE)
+ ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL,
+ actual_mechs);
+ if (ret != GSS_S_COMPLETE) {
+ if (handle->mechanisms != NULL)
+ gss_release_oid_set(NULL, &handle->mechanisms);
+ HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+ krb5_free_principal(gssapi_krb5_context, handle->principal);
+ free(handle);
+ return (ret);
+ }
+ *minor_status = 0;
+ if (time_rec) {
+ ret = gssapi_lifetime_left(minor_status,
+ handle->lifetime,
+ time_rec);
+
+ if (ret)
+ return ret;
+ }
+ handle->usage = cred_usage;
+
+ *output_cred_handle = handle;
+ return (GSS_S_COMPLETE);
+}
+
+OM_uint32 gss_acquire_cred
+ (OM_uint32 * minor_status,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t * output_cred_handle,
+ gss_OID_set * actual_mechs,
+ OM_uint32 * time_rec
+ )
+{
+ return gsskrb5_acquire_cred(minor_status,
+ NULL, NULL,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+}
diff --git a/source4/heimdal/lib/gssapi/add_oid_set_member.c b/source4/heimdal/lib/gssapi/add_oid_set_member.c
new file mode 100644
index 0000000000..ed654fc8c5
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/add_oid_set_member.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: add_oid_set_member.c,v 1.8 2003/03/16 17:50:49 lha Exp $");
+
+OM_uint32 gss_add_oid_set_member (
+ OM_uint32 * minor_status,
+ const gss_OID member_oid,
+ gss_OID_set * oid_set
+ )
+{
+ gss_OID tmp;
+ size_t n;
+ OM_uint32 res;
+ int present;
+
+ res = gss_test_oid_set_member(minor_status, member_oid, *oid_set, &present);
+ if (res != GSS_S_COMPLETE)
+ return res;
+
+ if (present) {
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ n = (*oid_set)->count + 1;
+ tmp = realloc ((*oid_set)->elements, n * sizeof(gss_OID_desc));
+ if (tmp == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ (*oid_set)->elements = tmp;
+ (*oid_set)->count = n;
+ (*oid_set)->elements[n-1] = *member_oid;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/address_to_krb5addr.c b/source4/heimdal/lib/gssapi/address_to_krb5addr.c
new file mode 100644
index 0000000000..13a6825f55
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/address_to_krb5addr.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+#include <roken.h>
+
+krb5_error_code
+gss_address_to_krb5addr(OM_uint32 gss_addr_type,
+ gss_buffer_desc *gss_addr,
+ int16_t port,
+ krb5_address *address)
+{
+ int addr_type;
+ struct sockaddr sa;
+ krb5_socklen_t sa_size = sizeof(sa);
+ krb5_error_code problem;
+
+ if (gss_addr == NULL)
+ return GSS_S_FAILURE;
+
+ switch (gss_addr_type) {
+#ifdef HAVE_IPV6
+ case GSS_C_AF_INET6: addr_type = AF_INET6;
+ break;
+#endif /* HAVE_IPV6 */
+
+ case GSS_C_AF_INET: addr_type = AF_INET;
+ break;
+ default:
+ return GSS_S_FAILURE;
+ }
+
+ problem = krb5_h_addr2sockaddr (gssapi_krb5_context,
+ addr_type,
+ gss_addr->value,
+ &sa,
+ &sa_size,
+ port);
+ if (problem)
+ return GSS_S_FAILURE;
+
+ problem = krb5_sockaddr2address (gssapi_krb5_context, &sa, address);
+
+ return problem;
+}
diff --git a/source4/heimdal/lib/gssapi/arcfour.c b/source4/heimdal/lib/gssapi/arcfour.c
new file mode 100644
index 0000000000..5edcee08ec
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/arcfour.c
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 2003 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: arcfour.c,v 1.17 2005/05/06 07:13:32 lha Exp $");
+
+/*
+ * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
+ *
+ * The arcfour message have the following formats:
+ *
+ * MIC token
+ * TOK_ID[2] = 01 01
+ * SGN_ALG[2] = 11 00
+ * Filler[4]
+ * SND_SEQ[8]
+ * SGN_CKSUM[8]
+ *
+ * WRAP token
+ * TOK_ID[2] = 02 01
+ * SGN_ALG[2];
+ * SEAL_ALG[2]
+ * Filler[2]
+ * SND_SEQ[2]
+ * SGN_CKSUM[8]
+ * Confounder[8]
+ */
+
+
+static krb5_error_code
+arcfour_mic_key(krb5_context context, krb5_keyblock *key,
+ void *cksum_data, size_t cksum_size,
+ void *key6_data, size_t key6_size)
+{
+ krb5_error_code ret;
+
+ Checksum cksum_k5;
+ krb5_keyblock key5;
+ char k5_data[16];
+
+ Checksum cksum_k6;
+
+ char T[4];
+
+ memset(T, 0, 4);
+ cksum_k5.checksum.data = k5_data;
+ cksum_k5.checksum.length = sizeof(k5_data);
+
+ if (key->keytype == KEYTYPE_ARCFOUR_56) {
+ char L40[14] = "fortybits";
+
+ memcpy(L40 + 10, T, sizeof(T));
+ ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
+ L40, 14, 0, key, &cksum_k5);
+ memset(&k5_data[7], 0xAB, 9);
+ } else {
+ ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
+ T, 4, 0, key, &cksum_k5);
+ }
+ if (ret)
+ return ret;
+
+ key5.keytype = KEYTYPE_ARCFOUR;
+ key5.keyvalue = cksum_k5.checksum;
+
+ cksum_k6.checksum.data = key6_data;
+ cksum_k6.checksum.length = key6_size;
+
+ return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
+ cksum_data, cksum_size, 0, &key5, &cksum_k6);
+}
+
+
+static krb5_error_code
+arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
+ u_char *sgn_cksum, size_t sgn_cksum_sz,
+ const char *v1, size_t l1,
+ const void *v2, size_t l2,
+ const void *v3, size_t l3)
+{
+ Checksum CKSUM;
+ u_char *ptr;
+ size_t len;
+ krb5_crypto crypto;
+ krb5_error_code ret;
+
+ assert(sgn_cksum_sz == 8);
+
+ len = l1 + l2 + l3;
+
+ ptr = malloc(len);
+ if (ptr == NULL)
+ return ENOMEM;
+
+ memcpy(ptr, v1, l1);
+ memcpy(ptr + l1, v2, l2);
+ memcpy(ptr + l1 + l2, v3, l3);
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret) {
+ free(ptr);
+ return ret;
+ }
+
+ ret = krb5_create_checksum(gssapi_krb5_context,
+ crypto,
+ usage,
+ 0,
+ ptr, len,
+ &CKSUM);
+ free(ptr);
+ if (ret == 0) {
+ memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
+ free_Checksum(&CKSUM);
+ }
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+ return ret;
+}
+
+
+OM_uint32
+_gssapi_get_mic_arcfour(OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ int32_t seq_number;
+ size_t len, total_len;
+ u_char k6_data[16], *p0, *p;
+ RC4_KEY rc4_key;
+
+ gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ message_token->length = total_len;
+ message_token->value = malloc (total_len);
+ if (message_token->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p0 = _gssapi_make_mech_header(message_token->value,
+ len,
+ GSS_KRB5_MECHANISM);
+ p = p0;
+
+ *p++ = 0x01; /* TOK_ID */
+ *p++ = 0x01;
+ *p++ = 0x11; /* SGN_ALG */
+ *p++ = 0x00;
+ *p++ = 0xff; /* Filler */
+ *p++ = 0xff;
+ *p++ = 0xff;
+ *p++ = 0xff;
+
+ p = NULL;
+
+ ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
+ p0 + 16, 8, /* SGN_CKSUM */
+ p0, 8, /* TOK_ID, SGN_ALG, Filer */
+ message_buffer->value, message_buffer->length,
+ NULL, 0);
+ if (ret) {
+ gss_release_buffer(minor_status, message_token);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = arcfour_mic_key(gssapi_krb5_context, key,
+ p0 + 16, 8, /* SGN_CKSUM */
+ k6_data, sizeof(k6_data));
+ if (ret) {
+ gss_release_buffer(minor_status, message_token);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+ p = p0 + 8; /* SND_SEQ */
+ gssapi_encode_be_om_uint32(seq_number, p);
+
+ krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
+
+ RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+ RC4 (&rc4_key, 8, p, p);
+
+ memset(&rc4_key, 0, sizeof(rc4_key));
+ memset(k6_data, 0, sizeof(k6_data));
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+
+OM_uint32
+_gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t * qop_state,
+ krb5_keyblock *key,
+ char *type)
+{
+ krb5_error_code ret;
+ int32_t seq_number;
+ OM_uint32 omret;
+ char cksum_data[8], k6_data[16], SND_SEQ[8];
+ u_char *p;
+ int cmp;
+
+ if (qop_state)
+ *qop_state = 0;
+
+ p = token_buffer->value;
+ omret = gssapi_krb5_verify_header (&p,
+ token_buffer->length,
+ type,
+ GSS_KRB5_MECHANISM);
+ if (omret)
+ return omret;
+
+ if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
+ return GSS_S_BAD_MIC;
+ p += 4;
+
+ ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
+ cksum_data, sizeof(cksum_data),
+ p - 8, 8,
+ message_buffer->value, message_buffer->length,
+ NULL, 0);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = arcfour_mic_key(gssapi_krb5_context, key,
+ cksum_data, sizeof(cksum_data),
+ k6_data, sizeof(k6_data));
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ cmp = memcmp(cksum_data, p + 8, 8);
+ if (cmp) {
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ {
+ RC4_KEY rc4_key;
+
+ RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+ RC4 (&rc4_key, 8, p, SND_SEQ);
+
+ memset(&rc4_key, 0, sizeof(rc4_key));
+ memset(k6_data, 0, sizeof(k6_data));
+ }
+
+ gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
+
+ if (context_handle->more_flags & LOCAL)
+ cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+ else
+ cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+
+ memset(SND_SEQ, 0, sizeof(SND_SEQ));
+ if (cmp != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ omret = _gssapi_msg_order_check(context_handle->order, seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ if (omret)
+ return omret;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_gssapi_wrap_arcfour(OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int * conf_state,
+ gss_buffer_t output_message_buffer,
+ krb5_keyblock *key)
+{
+ u_char Klocaldata[16], k6_data[16], *p, *p0;
+ size_t len, total_len, datalen;
+ krb5_keyblock Klocal;
+ krb5_error_code ret;
+ int32_t seq_number;
+
+ if (conf_state)
+ *conf_state = 0;
+
+ datalen = input_message_buffer->length;
+ len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ /* if GSS_C_DCE_STYLE is in use:
+ * - we only need to encapsulate the WRAP token
+ * - we should not add padding
+ */
+ if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+ datalen += 1 /* padding */;
+ len += datalen;
+ }
+ _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+ if (context_handle->flags & GSS_C_DCE_STYLE) {
+ total_len += datalen;
+ }
+
+ output_message_buffer->length = total_len;
+ output_message_buffer->value = malloc (total_len);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p0 = _gssapi_make_mech_header(output_message_buffer->value,
+ len,
+ GSS_KRB5_MECHANISM);
+ p = p0;
+
+ *p++ = 0x02; /* TOK_ID */
+ *p++ = 0x01;
+ *p++ = 0x11; /* SGN_ALG */
+ *p++ = 0x00;
+ if (conf_req_flag) {
+ *p++ = 0x10; /* SEAL_ALG */
+ *p++ = 0x00;
+ } else {
+ *p++ = 0xff; /* SEAL_ALG */
+ *p++ = 0xff;
+ }
+ *p++ = 0xff; /* Filler */
+ *p++ = 0xff;
+
+ p = NULL;
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+
+ gssapi_encode_be_om_uint32(seq_number, p0 + 8);
+
+ krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ memset (p0 + 8 + 4,
+ (context_handle->more_flags & LOCAL) ? 0 : 0xff,
+ 4);
+
+ krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
+
+ /* p points to data */
+ p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ memcpy(p, input_message_buffer->value, input_message_buffer->length);
+ /* only add padding when GSS_C_DCE_STYLE is not in use */
+ if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+ p[input_message_buffer->length] = 1; /* PADDING */
+ }
+
+ ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
+ p0 + 16, 8, /* SGN_CKSUM */
+ p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
+ p0 + 24, 8, /* Confounder */
+ p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+ datalen);
+ if (ret) {
+ *minor_status = ret;
+ gss_release_buffer(minor_status, output_message_buffer);
+ return GSS_S_FAILURE;
+ }
+
+ {
+ int i;
+
+ Klocal.keytype = key->keytype;
+ Klocal.keyvalue.data = Klocaldata;
+ Klocal.keyvalue.length = sizeof(Klocaldata);
+
+ for (i = 0; i < 16; i++)
+ Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+ }
+ ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
+ p0 + 8, 4, /* SND_SEQ */
+ k6_data, sizeof(k6_data));
+ memset(Klocaldata, 0, sizeof(Klocaldata));
+ if (ret) {
+ gss_release_buffer(minor_status, output_message_buffer);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+
+ if(conf_req_flag) {
+ RC4_KEY rc4_key;
+
+ RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+ /* XXX ? */
+ RC4 (&rc4_key, 8 + datalen, p0 + 24, p0 + 24); /* Confounder + data */
+ memset(&rc4_key, 0, sizeof(rc4_key));
+ }
+ memset(k6_data, 0, sizeof(k6_data));
+
+ ret = arcfour_mic_key(gssapi_krb5_context, key,
+ p0 + 16, 8, /* SGN_CKSUM */
+ k6_data, sizeof(k6_data));
+ if (ret) {
+ gss_release_buffer(minor_status, output_message_buffer);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ {
+ RC4_KEY rc4_key;
+
+ RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+ RC4 (&rc4_key, 8, p0 + 8, p0 + 8); /* SND_SEQ */
+ memset(&rc4_key, 0, sizeof(rc4_key));
+ memset(k6_data, 0, sizeof(k6_data));
+ }
+
+ if (conf_state)
+ *conf_state = conf_req_flag;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key)
+{
+ u_char Klocaldata[16];
+ krb5_keyblock Klocal;
+ krb5_error_code ret;
+ int32_t seq_number;
+ size_t len, datalen;
+ OM_uint32 omret;
+ char k6_data[16], SND_SEQ[8], Confounder[8];
+ char cksum_data[8];
+ u_char *p, *p0;
+ int cmp;
+ int conf_flag;
+ size_t padlen = 0;
+
+ if (conf_state)
+ *conf_state = 0;
+ if (qop_state)
+ *qop_state = 0;
+
+ p0 = input_message_buffer->value;
+ len = input_message_buffer->length;
+ /* if we have GSS_C_DCE_STYLE in use, we only need to decapsulate the WRAP token */
+ if (context_handle->flags & GSS_C_DCE_STYLE) {
+ if (input_message_buffer->length < (GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE)) {
+ return GSS_S_BAD_MECH;
+ }
+ len = GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ }
+ omret = _gssapi_verify_mech_header(&p0,
+ len,
+ GSS_KRB5_MECHANISM);
+ if (omret)
+ return omret;
+ p = p0;
+
+ datalen = input_message_buffer->length -
+ (p - ((u_char *)input_message_buffer->value)) -
+ GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+
+ if (memcmp(p, "\x02\x01", 2) != 0)
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+ return GSS_S_BAD_SIG;
+ p += 2;
+
+ if (memcmp (p, "\x10\x00", 2) == 0)
+ conf_flag = 1;
+ else if (memcmp (p, "\xff\xff", 2) == 0)
+ conf_flag = 0;
+ else
+ return GSS_S_BAD_SIG;
+
+ p += 2;
+ if (memcmp (p, "\xff\xff", 2) != 0)
+ return GSS_S_BAD_MIC;
+ p = NULL;
+
+ ret = arcfour_mic_key(gssapi_krb5_context, key,
+ p0 + 16, 8, /* SGN_CKSUM */
+ k6_data, sizeof(k6_data));
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ {
+ RC4_KEY rc4_key;
+
+ RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+ RC4 (&rc4_key, 8, p0 + 8, SND_SEQ); /* SND_SEQ */
+ memset(&rc4_key, 0, sizeof(rc4_key));
+ memset(k6_data, 0, sizeof(k6_data));
+ }
+
+ gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
+
+ if (context_handle->more_flags & LOCAL)
+ cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+ else
+ cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+
+ if (cmp != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ {
+ int i;
+
+ Klocal.keytype = key->keytype;
+ Klocal.keyvalue.data = Klocaldata;
+ Klocal.keyvalue.length = sizeof(Klocaldata);
+
+ for (i = 0; i < 16; i++)
+ Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+ }
+ ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
+ SND_SEQ, 4,
+ k6_data, sizeof(k6_data));
+ memset(Klocaldata, 0, sizeof(Klocaldata));
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ output_message_buffer->value = malloc(datalen);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ output_message_buffer->length = datalen;
+
+ if(conf_flag) {
+ RC4_KEY rc4_key;
+
+ RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+ RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */
+ RC4 (&rc4_key, datalen, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+ output_message_buffer->value);
+ memset(&rc4_key, 0, sizeof(rc4_key));
+ } else {
+ memcpy(Confounder, p0 + 24, 8); /* Confounder */
+ memcpy(output_message_buffer->value,
+ p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+ datalen);
+ }
+ memset(k6_data, 0, sizeof(k6_data));
+
+ if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+ ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
+ if (ret) {
+ gss_release_buffer(minor_status, output_message_buffer);
+ *minor_status = 0;
+ return ret;
+ }
+ output_message_buffer->length -= padlen;
+ }
+
+ ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
+ cksum_data, sizeof(cksum_data),
+ p0, 8,
+ Confounder, sizeof(Confounder),
+ output_message_buffer->value,
+ output_message_buffer->length + padlen);
+ if (ret) {
+ gss_release_buffer(minor_status, output_message_buffer);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
+ if (cmp) {
+ gss_release_buffer(minor_status, output_message_buffer);
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ omret = _gssapi_msg_order_check(context_handle->order, seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ if (omret)
+ return omret;
+
+ if (conf_state)
+ *conf_state = conf_flag;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/arcfour.h b/source4/heimdal/lib/gssapi/arcfour.h
new file mode 100644
index 0000000000..5acfcad29d
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/arcfour.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: arcfour.h,v 1.5 2004/03/07 22:30:57 lha Exp $ */
+
+#ifndef GSSAPI_ARCFOUR_H_
+#define GSSAPI_ARCFOUR_H_ 1
+
+#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
+#define GSS_ARCFOUR_WRAP_TOKEN_OFFSET 13
+
+OM_uint32 _gssapi_wrap_arcfour(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_verify_mic_arcfour(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key,
+ char *type);
+
+#endif /* GSSAPI_ARCFOUR_H_ */
diff --git a/source4/heimdal/lib/gssapi/ccache_name.c b/source4/heimdal/lib/gssapi/ccache_name.c
new file mode 100755
index 0000000000..3bebb83c1f
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/ccache_name.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: ccache_name.c,v 1.2 2005/06/16 20:38:49 lha Exp $");
+
+char *last_out_name;
+
+OM_uint32
+gss_krb5_ccache_name(OM_uint32 *minor_status,
+ const char *name,
+ const char **out_name)
+{
+ krb5_error_code kret;
+
+ *minor_status = 0;
+
+ GSSAPI_KRB5_INIT();
+
+ if (out_name) {
+ const char *n;
+
+ if (last_out_name) {
+ free(last_out_name);
+ last_out_name = NULL;
+ }
+
+ n = krb5_cc_default_name(gssapi_krb5_context);
+ if (n == NULL) {
+ *minor_status = ENOMEM;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+ last_out_name = strdup(n);
+ if (last_out_name == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ *out_name = last_out_name;
+ }
+
+ kret = krb5_cc_set_default_name(gssapi_krb5_context, name);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/cfx.c b/source4/heimdal/lib/gssapi/cfx.c
new file mode 100755
index 0000000000..75b6a8bcfa
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/cfx.c
@@ -0,0 +1,841 @@
+/*
+ * Copyright (c) 2003, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "gssapi_locl.h"
+
+RCSID("$Id: cfx.c,v 1.17 2005/04/27 17:47:32 lha Exp $");
+
+/*
+ * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt
+ */
+
+#define CFXSentByAcceptor (1 << 0)
+#define CFXSealed (1 << 1)
+#define CFXAcceptorSubkey (1 << 2)
+
+static krb5_error_code
+wrap_length_cfx(krb5_crypto crypto,
+ int conf_req_flag,
+ size_t input_length,
+ size_t *output_length,
+ size_t *cksumsize,
+ u_int16_t *padlength)
+{
+ krb5_error_code ret;
+ krb5_cksumtype type;
+
+ /* 16-byte header is always first */
+ *output_length = sizeof(gss_cfx_wrap_token_desc);
+ *padlength = 0;
+
+ ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, crypto, &type);
+ if (ret) {
+ return ret;
+ }
+
+ ret = krb5_checksumsize(gssapi_krb5_context, type, cksumsize);
+ if (ret) {
+ return ret;
+ }
+
+ if (conf_req_flag) {
+ size_t padsize;
+
+ /* Header is concatenated with data before encryption */
+ input_length += sizeof(gss_cfx_wrap_token_desc);
+
+ ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, &padsize);
+ if (ret) {
+ return ret;
+ }
+ if (padsize > 1) {
+ /* XXX check this */
+ *padlength = padsize - (input_length % padsize);
+ }
+
+ /* We add the pad ourselves (noted here for completeness only) */
+ input_length += *padlength;
+
+ *output_length += krb5_get_wrapped_length(gssapi_krb5_context,
+ crypto, input_length);
+ } else {
+ /* Checksum is concatenated with data */
+ *output_length += input_length + *cksumsize;
+ }
+
+ assert(*output_length > input_length);
+
+ return 0;
+}
+
+OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+ u_int16_t padlength;
+ size_t output_length, cksumsize;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = wrap_length_cfx(crypto, conf_req_flag,
+ req_output_size,
+ &output_length, &cksumsize, &padlength);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ if (output_length < req_output_size) {
+ *max_input_size = (req_output_size - output_length);
+ *max_input_size -= padlength;
+ } else {
+ /* Should this return an error? */
+ *max_input_size = 0;
+ }
+
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Rotate "rrc" bytes to the front or back
+ */
+
+static krb5_error_code
+rrc_rotate(void *data, size_t len, u_int16_t rrc, krb5_boolean unrotate)
+{
+ u_char *tmp;
+ size_t left;
+ char buf[256];
+
+ if (len == 0)
+ return 0;
+
+ rrc %= len;
+
+ if (rrc == 0)
+ return 0;
+
+ left = len - rrc;
+
+ if (rrc <= sizeof(buf)) {
+ tmp = buf;
+ } else {
+ tmp = malloc(rrc);
+ if (tmp == NULL)
+ return ENOMEM;
+ }
+
+ if (unrotate) {
+ memcpy(tmp, data, rrc);
+ memmove(data, (u_char *)data + rrc, left);
+ memcpy((u_char *)data + left, tmp, rrc);
+ } else {
+ memcpy(tmp, (u_char *)data + left, rrc);
+ memmove((u_char *)data + rrc, data, left);
+ memcpy(data, tmp, rrc);
+ }
+
+ if (rrc > sizeof(buf))
+ free(tmp);
+
+ return 0;
+}
+
+OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer,
+ krb5_keyblock *key)
+{
+ krb5_crypto crypto;
+ gss_cfx_wrap_token token;
+ krb5_error_code ret;
+ unsigned usage;
+ krb5_data cipher;
+ size_t wrapped_len, cksumsize;
+ u_int16_t padlength, rrc = 0;
+ OM_uint32 seq_number;
+ u_char *p;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = wrap_length_cfx(crypto, conf_req_flag,
+ input_message_buffer->length,
+ &wrapped_len, &cksumsize, &padlength);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ /* Always rotate encrypted token (if any) and checksum to header */
+ rrc = (conf_req_flag ? sizeof(*token) : 0) + (u_int16_t)cksumsize;
+
+ output_message_buffer->length = wrapped_len;
+ output_message_buffer->value = malloc(output_message_buffer->length);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ p = output_message_buffer->value;
+ token = (gss_cfx_wrap_token)p;
+ token->TOK_ID[0] = 0x05;
+ token->TOK_ID[1] = 0x04;
+ token->Flags = 0;
+ token->Filler = 0xFF;
+ if ((context_handle->more_flags & LOCAL) == 0)
+ token->Flags |= CFXSentByAcceptor;
+ if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+ token->Flags |= CFXAcceptorSubkey;
+ if (conf_req_flag) {
+ /*
+ * In Wrap tokens with confidentiality, the EC field is
+ * used to encode the size (in bytes) of the random filler.
+ */
+ token->Flags |= CFXSealed;
+ token->EC[0] = (padlength >> 8) & 0xFF;
+ token->EC[1] = (padlength >> 0) & 0xFF;
+ } else {
+ /*
+ * In Wrap tokens without confidentiality, the EC field is
+ * used to encode the size (in bytes) of the trailing
+ * checksum.
+ *
+ * This is not used in the checksum calcuation itself,
+ * because the checksum length could potentially vary
+ * depending on the data length.
+ */
+ token->EC[0] = 0;
+ token->EC[1] = 0;
+ }
+
+ /*
+ * In Wrap tokens that provide for confidentiality, the RRC
+ * field in the header contains the hex value 00 00 before
+ * encryption.
+ *
+ * In Wrap tokens that do not provide for confidentiality,
+ * both the EC and RRC fields in the appended checksum
+ * contain the hex value 00 00 for the purpose of calculating
+ * the checksum.
+ */
+ token->RRC[0] = 0;
+ token->RRC[1] = 0;
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+ gssapi_encode_be_om_uint32(0, &token->SND_SEQ[0]);
+ gssapi_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
+ krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /*
+ * If confidentiality is requested, the token header is
+ * appended to the plaintext before encryption; the resulting
+ * token is {"header" | encrypt(plaintext | pad | "header")}.
+ *
+ * If no confidentiality is requested, the checksum is
+ * calculated over the plaintext concatenated with the
+ * token header.
+ */
+ if (context_handle->more_flags & LOCAL) {
+ usage = KRB5_KU_USAGE_INITIATOR_SEAL;
+ } else {
+ usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
+ }
+
+ if (conf_req_flag) {
+ /*
+ * Any necessary padding is added here to ensure that the
+ * encrypted token header is always at the end of the
+ * ciphertext.
+ *
+ * The specification does not require that the padding
+ * bytes are initialized.
+ */
+ p += sizeof(*token);
+ memcpy(p, input_message_buffer->value, input_message_buffer->length);
+ memset(p + input_message_buffer->length, 0xFF, padlength);
+ memcpy(p + input_message_buffer->length + padlength,
+ token, sizeof(*token));
+
+ ret = krb5_encrypt(gssapi_krb5_context, crypto,
+ usage, p,
+ input_message_buffer->length + padlength +
+ sizeof(*token),
+ &cipher);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ gss_release_buffer(minor_status, output_message_buffer);
+ return GSS_S_FAILURE;
+ }
+ assert(sizeof(*token) + cipher.length == wrapped_len);
+ token->RRC[0] = (rrc >> 8) & 0xFF;
+ token->RRC[1] = (rrc >> 0) & 0xFF;
+
+ ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ gss_release_buffer(minor_status, output_message_buffer);
+ return GSS_S_FAILURE;
+ }
+ memcpy(p, cipher.data, cipher.length);
+ krb5_data_free(&cipher);
+ } else {
+ char *buf;
+ Checksum cksum;
+
+ buf = malloc(input_message_buffer->length + sizeof(*token));
+ if (buf == NULL) {
+ *minor_status = ENOMEM;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ gss_release_buffer(minor_status, output_message_buffer);
+ return GSS_S_FAILURE;
+ }
+ memcpy(buf, input_message_buffer->value, input_message_buffer->length);
+ memcpy(buf + input_message_buffer->length, token, sizeof(*token));
+
+ ret = krb5_create_checksum(gssapi_krb5_context, crypto,
+ usage, 0, buf,
+ input_message_buffer->length +
+ sizeof(*token),
+ &cksum);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ gss_release_buffer(minor_status, output_message_buffer);
+ free(buf);
+ return GSS_S_FAILURE;
+ }
+
+ free(buf);
+
+ assert(cksum.checksum.length == cksumsize);
+ token->EC[0] = (cksum.checksum.length >> 8) & 0xFF;
+ token->EC[1] = (cksum.checksum.length >> 0) & 0xFF;
+ token->RRC[0] = (rrc >> 8) & 0xFF;
+ token->RRC[1] = (rrc >> 0) & 0xFF;
+
+ p += sizeof(*token);
+ memcpy(p, input_message_buffer->value, input_message_buffer->length);
+ memcpy(p + input_message_buffer->length,
+ cksum.checksum.data, cksum.checksum.length);
+
+ ret = rrc_rotate(p,
+ input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ gss_release_buffer(minor_status, output_message_buffer);
+ free_Checksum(&cksum);
+ return GSS_S_FAILURE;
+ }
+ free_Checksum(&cksum);
+ }
+
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+ if (conf_state != NULL) {
+ *conf_state = conf_req_flag;
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key)
+{
+ krb5_crypto crypto;
+ gss_cfx_wrap_token token;
+ u_char token_flags;
+ krb5_error_code ret;
+ unsigned usage;
+ krb5_data data;
+ u_int16_t ec, rrc;
+ OM_uint32 seq_number_lo, seq_number_hi;
+ size_t len;
+ u_char *p;
+
+ *minor_status = 0;
+
+ if (input_message_buffer->length < sizeof(*token)) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ p = input_message_buffer->value;
+
+ token = (gss_cfx_wrap_token)p;
+
+ if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* Ignore unknown flags */
+ token_flags = token->Flags &
+ (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
+
+ if (token_flags & CFXSentByAcceptor) {
+ if ((context_handle->more_flags & LOCAL) == 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+ if ((token_flags & CFXAcceptorSubkey) == 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ if (token_flags & CFXAcceptorSubkey)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (token->Filler != 0xFF) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (conf_state != NULL) {
+ *conf_state = (token_flags & CFXSealed) ? 1 : 0;
+ }
+
+ ec = (token->EC[0] << 8) | token->EC[1];
+ rrc = (token->RRC[0] << 8) | token->RRC[1];
+
+ /*
+ * Check sequence number
+ */
+ gssapi_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
+ gssapi_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
+ if (seq_number_hi) {
+ /* no support for 64-bit sequence numbers */
+ *minor_status = ERANGE;
+ return GSS_S_UNSEQ_TOKEN;
+ }
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+ if (ret != 0) {
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ gss_release_buffer(minor_status, output_message_buffer);
+ return ret;
+ }
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /*
+ * Decrypt and/or verify checksum
+ */
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ if (context_handle->more_flags & LOCAL) {
+ usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
+ } else {
+ usage = KRB5_KU_USAGE_INITIATOR_SEAL;
+ }
+
+ p += sizeof(*token);
+ len = input_message_buffer->length;
+ len -= (p - (u_char *)input_message_buffer->value);
+
+ /* Rotate by RRC; bogus to do this in-place XXX */
+ *minor_status = rrc_rotate(p, len, rrc, TRUE);
+ if (*minor_status != 0) {
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ if (token_flags & CFXSealed) {
+ ret = krb5_decrypt(gssapi_krb5_context, crypto, usage,
+ p, len, &data);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_BAD_MIC;
+ }
+
+ /* Check that there is room for the pad and token header */
+ if (data.length < ec + sizeof(*token)) {
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ krb5_data_free(&data);
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ p = data.data;
+ p += data.length - sizeof(*token);
+
+ /* RRC is unprotected; don't modify input buffer */
+ ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
+ ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
+
+ /* Check the integrity of the header */
+ if (memcmp(p, token, sizeof(*token)) != 0) {
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ krb5_data_free(&data);
+ return GSS_S_BAD_MIC;
+ }
+
+ output_message_buffer->value = data.data;
+ output_message_buffer->length = data.length - ec - sizeof(*token);
+ } else {
+ Checksum cksum;
+
+ /* Determine checksum type */
+ ret = krb5_crypto_get_checksum_type(gssapi_krb5_context,
+ crypto, &cksum.cksumtype);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ cksum.checksum.length = ec;
+
+ /* Check we have at least as much data as the checksum */
+ if (len < cksum.checksum.length) {
+ *minor_status = ERANGE;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_BAD_MIC;
+ }
+
+ /* Length now is of the plaintext only, no checksum */
+ len -= cksum.checksum.length;
+ cksum.checksum.data = p + len;
+
+ output_message_buffer->length = len; /* for later */
+ output_message_buffer->value = malloc(len + sizeof(*token));
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ /* Checksum is over (plaintext-data | "header") */
+ memcpy(output_message_buffer->value, p, len);
+ memcpy((u_char *)output_message_buffer->value + len,
+ token, sizeof(*token));
+
+ /* EC is not included in checksum calculation */
+ token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
+ len);
+ token->EC[0] = 0;
+ token->EC[1] = 0;
+ token->RRC[0] = 0;
+ token->RRC[1] = 0;
+
+ ret = krb5_verify_checksum(gssapi_krb5_context, crypto,
+ usage,
+ output_message_buffer->value,
+ len + sizeof(*token),
+ &cksum);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ gss_release_buffer(minor_status, output_message_buffer);
+ return GSS_S_BAD_MIC;
+ }
+ }
+
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+ if (qop_state != NULL) {
+ *qop_state = GSS_C_QOP_DEFAULT;
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ krb5_keyblock *key)
+{
+ krb5_crypto crypto;
+ gss_cfx_mic_token token;
+ krb5_error_code ret;
+ unsigned usage;
+ Checksum cksum;
+ u_char *buf;
+ size_t len;
+ OM_uint32 seq_number;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ len = message_buffer->length + sizeof(*token);
+ buf = malloc(len);
+ if (buf == NULL) {
+ *minor_status = ENOMEM;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(buf, message_buffer->value, message_buffer->length);
+
+ token = (gss_cfx_mic_token)(buf + message_buffer->length);
+ token->TOK_ID[0] = 0x04;
+ token->TOK_ID[1] = 0x04;
+ token->Flags = 0;
+ if ((context_handle->more_flags & LOCAL) == 0)
+ token->Flags |= CFXSentByAcceptor;
+ if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+ token->Flags |= CFXAcceptorSubkey;
+ memset(token->Filler, 0xFF, 5);
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+ gssapi_encode_be_om_uint32(0, &token->SND_SEQ[0]);
+ gssapi_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
+ krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ if (context_handle->more_flags & LOCAL) {
+ usage = KRB5_KU_USAGE_INITIATOR_SIGN;
+ } else {
+ usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
+ }
+
+ ret = krb5_create_checksum(gssapi_krb5_context, crypto,
+ usage, 0, buf, len, &cksum);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ free(buf);
+ return GSS_S_FAILURE;
+ }
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+ /* Determine MIC length */
+ message_token->length = sizeof(*token) + cksum.checksum.length;
+ message_token->value = malloc(message_token->length);
+ if (message_token->value == NULL) {
+ *minor_status = ENOMEM;
+ free_Checksum(&cksum);
+ free(buf);
+ return GSS_S_FAILURE;
+ }
+
+ /* Token is { "header" | get_mic("header" | plaintext-data) } */
+ memcpy(message_token->value, token, sizeof(*token));
+ memcpy((u_char *)message_token->value + sizeof(*token),
+ cksum.checksum.data, cksum.checksum.length);
+
+ free_Checksum(&cksum);
+ free(buf);
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key)
+{
+ krb5_crypto crypto;
+ gss_cfx_mic_token token;
+ u_char token_flags;
+ krb5_error_code ret;
+ unsigned usage;
+ OM_uint32 seq_number_lo, seq_number_hi;
+ u_char *buf, *p;
+ Checksum cksum;
+
+ *minor_status = 0;
+
+ if (token_buffer->length < sizeof(*token)) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ p = token_buffer->value;
+
+ token = (gss_cfx_mic_token)p;
+
+ if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* Ignore unknown flags */
+ token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
+
+ if (token_flags & CFXSentByAcceptor) {
+ if ((context_handle->more_flags & LOCAL) == 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+ if ((token_flags & CFXAcceptorSubkey) == 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ if (token_flags & CFXAcceptorSubkey)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /*
+ * Check sequence number
+ */
+ gssapi_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
+ gssapi_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
+ if (seq_number_hi) {
+ *minor_status = ERANGE;
+ return GSS_S_UNSEQ_TOKEN;
+ }
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+ if (ret != 0) {
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return ret;
+ }
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /*
+ * Verify checksum
+ */
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, crypto,
+ &cksum.cksumtype);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+
+ cksum.checksum.data = p + sizeof(*token);
+ cksum.checksum.length = token_buffer->length - sizeof(*token);
+
+ if (context_handle->more_flags & LOCAL) {
+ usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
+ } else {
+ usage = KRB5_KU_USAGE_INITIATOR_SIGN;
+ }
+
+ buf = malloc(message_buffer->length + sizeof(*token));
+ if (buf == NULL) {
+ *minor_status = ENOMEM;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ return GSS_S_FAILURE;
+ }
+ memcpy(buf, message_buffer->value, message_buffer->length);
+ memcpy(buf + message_buffer->length, token, sizeof(*token));
+
+ ret = krb5_verify_checksum(gssapi_krb5_context, crypto,
+ usage,
+ buf,
+ sizeof(*token) + message_buffer->length,
+ &cksum);
+ if (ret != 0) {
+ gssapi_krb5_set_error_string();
+ *minor_status = ret;
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ free(buf);
+ return GSS_S_BAD_MIC;
+ }
+
+ free(buf);
+
+ if (qop_state != NULL) {
+ *qop_state = GSS_C_QOP_DEFAULT;
+ }
+
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/cfx.h b/source4/heimdal/lib/gssapi/cfx.h
new file mode 100755
index 0000000000..a587cb9d97
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/cfx.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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.
+ */
+
+/* $Id: cfx.h,v 1.5 2003/09/22 21:48:35 lha Exp $ */
+
+#ifndef GSSAPI_CFX_H_
+#define GSSAPI_CFX_H_ 1
+
+/*
+ * Implementation of draft-ietf-krb-wg-gssapi-cfx-01.txt
+ */
+
+typedef struct gss_cfx_mic_token_desc_struct {
+ u_char TOK_ID[2]; /* 04 04 */
+ u_char Flags;
+ u_char Filler[5];
+ u_char SND_SEQ[8];
+} gss_cfx_mic_token_desc, *gss_cfx_mic_token;
+
+typedef struct gss_cfx_wrap_token_desc_struct {
+ u_char TOK_ID[2]; /* 04 05 */
+ u_char Flags;
+ u_char Filler;
+ u_char EC[2];
+ u_char RRC[2];
+ u_char SND_SEQ[8];
+} gss_cfx_wrap_token_desc, *gss_cfx_wrap_token;
+
+typedef struct gss_cfx_delete_token_desc_struct {
+ u_char TOK_ID[2]; /* 05 04 */
+ u_char Flags;
+ u_char Filler[5];
+ u_char SND_SEQ[8];
+} gss_cfx_delete_token_desc, *gss_cfx_delete_token;
+
+OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ krb5_keyblock *key);
+
+OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t *qop_state,
+ krb5_keyblock *key);
+
+#endif /* GSSAPI_CFX_H_ */
diff --git a/source4/heimdal/lib/gssapi/compat.c b/source4/heimdal/lib/gssapi/compat.c
new file mode 100644
index 0000000000..5605c48023
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/compat.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: compat.c,v 1.10 2005/05/30 20:51:51 lha Exp $");
+
+
+krb5_error_code
+_gss_check_compat(OM_uint32 *minor_status, gss_name_t name,
+ const char *option, krb5_boolean *compat,
+ krb5_boolean match_val)
+{
+ krb5_error_code ret = 0;
+ char **p, **q;
+ krb5_principal match;
+
+
+ p = krb5_config_get_strings(gssapi_krb5_context, NULL, "gssapi",
+ option, NULL);
+ if(p == NULL)
+ return 0;
+
+ match = NULL;
+ for(q = p; *q; q++) {
+ ret = krb5_parse_name(gssapi_krb5_context, *q, &match);
+ if (ret)
+ break;
+
+ if (krb5_principal_match(gssapi_krb5_context, name, match)) {
+ *compat = match_val;
+ break;
+ }
+
+ krb5_free_principal(gssapi_krb5_context, match);
+ match = NULL;
+ }
+ if (match)
+ krb5_free_principal(gssapi_krb5_context, match);
+ krb5_config_free_strings(p);
+
+ if (ret) {
+ if (minor_status)
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ return 0;
+}
+
+/*
+ * ctx->ctx_id_mutex is assumed to be locked
+ */
+
+OM_uint32
+_gss_DES3_get_mic_compat(OM_uint32 *minor_status, gss_ctx_id_t ctx)
+{
+ krb5_boolean use_compat = FALSE;
+ OM_uint32 ret;
+
+ if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) {
+ ret = _gss_check_compat(minor_status, ctx->target,
+ "broken_des3_mic", &use_compat, TRUE);
+ if (ret)
+ return ret;
+ ret = _gss_check_compat(minor_status, ctx->target,
+ "correct_des3_mic", &use_compat, FALSE);
+ if (ret)
+ return ret;
+
+ if (use_compat)
+ ctx->more_flags |= COMPAT_OLD_DES3;
+ ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
+ }
+ return 0;
+}
+
+OM_uint32
+gss_krb5_compat_des3_mic(OM_uint32 *minor_status, gss_ctx_id_t ctx, int on)
+{
+ *minor_status = 0;
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ if (on) {
+ ctx->more_flags |= COMPAT_OLD_DES3;
+ } else {
+ ctx->more_flags &= ~COMPAT_OLD_DES3;
+ }
+ ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+
+ return 0;
+}
+
+/*
+ * For compatability with the Windows SPNEGO implementation, the
+ * default is to ignore the mechListMIC unless the initiator specified
+ * CFX or configured in krb5.conf with the option
+ * [gssapi]require_mechlist_mic=target-principal-pattern.
+ * The option is valid for both initiator and acceptor.
+ */
+OM_uint32
+_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
+ gss_ctx_id_t ctx,
+ krb5_boolean *require_mic)
+{
+ OM_uint32 ret;
+ int is_cfx = 0;
+
+ gsskrb5_is_cfx(ctx, &is_cfx);
+ if (is_cfx) {
+ /* CFX session key was used */
+ *require_mic = TRUE;
+ } else {
+ *require_mic = FALSE;
+ ret = _gss_check_compat(minor_status, ctx->target,
+ "require_mechlist_mic",
+ require_mic, TRUE);
+ if (ret)
+ return ret;
+ }
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/context_time.c b/source4/heimdal/lib/gssapi/context_time.c
new file mode 100644
index 0000000000..e13480c85e
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/context_time.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: context_time.c,v 1.10 2003/06/03 15:08:00 lha Exp $");
+
+OM_uint32
+gssapi_lifetime_left(OM_uint32 *minor_status,
+ OM_uint32 lifetime,
+ OM_uint32 *lifetime_rec)
+{
+ krb5_timestamp timeret;
+ krb5_error_code kret;
+
+ kret = krb5_timeofday(gssapi_krb5_context, &timeret);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ if (lifetime < timeret)
+ *lifetime_rec = 0;
+ else
+ *lifetime_rec = lifetime - timeret;
+
+ return GSS_S_COMPLETE;
+}
+
+
+OM_uint32 gss_context_time
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ OM_uint32 * time_rec
+ )
+{
+ OM_uint32 lifetime;
+ OM_uint32 major_status;
+
+ GSSAPI_KRB5_INIT ();
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ lifetime = context_handle->lifetime;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ major_status = gssapi_lifetime_left(minor_status, lifetime, time_rec);
+ if (major_status != GSS_S_COMPLETE)
+ return major_status;
+
+ *minor_status = 0;
+
+ if (*time_rec == 0)
+ return GSS_S_CONTEXT_EXPIRED;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/copy_ccache.c b/source4/heimdal/lib/gssapi/copy_ccache.c
new file mode 100644
index 0000000000..4f2b3f4895
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/copy_ccache.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2000 - 2001, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: copy_ccache.c,v 1.7 2003/09/01 15:11:09 lha Exp $");
+
+OM_uint32
+gss_krb5_copy_ccache(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ krb5_ccache out)
+{
+ krb5_error_code kret;
+
+ HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
+
+ if (cred->ccache == NULL) {
+ HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_cc_copy_cache(gssapi_krb5_context, cred->ccache, out);
+ HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int ad_type,
+ gss_buffer_t ad_data)
+{
+ krb5_error_code ret;
+ krb5_data data;
+
+ ad_data->value = NULL;
+ ad_data->length = 0;
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ if (context_handle->ticket == NULL) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ ret = krb5_ticket_get_authorization_data_type(gssapi_krb5_context,
+ context_handle->ticket,
+ ad_type,
+ &data);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ad_data->value = malloc(data.length);
+ if (ad_data->value == NULL) {
+ krb5_data_free(&data);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ ad_data->length = data.length;
+ memcpy(ad_data->value, data.data, ad_data->length);
+ krb5_data_free(&data);
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_krb5_copy_service_keyblock
+ (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ struct EncryptionKey **out)
+{
+ krb5_error_code ret;
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ if (context_handle->service_keyblock == NULL) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ ret = krb5_copy_keyblock(gssapi_krb5_context,
+ context_handle->service_keyblock,
+ out);
+
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c b/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c
new file mode 100644
index 0000000000..1a25e0d781
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: create_emtpy_oid_set.c,v 1.5 2003/03/16 17:47:07 lha Exp $");
+
+OM_uint32 gss_create_empty_oid_set (
+ OM_uint32 * minor_status,
+ gss_OID_set * oid_set
+ )
+{
+ *oid_set = malloc(sizeof(**oid_set));
+ if (*oid_set == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ (*oid_set)->count = 0;
+ (*oid_set)->elements = NULL;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/decapsulate.c b/source4/heimdal/lib/gssapi/decapsulate.c
new file mode 100644
index 0000000000..90e037f09b
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/decapsulate.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: decapsulate.c,v 1.12 2005/06/16 20:40:49 lha Exp $");
+
+/*
+ * return the length of the mechanism in token or -1
+ * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
+ */
+
+ssize_t
+gssapi_krb5_get_mech (const u_char *ptr,
+ size_t total_len,
+ const u_char **mech_ret)
+{
+ size_t len, len_len, mech_len, foo;
+ const u_char *p = ptr;
+ int e;
+
+ if (total_len < 1)
+ return -1;
+ if (*p++ != 0x60)
+ return -1;
+ e = der_get_length (p, total_len - 1, &len, &len_len);
+ if (e || 1 + len_len + len != total_len)
+ return -1;
+ p += len_len;
+ if (*p++ != 0x06)
+ return -1;
+ e = der_get_length (p, total_len - 1 - len_len - 1,
+ &mech_len, &foo);
+ if (e)
+ return -1;
+ p += foo;
+ *mech_ret = p;
+ return mech_len;
+}
+
+OM_uint32
+_gssapi_verify_mech_header(u_char **str,
+ size_t total_len,
+ gss_OID mech)
+{
+ const u_char *p;
+ ssize_t mech_len;
+
+ mech_len = gssapi_krb5_get_mech (*str, total_len, &p);
+ if (mech_len < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (mech_len != mech->length)
+ return GSS_S_BAD_MECH;
+ if (memcmp(p,
+ mech->elements,
+ mech->length) != 0)
+ return GSS_S_BAD_MECH;
+ p += mech_len;
+ *str = rk_UNCONST(p);
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssapi_krb5_verify_header(u_char **str,
+ size_t total_len,
+ const u_char *type,
+ gss_OID oid)
+{
+ OM_uint32 ret;
+ size_t len;
+ u_char *p = *str;
+
+ ret = _gssapi_verify_mech_header(str, total_len, oid);
+ if (ret)
+ return ret;
+
+ len = total_len - (*str - p);
+
+ if (len < 2)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (memcmp (*str, type, 2) != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ *str += 2;
+
+ return 0;
+}
+
+/*
+ * Remove the GSS-API wrapping from `in_token' giving `out_data.
+ * Does not copy data, so just free `in_token'.
+ */
+
+OM_uint32
+_gssapi_decapsulate(
+ OM_uint32 *minor_status,
+ gss_buffer_t input_token_buffer,
+ krb5_data *out_data,
+ const gss_OID mech
+)
+{
+ u_char *p;
+ OM_uint32 ret;
+
+ p = input_token_buffer->value;
+ ret = _gssapi_verify_mech_header(&p,
+ input_token_buffer->length,
+ mech);
+ if (ret) {
+ *minor_status = 0;
+ return ret;
+ }
+
+ out_data->length = input_token_buffer->length -
+ (p - (u_char *)input_token_buffer->value);
+ out_data->data = p;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Remove the GSS-API wrapping from `in_token' giving `out_data.
+ * Does not copy data, so just free `in_token'.
+ */
+
+OM_uint32
+gssapi_krb5_decapsulate(OM_uint32 *minor_status,
+ gss_buffer_t input_token_buffer,
+ krb5_data *out_data,
+ const char *type,
+ gss_OID oid)
+{
+ u_char *p;
+ OM_uint32 ret;
+
+ p = input_token_buffer->value;
+ ret = gssapi_krb5_verify_header(&p,
+ input_token_buffer->length,
+ type,
+ oid);
+ if (ret) {
+ *minor_status = 0;
+ return ret;
+ }
+
+ out_data->length = input_token_buffer->length -
+ (p - (u_char *)input_token_buffer->value);
+ out_data->data = p;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Verify padding of a gss wrapped message and return its length.
+ */
+
+OM_uint32
+_gssapi_verify_pad(gss_buffer_t wrapped_token,
+ size_t datalen,
+ size_t *padlen)
+{
+ u_char *pad;
+ size_t padlength;
+ int i;
+
+ pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
+ padlength = *pad;
+
+ if (padlength > datalen)
+ return GSS_S_BAD_MECH;
+
+ for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
+ ;
+ if (i != 0)
+ return GSS_S_BAD_MIC;
+
+ *padlen = padlength;
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/gssapi/delete_sec_context.c b/source4/heimdal/lib/gssapi/delete_sec_context.c
new file mode 100644
index 0000000000..83658fa76c
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/delete_sec_context.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: delete_sec_context.c,v 1.15 2005/04/27 17:48:17 lha Exp $");
+
+OM_uint32 gss_delete_sec_context
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ gss_buffer_t output_token
+ )
+{
+ GSSAPI_KRB5_INIT ();
+
+ if (output_token) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+
+ krb5_auth_con_free (gssapi_krb5_context,
+ (*context_handle)->auth_context);
+ if((*context_handle)->source)
+ krb5_free_principal (gssapi_krb5_context,
+ (*context_handle)->source);
+ if((*context_handle)->target)
+ krb5_free_principal (gssapi_krb5_context,
+ (*context_handle)->target);
+ if ((*context_handle)->ticket)
+ krb5_free_ticket (gssapi_krb5_context,
+ (*context_handle)->ticket);
+ if ((*context_handle)->service_keyblock)
+ krb5_free_keyblock (gssapi_krb5_context,
+ (*context_handle)->service_keyblock);
+ if((*context_handle)->order)
+ _gssapi_msg_order_destroy(&(*context_handle)->order);
+
+ HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
+ HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
+ memset(*context_handle, 0, sizeof(**context_handle));
+ free (*context_handle);
+ *context_handle = GSS_C_NO_CONTEXT;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/display_name.c b/source4/heimdal/lib/gssapi/display_name.c
new file mode 100644
index 0000000000..27a232fd3c
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/display_name.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: display_name.c,v 1.9 2003/03/16 17:46:11 lha Exp $");
+
+OM_uint32 gss_display_name
+ (OM_uint32 * minor_status,
+ const gss_name_t input_name,
+ gss_buffer_t output_name_buffer,
+ gss_OID * output_name_type
+ )
+{
+ krb5_error_code kret;
+ char *buf;
+ size_t len;
+
+ GSSAPI_KRB5_INIT ();
+ kret = krb5_unparse_name (gssapi_krb5_context,
+ input_name,
+ &buf);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+ len = strlen (buf);
+ output_name_buffer->length = len;
+ output_name_buffer->value = malloc(len + 1);
+ if (output_name_buffer->value == NULL) {
+ free (buf);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy (output_name_buffer->value, buf, len);
+ ((char *)output_name_buffer->value)[len] = '\0';
+ free (buf);
+ if (output_name_type)
+ *output_name_type = GSS_KRB5_NT_PRINCIPAL_NAME;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/display_status.c b/source4/heimdal/lib/gssapi/display_status.c
new file mode 100644
index 0000000000..2c84628266
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/display_status.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: display_status.c,v 1.12 2005/03/16 13:15:03 lha Exp $");
+
+static char *
+calling_error(OM_uint32 v)
+{
+ static char *msgs[] = {
+ NULL, /* 0 */
+ "A required input parameter could not be read.", /* */
+ "A required output parameter could not be written.", /* */
+ "A parameter was malformed"
+ };
+
+ v >>= GSS_C_CALLING_ERROR_OFFSET;
+
+ if (v == 0)
+ return "";
+ else if (v >= sizeof(msgs)/sizeof(*msgs))
+ return "unknown calling error";
+ else
+ return msgs[v];
+}
+
+static char *
+routine_error(OM_uint32 v)
+{
+ static char *msgs[] = {
+ NULL, /* 0 */
+ "An unsupported mechanism was requested",
+ "An invalid name was supplied",
+ "A supplied name was of an unsupported type",
+ "Incorrect channel bindings were supplied",
+ "An invalid status code was supplied",
+ "A token had an invalid MIC",
+ "No credentials were supplied, "
+ "or the credentials were unavailable or inaccessible.",
+ "No context has been established",
+ "A token was invalid",
+ "A credential was invalid",
+ "The referenced credentials have expired",
+ "The context has expired",
+ "Miscellaneous failure (see text)",
+ "The quality-of-protection requested could not be provide",
+ "The operation is forbidden by local security policy",
+ "The operation or option is not available",
+ "The requested credential element already exists",
+ "The provided name was not a mechanism name.",
+ };
+
+ v >>= GSS_C_ROUTINE_ERROR_OFFSET;
+
+ if (v == 0)
+ return "";
+ else if (v >= sizeof(msgs)/sizeof(*msgs))
+ return "unknown routine error";
+ else
+ return msgs[v];
+}
+
+static char *
+supplementary_error(OM_uint32 v)
+{
+ static char *msgs[] = {
+ "normal completion",
+ "continuation call to routine required",
+ "duplicate per-message token detected",
+ "timed-out per-message token detected",
+ "reordered (early) per-message token detected",
+ "skipped predecessor token(s) detected"
+ };
+
+ v >>= GSS_C_SUPPLEMENTARY_OFFSET;
+
+ if (v >= sizeof(msgs)/sizeof(*msgs))
+ return "unknown routine error";
+ else
+ return msgs[v];
+}
+
+void
+gssapi_krb5_set_error_string (void)
+{
+ struct gssapi_thr_context *ctx = gssapi_get_thread_context(1);
+ char *e;
+
+ if (ctx == NULL)
+ return;
+ HEIMDAL_MUTEX_lock(&ctx->mutex);
+ if (ctx->error_string)
+ free(ctx->error_string);
+ e = krb5_get_error_string(gssapi_krb5_context);
+ if (e == NULL)
+ ctx->error_string = NULL;
+ else {
+ /* ignore failures, will use status code instead */
+ ctx->error_string = strdup(e);
+ krb5_free_error_string(gssapi_krb5_context, e);
+ }
+ HEIMDAL_MUTEX_unlock(&ctx->mutex);
+}
+
+char *
+gssapi_krb5_get_error_string (void)
+{
+ struct gssapi_thr_context *ctx = gssapi_get_thread_context(0);
+ char *ret;
+
+ if (ctx == NULL)
+ return NULL;
+ HEIMDAL_MUTEX_lock(&ctx->mutex);
+ ret = ctx->error_string;
+ ctx->error_string = NULL;
+ HEIMDAL_MUTEX_unlock(&ctx->mutex);
+ return ret;
+}
+
+OM_uint32 gss_display_status
+ (OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ int status_type,
+ const gss_OID mech_type,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string)
+{
+ char *buf;
+
+ GSSAPI_KRB5_INIT ();
+
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
+ gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
+ *minor_status = 0;
+ return GSS_C_GSS_CODE;
+ }
+
+ if (status_type == GSS_C_GSS_CODE) {
+ if (GSS_SUPPLEMENTARY_INFO(status_value))
+ asprintf(&buf, "%s",
+ supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value)));
+ else
+ asprintf (&buf, "%s %s",
+ calling_error(GSS_CALLING_ERROR(status_value)),
+ routine_error(GSS_ROUTINE_ERROR(status_value)));
+ } else if (status_type == GSS_C_MECH_CODE) {
+ buf = gssapi_krb5_get_error_string ();
+ if (buf == NULL) {
+ const char *tmp = krb5_get_err_text (gssapi_krb5_context,
+ status_value);
+ if (tmp == NULL)
+ asprintf(&buf, "unknown mech error-code %u",
+ (unsigned)status_value);
+ else
+ buf = strdup(tmp);
+ }
+ } else {
+ *minor_status = EINVAL;
+ return GSS_S_BAD_STATUS;
+ }
+
+ if (buf == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ *message_context = 0;
+ *minor_status = 0;
+
+ status_string->length = strlen(buf);
+ status_string->value = buf;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/duplicate_name.c b/source4/heimdal/lib/gssapi/duplicate_name.c
new file mode 100644
index 0000000000..2b54e90ec8
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/duplicate_name.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: duplicate_name.c,v 1.7 2003/03/16 17:44:26 lha Exp $");
+
+OM_uint32 gss_duplicate_name (
+ OM_uint32 * minor_status,
+ const gss_name_t src_name,
+ gss_name_t * dest_name
+ )
+{
+ krb5_error_code kret;
+
+ GSSAPI_KRB5_INIT ();
+
+ kret = krb5_copy_principal (gssapi_krb5_context,
+ src_name,
+ dest_name);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ } else {
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+}
diff --git a/source4/heimdal/lib/gssapi/encapsulate.c b/source4/heimdal/lib/gssapi/encapsulate.c
new file mode 100644
index 0000000000..4d488a6c42
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/encapsulate.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: encapsulate.c,v 1.8 2003/09/04 18:08:55 lha Exp $");
+
+void
+_gssapi_encap_length (size_t data_len,
+ size_t *len,
+ size_t *total_len,
+ const gss_OID mech)
+{
+ size_t len_len;
+
+ *len = 1 + 1 + mech->length + data_len;
+
+ len_len = length_len(*len);
+
+ *total_len = 1 + len_len + *len;
+}
+
+void
+gssapi_krb5_encap_length (size_t data_len,
+ size_t *len,
+ size_t *total_len,
+ const gss_OID mech)
+{
+ _gssapi_encap_length(data_len + 2, len, total_len, mech);
+}
+
+u_char *
+gssapi_krb5_make_header (u_char *p,
+ size_t len,
+ const u_char *type,
+ const gss_OID mech)
+{
+ p = _gssapi_make_mech_header(p, len, mech);
+ memcpy (p, type, 2);
+ p += 2;
+ return p;
+}
+
+u_char *
+_gssapi_make_mech_header(u_char *p,
+ size_t len,
+ const gss_OID mech)
+{
+ int e;
+ size_t len_len, foo;
+
+ *p++ = 0x60;
+ len_len = length_len(len);
+ e = der_put_length (p + len_len - 1, len_len, len, &foo);
+ if(e || foo != len_len)
+ abort ();
+ p += len_len;
+ *p++ = 0x06;
+ *p++ = mech->length;
+ memcpy (p, mech->elements, mech->length);
+ p += mech->length;
+ return p;
+}
+
+/*
+ * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
+ */
+
+OM_uint32
+_gssapi_encapsulate(
+ OM_uint32 *minor_status,
+ const krb5_data *in_data,
+ gss_buffer_t output_token,
+ const gss_OID mech
+)
+{
+ size_t len, outer_len;
+ u_char *p;
+
+ _gssapi_encap_length (in_data->length, &len, &outer_len, mech);
+
+ output_token->length = outer_len;
+ output_token->value = malloc (outer_len);
+ if (output_token->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = _gssapi_make_mech_header (output_token->value, len, mech);
+ memcpy (p, in_data->data, in_data->length);
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Give it a krb5_data and it will encapsulate with extra GSS-API krb5
+ * wrappings.
+ */
+
+OM_uint32
+gssapi_krb5_encapsulate(
+ OM_uint32 *minor_status,
+ const krb5_data *in_data,
+ gss_buffer_t output_token,
+ const u_char *type,
+ const gss_OID mech
+)
+{
+ size_t len, outer_len;
+ u_char *p;
+
+ gssapi_krb5_encap_length (in_data->length, &len, &outer_len, mech);
+
+ output_token->length = outer_len;
+ output_token->value = malloc (outer_len);
+ if (output_token->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = gssapi_krb5_make_header (output_token->value, len, type, mech);
+ memcpy (p, in_data->data, in_data->length);
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/external.c b/source4/heimdal/lib/gssapi/external.c
new file mode 100644
index 0000000000..f3e97181e6
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/external.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: external.c,v 1.6 2003/09/08 15:34:19 lha Exp $");
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_user_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ "\x01\x02\x01\x01"};
+
+gss_OID GSS_C_NT_USER_NAME = &gss_c_nt_user_name_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_machine_uid_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ "\x01\x02\x01\x02"};
+
+gss_OID GSS_C_NT_MACHINE_UID_NAME = &gss_c_nt_machine_uid_name_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_string_uid_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ "\x01\x02\x01\x03"};
+
+gss_OID GSS_C_NT_STRING_UID_NAME = &gss_c_nt_string_uid_name_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)). The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc. This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+
+static gss_OID_desc gss_c_nt_hostbased_service_x_oid_desc =
+{6, (void *)"\x2b\x06\x01\x05\x06\x02"};
+
+gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = &gss_c_nt_hostbased_service_x_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}. The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+static gss_OID_desc gss_c_nt_hostbased_service_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x04"};
+
+gss_OID GSS_C_NT_HOSTBASED_SERVICE = &gss_c_nt_hostbased_service_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}. The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_anonymous_oid_desc =
+{6, (void *)"\x2b\x06\01\x05\x06\x03"};
+
+gss_OID GSS_C_NT_ANONYMOUS = &gss_c_nt_anonymous_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}. The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_export_name_oid_desc =
+{6, (void *)"\x2b\x06\x01\x05\x06\x04"};
+
+gss_OID GSS_C_NT_EXPORT_NAME = &gss_c_nt_export_name_oid_desc;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME".
+ */
+
+static gss_OID_desc gss_krb5_nt_principal_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
+
+gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &gss_krb5_nt_principal_name_oid_desc;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1)}. The recommended symbolic name for this
+ * type is "GSS_KRB5_NT_USER_NAME".
+ */
+
+gss_OID GSS_KRB5_NT_USER_NAME = &gss_c_nt_user_name_oid_desc;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_MACHINE_UID_NAME".
+ */
+
+gss_OID GSS_KRB5_NT_MACHINE_UID_NAME = &gss_c_nt_machine_uid_name_oid_desc;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_STRING_UID_NAME".
+ */
+
+gss_OID GSS_KRB5_NT_STRING_UID_NAME = &gss_c_nt_string_uid_name_oid_desc;
+
+/*
+ * To support ongoing experimentation, testing, and evolution of the
+ * specification, the Kerberos V5 GSS-API mechanism as defined in this
+ * and any successor memos will be identified with the following Object
+ * Identifier, as defined in RFC-1510, until the specification is
+ * advanced to the level of Proposed Standard RFC:
+ *
+ * {iso(1), org(3), dod(5), internet(1), security(5), kerberosv5(2)}
+ *
+ * Upon advancement to the level of Proposed Standard RFC, the Kerberos
+ * V5 GSS-API mechanism will be identified by an Object Identifier
+ * having the value:
+ *
+ * {iso(1) member-body(2) United States(840) mit(113554) infosys(1)
+ * gssapi(2) krb5(2)}
+ */
+
+#if 0 /* This is the old OID */
+
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+{5, (void *)"\x2b\x05\x01\x05\x02"};
+
+#endif
+
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+
+gss_OID GSS_KRB5_MECHANISM = &gss_krb5_mechanism_oid_desc;
+
+/*
+ * RFC2478, SPNEGO:
+ * The security mechanism of the initial
+ * negotiation token is identified by the Object Identifier
+ * iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2).
+ */
+
+static gss_OID_desc gss_spnego_mechanism_oid_desc =
+{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+
+gss_OID GSS_SPNEGO_MECHANISM = &gss_spnego_mechanism_oid_desc;
+
+/*
+ * draft-ietf-cat-iakerb-09, IAKERB:
+ * The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance
+ * with the mechanism proposed by SPNEGO [7] for negotiating protocol
+ * variations, is: {iso(1) org(3) dod(6) internet(1) security(5)
+ * mechanisms(5) iakerb(10) iakerbProxyProtocol(1)}. The proposed
+ * mechanism ID for IAKERB minimum messages GSS-API Kerberos, in
+ * accordance with the mechanism proposed by SPNEGO for negotiating
+ * protocol variations, is: {iso(1) org(3) dod(6) internet(1)
+ * security(5) mechanisms(5) iakerb(10)
+ * iakerbMinimumMessagesProtocol(2)}.
+ */
+
+static gss_OID_desc gss_iakerb_proxy_mechanism_oid_desc =
+{7, (void *)"\x2b\x06\x01\x05\x05\x0a\x01"};
+
+gss_OID GSS_IAKERB_PROXY_MECHANISM = &gss_iakerb_proxy_mechanism_oid_desc;
+
+static gss_OID_desc gss_iakerb_min_msg_mechanism_oid_desc =
+{7, (void *)"\x2b\x06\x01\x05\x05\x0a\x02"};
+
+gss_OID GSS_IAKERB_MIN_MSG_MECHANISM = &gss_iakerb_min_msg_mechanism_oid_desc;
+
+/*
+ * Context for krb5 calls.
+ */
+
+krb5_context gssapi_krb5_context;
diff --git a/source4/heimdal/lib/gssapi/get_mic.c b/source4/heimdal/lib/gssapi/get_mic.c
new file mode 100644
index 0000000000..1c950e95d9
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/get_mic.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: get_mic.c,v 1.29 2005/01/05 02:52:12 lukeh Exp $");
+
+static OM_uint32
+mic_des
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ krb5_keyblock *key
+ )
+{
+ u_char *p;
+ MD5_CTX md5;
+ u_char hash[16];
+ DES_key_schedule schedule;
+ DES_cblock deskey;
+ DES_cblock zero;
+ int32_t seq_number;
+ size_t len, total_len;
+
+ gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ message_token->length = total_len;
+ message_token->value = malloc (total_len);
+ if (message_token->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = gssapi_krb5_make_header(message_token->value,
+ len,
+ "\x01\x01", /* TOK_ID */
+ GSS_KRB5_MECHANISM);
+
+ memcpy (p, "\x00\x00", 2); /* SGN_ALG = DES MAC MD5 */
+ p += 2;
+
+ memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
+ p += 4;
+
+ /* Fill in later (SND-SEQ) */
+ memset (p, 0, 16);
+ p += 16;
+
+ /* checksum */
+ MD5_Init (&md5);
+ MD5_Update (&md5, p - 24, 8);
+ MD5_Update (&md5, message_buffer->value, message_buffer->length);
+ MD5_Final (hash, &md5);
+
+ memset (&zero, 0, sizeof(zero));
+ memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+ &schedule, &zero);
+ memcpy (p - 8, hash, 8); /* SGN_CKSUM */
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ /* sequence number */
+ krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+
+ p -= 16; /* SND_SEQ */
+ p[0] = (seq_number >> 0) & 0xFF;
+ p[1] = (seq_number >> 8) & 0xFF;
+ p[2] = (seq_number >> 16) & 0xFF;
+ p[3] = (seq_number >> 24) & 0xFF;
+ memset (p + 4,
+ (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+ 4);
+
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_encrypt ((void *)p, (void *)p, 8,
+ &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
+
+ krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ memset (deskey, 0, sizeof(deskey));
+ memset (&schedule, 0, sizeof(schedule));
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+mic_des3
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ krb5_keyblock *key
+ )
+{
+ u_char *p;
+ Checksum cksum;
+ u_char seq[8];
+
+ int32_t seq_number;
+ size_t len, total_len;
+
+ krb5_crypto crypto;
+ krb5_error_code kret;
+ krb5_data encdata;
+ char *tmp;
+ char ivec[8];
+
+ gssapi_krb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ message_token->length = total_len;
+ message_token->value = malloc (total_len);
+ if (message_token->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = gssapi_krb5_make_header(message_token->value,
+ len,
+ "\x01\x01", /* TOK-ID */
+ GSS_KRB5_MECHANISM);
+
+ memcpy (p, "\x04\x00", 2); /* SGN_ALG = HMAC SHA1 DES3-KD */
+ p += 2;
+
+ memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
+ p += 4;
+
+ /* this should be done in parts */
+
+ tmp = malloc (message_buffer->length + 8);
+ if (tmp == NULL) {
+ free (message_token->value);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy (tmp, p - 8, 8);
+ memcpy (tmp + 8, message_buffer->value, message_buffer->length);
+
+ kret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (kret) {
+ free (message_token->value);
+ free (tmp);
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_create_checksum (gssapi_krb5_context,
+ crypto,
+ KRB5_KU_USAGE_SIGN,
+ 0,
+ tmp,
+ message_buffer->length + 8,
+ &cksum);
+ free (tmp);
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ if (kret) {
+ free (message_token->value);
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ /* sequence number */
+ krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+
+ seq[0] = (seq_number >> 0) & 0xFF;
+ seq[1] = (seq_number >> 8) & 0xFF;
+ seq[2] = (seq_number >> 16) & 0xFF;
+ seq[3] = (seq_number >> 24) & 0xFF;
+ memset (seq + 4,
+ (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+ 4);
+
+ kret = krb5_crypto_init(gssapi_krb5_context, key,
+ ETYPE_DES3_CBC_NONE, &crypto);
+ if (kret) {
+ free (message_token->value);
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ if (context_handle->more_flags & COMPAT_OLD_DES3)
+ memset(ivec, 0, 8);
+ else
+ memcpy(ivec, p + 8, 8);
+
+ kret = krb5_encrypt_ivec (gssapi_krb5_context,
+ crypto,
+ KRB5_KU_USAGE_SEQ,
+ seq, 8, &encdata, ivec);
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ if (kret) {
+ free (message_token->value);
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ assert (encdata.length == 8);
+
+ memcpy (p, encdata.data, encdata.length);
+ krb5_data_free (&encdata);
+
+ krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ free_Checksum (&cksum);
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_get_mic
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token
+ )
+{
+ krb5_keyblock *key;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+
+ ret = gss_krb5_get_subkey(context_handle, &key);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+ switch (keytype) {
+ case KEYTYPE_DES :
+ ret = mic_des (minor_status, context_handle, qop_req,
+ message_buffer, message_token, key);
+ break;
+ case KEYTYPE_DES3 :
+ ret = mic_des3 (minor_status, context_handle, qop_req,
+ message_buffer, message_token, key);
+ break;
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_get_mic_arcfour (minor_status, context_handle, qop_req,
+ message_buffer, message_token, key);
+ break;
+ default :
+ ret = _gssapi_mic_cfx (minor_status, context_handle, qop_req,
+ message_buffer, message_token, key);
+ break;
+ }
+ krb5_free_keyblock (gssapi_krb5_context, key);
+ return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi.h
new file mode 100644
index 0000000000..5712581d3f
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/gssapi.h
@@ -0,0 +1,826 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: gssapi.h,v 1.37 2005/02/21 08:48:15 lukeh Exp $ */
+
+#ifndef GSSAPI_H_
+#define GSSAPI_H_
+
+/*
+ * First, include stddef.h to get size_t defined.
+ */
+#include <stddef.h>
+
+#include <krb5-types.h>
+
+/*
+ * Now define the three implementation-dependent types.
+ */
+
+typedef u_int32_t OM_uint32;
+
+typedef u_int32_t gss_uint32;
+
+/*
+ * This is to avoid having to include <krb5.h>
+ */
+
+struct krb5_auth_context_data;
+
+struct Principal;
+
+/* typedef void *gss_name_t; */
+
+typedef struct Principal *gss_name_t;
+
+struct gss_ctx_id_t_desc_struct;
+typedef struct gss_ctx_id_t_desc_struct *gss_ctx_id_t;
+
+typedef struct gss_OID_desc_struct {
+ OM_uint32 length;
+ void *elements;
+} gss_OID_desc, *gss_OID;
+
+typedef struct gss_OID_set_desc_struct {
+ size_t count;
+ gss_OID elements;
+} gss_OID_set_desc, *gss_OID_set;
+
+struct krb5_keytab_data;
+
+struct krb5_ccache_data;
+
+typedef int gss_cred_usage_t;
+
+struct gss_cred_id_t_desc_struct;
+typedef struct gss_cred_id_t_desc_struct *gss_cred_id_t;
+
+typedef struct gss_buffer_desc_struct {
+ size_t length;
+ void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef struct gss_channel_bindings_struct {
+ OM_uint32 initiator_addrtype;
+ gss_buffer_desc initiator_address;
+ OM_uint32 acceptor_addrtype;
+ gss_buffer_desc acceptor_address;
+ gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+/*
+ * For now, define a QOP-type as an OM_uint32
+ */
+typedef OM_uint32 gss_qop_t;
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG 1 /* 0x00000001 */
+#define GSS_C_MUTUAL_FLAG 2 /* 0x00000002 */
+#define GSS_C_REPLAY_FLAG 4 /* 0x00000004 */
+#define GSS_C_SEQUENCE_FLAG 8 /* 0x00000008 */
+#define GSS_C_CONF_FLAG 16 /* 0x00000010 */
+#define GSS_C_INTEG_FLAG 32 /* 0x00000020 */
+#define GSS_C_ANON_FLAG 64 /* 0x00000040 */
+#define GSS_C_PROT_READY_FLAG 128 /* 0x00000080 */
+#define GSS_C_TRANS_FLAG 256 /* 0x00000100 */
+
+/* these are from draft-brezak-win2k-krb-rc4-hmac-04.txt */
+#define GSS_C_DCE_STYLE 4096 /* 0x00001000 */
+#define GSS_C_IDENTIFY_FLAG 8192 /* 0x00002000 */
+#define GSS_C_EXTENDED_ERROR_FLAG 16384 /* 0x00004000 */
+
+/*
+ * Credential usage options
+ */
+#define GSS_C_BOTH 0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT 2
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+/*
+ * The constant definitions for channel-bindings address families
+ */
+#define GSS_C_AF_UNSPEC 0
+#define GSS_C_AF_LOCAL 1
+#define GSS_C_AF_INET 2
+#define GSS_C_AF_IMPLINK 3
+#define GSS_C_AF_PUP 4
+#define GSS_C_AF_CHAOS 5
+#define GSS_C_AF_NS 6
+#define GSS_C_AF_NBS 7
+#define GSS_C_AF_ECMA 8
+#define GSS_C_AF_DATAKIT 9
+#define GSS_C_AF_CCITT 10
+#define GSS_C_AF_SNA 11
+#define GSS_C_AF_DECnet 12
+#define GSS_C_AF_DLI 13
+#define GSS_C_AF_LAT 14
+#define GSS_C_AF_HYLINK 15
+#define GSS_C_AF_APPLETALK 16
+#define GSS_C_AF_BSC 17
+#define GSS_C_AF_DSS 18
+#define GSS_C_AF_OSI 19
+#define GSS_C_AF_X25 21
+#define GSS_C_AF_INET6 24
+
+#define GSS_C_AF_NULLADDR 255
+
+/*
+ * Various Null values
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Some alternate names for a couple of the above
+ * values. These are defined for V1 compatibility.
+ */
+#define GSS_C_NULL_OID GSS_C_NO_OID
+#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
+
+/*
+ * Define the default Quality of Protection for per-message
+ * services. Note that an implementation that offers multiple
+ * levels of QOP may define GSS_C_QOP_DEFAULT to be either zero
+ * (as done here) to mean "default protection", or to a specific
+ * explicit QOP value. However, a value of 0 should always be
+ * interpreted by a GSSAPI implementation as a request for the
+ * default protection level.
+ */
+#define GSS_C_QOP_DEFAULT 0
+
+#define GSS_KRB5_CONF_C_QOP_DES 0x0100
+#define GSS_KRB5_CONF_C_QOP_DES3_KD 0x0200
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE 0xfffffffful
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_USER_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_STRING_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)). The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc. This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}. The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}. The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_ANONYMOUS;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}. The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_EXPORT_NAME;
+
+/*
+ * RFC2478, SPNEGO:
+ * The security mechanism of the initial
+ * negotiation token is identified by the Object Identifier
+ * iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2).
+ */
+extern gss_OID GSS_SPNEGO_MECHANISM;
+
+/*
+ * This if for kerberos5 names.
+ */
+
+extern gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
+extern gss_OID GSS_KRB5_NT_USER_NAME;
+extern gss_OID GSS_KRB5_NT_MACHINE_UID_NAME;
+extern gss_OID GSS_KRB5_NT_STRING_UID_NAME;
+
+extern gss_OID GSS_KRB5_MECHANISM;
+
+/* for compatibility with MIT api */
+
+#define gss_mech_krb5 GSS_KRB5_MECHANISM
+#define gss_krb5_nt_general_name GSS_KRB5_NT_PRINCIPAL_NAME
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK 0377ul
+#define GSS_C_ROUTINE_ERROR_MASK 0377ul
+#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
+
+/*
+ * The macros that test status codes for error conditions.
+ * Note that the GSS_ERROR() macro has changed slightly from
+ * the V1 GSSAPI so that it now evaluates its argument
+ * only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+ (x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+ (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+ (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+ (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+ (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Now the actual status code definitions
+ */
+
+/*
+ * Calling errors:
+ */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+ (1ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+ (2ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+ (3ul << GSS_C_CALLING_ERROR_OFFSET)
+
+/*
+ * Routine errors:
+ */
+#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET)
+
+#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MIC GSS_S_BAD_SIG
+#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET)
+
+/*
+ * Supplementary info bits:
+ */
+#define GSS_S_CONTINUE_NEEDED (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+/*
+ * From RFC1964:
+ *
+ * 4.1.1. Non-Kerberos-specific codes
+ */
+
+#define GSS_KRB5_S_G_BAD_SERVICE_NAME 1
+ /* "No @ in SERVICE-NAME name string" */
+#define GSS_KRB5_S_G_BAD_STRING_UID 2
+ /* "STRING-UID-NAME contains nondigits" */
+#define GSS_KRB5_S_G_NOUSER 3
+ /* "UID does not resolve to username" */
+#define GSS_KRB5_S_G_VALIDATE_FAILED 4
+ /* "Validation error" */
+#define GSS_KRB5_S_G_BUFFER_ALLOC 5
+ /* "Couldn't allocate gss_buffer_t data" */
+#define GSS_KRB5_S_G_BAD_MSG_CTX 6
+ /* "Message context invalid" */
+#define GSS_KRB5_S_G_WRONG_SIZE 7
+ /* "Buffer is the wrong size" */
+#define GSS_KRB5_S_G_BAD_USAGE 8
+ /* "Credential usage type is unknown" */
+#define GSS_KRB5_S_G_UNKNOWN_QOP 9
+ /* "Unknown quality of protection specified" */
+
+ /*
+ * 4.1.2. Kerberos-specific-codes
+ */
+
+#define GSS_KRB5_S_KG_CCACHE_NOMATCH 10
+ /* "Principal in credential cache does not match desired name" */
+#define GSS_KRB5_S_KG_KEYTAB_NOMATCH 11
+ /* "No principal in keytab matches desired name" */
+#define GSS_KRB5_S_KG_TGT_MISSING 12
+ /* "Credential cache has no TGT" */
+#define GSS_KRB5_S_KG_NO_SUBKEY 13
+ /* "Authenticator has no subkey" */
+#define GSS_KRB5_S_KG_CONTEXT_ESTABLISHED 14
+ /* "Context is already fully established" */
+#define GSS_KRB5_S_KG_BAD_SIGN_TYPE 15
+ /* "Unknown signature type in token" */
+#define GSS_KRB5_S_KG_BAD_LENGTH 16
+ /* "Invalid field length in token" */
+#define GSS_KRB5_S_KG_CTX_INCOMPLETE 17
+ /* "Attempt to use incomplete security context" */
+
+/*
+ * Finally, function prototypes for the GSS-API routines.
+ */
+
+
+OM_uint32 gss_acquire_cred
+ (OM_uint32 * /*minor_status*/,
+ const gss_name_t /*desired_name*/,
+ OM_uint32 /*time_req*/,
+ const gss_OID_set /*desired_mechs*/,
+ gss_cred_usage_t /*cred_usage*/,
+ gss_cred_id_t * /*output_cred_handle*/,
+ gss_OID_set * /*actual_mechs*/,
+ OM_uint32 * /*time_rec*/
+ );
+
+OM_uint32 gss_release_cred
+ (OM_uint32 * /*minor_status*/,
+ gss_cred_id_t * /*cred_handle*/
+ );
+
+OM_uint32 gss_init_sec_context
+ (OM_uint32 * /*minor_status*/,
+ const gss_cred_id_t /*initiator_cred_handle*/,
+ gss_ctx_id_t * /*context_handle*/,
+ const gss_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*/
+ );
+
+OM_uint32 gss_accept_sec_context
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t * /*context_handle*/,
+ const gss_cred_id_t /*acceptor_cred_handle*/,
+ const gss_buffer_t /*input_token_buffer*/,
+ const gss_channel_bindings_t /*input_chan_bindings*/,
+ gss_name_t * /*src_name*/,
+ gss_OID * /*mech_type*/,
+ gss_buffer_t /*output_token*/,
+ OM_uint32 * /*ret_flags*/,
+ OM_uint32 * /*time_rec*/,
+ gss_cred_id_t * /*delegated_cred_handle*/
+ );
+
+OM_uint32 gss_process_context_token
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ const gss_buffer_t /*token_buffer*/
+ );
+
+OM_uint32 gss_delete_sec_context
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t * /*context_handle*/,
+ gss_buffer_t /*output_token*/
+ );
+
+OM_uint32 gss_context_time
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ OM_uint32 * /*time_rec*/
+ );
+
+OM_uint32 gss_get_mic
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ gss_qop_t /*qop_req*/,
+ const gss_buffer_t /*message_buffer*/,
+ gss_buffer_t /*message_token*/
+ );
+
+OM_uint32 gss_verify_mic
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ const gss_buffer_t /*message_buffer*/,
+ const gss_buffer_t /*token_buffer*/,
+ gss_qop_t * /*qop_state*/
+ );
+
+OM_uint32 gss_wrap
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ gss_qop_t /*qop_req*/,
+ const gss_buffer_t /*input_message_buffer*/,
+ int * /*conf_state*/,
+ gss_buffer_t /*output_message_buffer*/
+ );
+
+OM_uint32 gss_unwrap
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ const gss_buffer_t /*input_message_buffer*/,
+ gss_buffer_t /*output_message_buffer*/,
+ int * /*conf_state*/,
+ gss_qop_t * /*qop_state*/
+ );
+
+OM_uint32 gss_display_status
+ (OM_uint32 * /*minor_status*/,
+ OM_uint32 /*status_value*/,
+ int /*status_type*/,
+ const gss_OID /*mech_type*/,
+ OM_uint32 * /*message_context*/,
+ gss_buffer_t /*status_string*/
+ );
+
+OM_uint32 gss_indicate_mechs
+ (OM_uint32 * /*minor_status*/,
+ gss_OID_set * /*mech_set*/
+ );
+
+OM_uint32 gss_compare_name
+ (OM_uint32 * /*minor_status*/,
+ const gss_name_t /*name1*/,
+ const gss_name_t /*name2*/,
+ int * /*name_equal*/
+ );
+
+OM_uint32 gss_display_name
+ (OM_uint32 * /*minor_status*/,
+ const gss_name_t /*input_name*/,
+ gss_buffer_t /*output_name_buffer*/,
+ gss_OID * /*output_name_type*/
+ );
+
+OM_uint32 gss_import_name
+ (OM_uint32 * /*minor_status*/,
+ const gss_buffer_t /*input_name_buffer*/,
+ const gss_OID /*input_name_type*/,
+ gss_name_t * /*output_name*/
+ );
+
+OM_uint32 gss_export_name
+ (OM_uint32 * /*minor_status*/,
+ const gss_name_t /*input_name*/,
+ gss_buffer_t /*exported_name*/
+ );
+
+OM_uint32 gss_release_name
+ (OM_uint32 * /*minor_status*/,
+ gss_name_t * /*input_name*/
+ );
+
+OM_uint32 gss_release_buffer
+ (OM_uint32 * /*minor_status*/,
+ gss_buffer_t /*buffer*/
+ );
+
+OM_uint32 gss_release_oid_set
+ (OM_uint32 * /*minor_status*/,
+ gss_OID_set * /*set*/
+ );
+
+OM_uint32 gss_inquire_cred
+ (OM_uint32 * /*minor_status*/,
+ const gss_cred_id_t /*cred_handle*/,
+ gss_name_t * /*name*/,
+ OM_uint32 * /*lifetime*/,
+ gss_cred_usage_t * /*cred_usage*/,
+ gss_OID_set * /*mechanisms*/
+ );
+
+OM_uint32 gss_inquire_context (
+ OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ gss_name_t * /*src_name*/,
+ gss_name_t * /*targ_name*/,
+ OM_uint32 * /*lifetime_rec*/,
+ gss_OID * /*mech_type*/,
+ OM_uint32 * /*ctx_flags*/,
+ int * /*locally_initiated*/,
+ int * /*open_context*/
+ );
+
+OM_uint32 gss_wrap_size_limit (
+ OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ gss_qop_t /*qop_req*/,
+ OM_uint32 /*req_output_size*/,
+ OM_uint32 * /*max_input_size*/
+ );
+
+OM_uint32 gss_add_cred (
+ OM_uint32 * /*minor_status*/,
+ const gss_cred_id_t /*input_cred_handle*/,
+ const gss_name_t /*desired_name*/,
+ const gss_OID /*desired_mech*/,
+ gss_cred_usage_t /*cred_usage*/,
+ OM_uint32 /*initiator_time_req*/,
+ OM_uint32 /*acceptor_time_req*/,
+ gss_cred_id_t * /*output_cred_handle*/,
+ gss_OID_set * /*actual_mechs*/,
+ OM_uint32 * /*initiator_time_rec*/,
+ OM_uint32 * /*acceptor_time_rec*/
+ );
+
+OM_uint32 gss_inquire_cred_by_mech (
+ OM_uint32 * /*minor_status*/,
+ const gss_cred_id_t /*cred_handle*/,
+ const gss_OID /*mech_type*/,
+ gss_name_t * /*name*/,
+ OM_uint32 * /*initiator_lifetime*/,
+ OM_uint32 * /*acceptor_lifetime*/,
+ gss_cred_usage_t * /*cred_usage*/
+ );
+
+OM_uint32 gss_export_sec_context (
+ OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t * /*context_handle*/,
+ gss_buffer_t /*interprocess_token*/
+ );
+
+OM_uint32 gss_import_sec_context (
+ OM_uint32 * /*minor_status*/,
+ const gss_buffer_t /*interprocess_token*/,
+ gss_ctx_id_t * /*context_handle*/
+ );
+
+OM_uint32 gss_create_empty_oid_set (
+ OM_uint32 * /*minor_status*/,
+ gss_OID_set * /*oid_set*/
+ );
+
+OM_uint32 gss_add_oid_set_member (
+ OM_uint32 * /*minor_status*/,
+ const gss_OID /*member_oid*/,
+ gss_OID_set * /*oid_set*/
+ );
+
+OM_uint32 gss_test_oid_set_member (
+ OM_uint32 * /*minor_status*/,
+ const gss_OID /*member*/,
+ const gss_OID_set /*set*/,
+ int * /*present*/
+ );
+
+OM_uint32 gss_inquire_names_for_mech (
+ OM_uint32 * /*minor_status*/,
+ const gss_OID /*mechanism*/,
+ gss_OID_set * /*name_types*/
+ );
+
+OM_uint32 gss_inquire_mechs_for_name (
+ OM_uint32 * /*minor_status*/,
+ const gss_name_t /*input_name*/,
+ gss_OID_set * /*mech_types*/
+ );
+
+OM_uint32 gss_canonicalize_name (
+ OM_uint32 * /*minor_status*/,
+ const gss_name_t /*input_name*/,
+ const gss_OID /*mech_type*/,
+ gss_name_t * /*output_name*/
+ );
+
+OM_uint32 gss_duplicate_name (
+ OM_uint32 * /*minor_status*/,
+ const gss_name_t /*src_name*/,
+ gss_name_t * /*dest_name*/
+ );
+
+/*
+ * The following routines are obsolete variants of gss_get_mic,
+ * gss_verify_mic, gss_wrap and gss_unwrap. They should be
+ * provided by GSSAPI V2 implementations for backwards
+ * compatibility with V1 applications. Distinct entrypoints
+ * (as opposed to #defines) should be provided, both to allow
+ * GSSAPI V1 applications to link against GSSAPI V2 implementations,
+ * and to retain the slight parameter type differences between the
+ * obsolete versions of these routines and their current forms.
+ */
+
+OM_uint32 gss_sign
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ int /*qop_req*/,
+ gss_buffer_t /*message_buffer*/,
+ gss_buffer_t /*message_token*/
+ );
+
+OM_uint32 gss_verify
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ gss_buffer_t /*message_buffer*/,
+ gss_buffer_t /*token_buffer*/,
+ int * /*qop_state*/
+ );
+
+OM_uint32 gss_seal
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ int /*qop_req*/,
+ gss_buffer_t /*input_message_buffer*/,
+ int * /*conf_state*/,
+ gss_buffer_t /*output_message_buffer*/
+ );
+
+OM_uint32 gss_unseal
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ gss_buffer_t /*input_message_buffer*/,
+ gss_buffer_t /*output_message_buffer*/,
+ int * /*conf_state*/,
+ int * /*qop_state*/
+ );
+
+/*
+ * kerberos mechanism specific functions
+ */
+
+OM_uint32 gsskrb5_acquire_cred
+ (OM_uint32 * minor_status,
+ struct krb5_keytab_data *keytab,
+ struct krb5_ccache_data *ccache,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t * output_cred_handle,
+ gss_OID_set * actual_mechs,
+ OM_uint32 * time_rec
+ );
+
+OM_uint32
+gss_krb5_ccache_name(OM_uint32 * /*minor_status*/,
+ const char * /*name */,
+ const char ** /*out_name */);
+
+OM_uint32 gsskrb5_register_acceptor_identity
+ (const char */*identity*/);
+
+OM_uint32 gss_krb5_copy_ccache
+ (OM_uint32 */*minor*/,
+ gss_cred_id_t /*cred*/,
+ struct krb5_ccache_data */*out*/);
+
+OM_uint32 gss_krb5_copy_service_keyblock
+ (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ struct EncryptionKey **out);
+
+OM_uint32 gss_krb5_get_tkt_flags
+ (OM_uint32 */*minor*/,
+ gss_ctx_id_t /*context_handle*/,
+ OM_uint32 */*tkt_flags*/);
+
+OM_uint32
+gsskrb5_extract_authz_data_from_sec_context
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t /*context_handle*/,
+ int /*ad_type*/,
+ gss_buffer_t /*ad_data*/);
+OM_uint32
+gsskrb5_get_initiator_subkey
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t context_handle,
+ gss_buffer_t /* subkey */);
+
+#define GSS_C_KRB5_COMPAT_DES3_MIC 1
+
+OM_uint32
+gss_krb5_compat_des3_mic(OM_uint32 *, gss_ctx_id_t, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GSSAPI_H_ */
diff --git a/source4/heimdal/lib/gssapi/gssapi_locl.h b/source4/heimdal/lib/gssapi/gssapi_locl.h
new file mode 100644
index 0000000000..47a37e4657
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/gssapi_locl.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: gssapi_locl.h,v 1.40 2005/06/16 20:34:03 lha Exp $ */
+
+#ifndef GSSAPI_LOCL_H
+#define GSSAPI_LOCL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <krb5_locl.h>
+#include <gssapi.h>
+#include <assert.h>
+
+#include "cfx.h"
+#include "arcfour.h"
+
+#include "spnego_asn1.h"
+
+/*
+ *
+ */
+
+struct gss_msg_order;
+
+typedef struct gss_ctx_id_t_desc_struct {
+ struct krb5_auth_context_data *auth_context;
+ gss_name_t source, target;
+ enum gss_ctx_id_t_state {
+ INITIATOR_START = 1, INITIATOR_WAIT_FOR_MUTAL = 2, INITIATOR_READY= 3,
+ ACCEPTOR_START = 11, ACCEPTOR_WAIT_FOR_DCESTYLE = 12, ACCEPTOR_READY = 13
+ } state;
+ OM_uint32 flags;
+ enum {LOCAL = 1,
+ OPEN = 2,
+ COMPAT_OLD_DES3 = 4,
+ COMPAT_OLD_DES3_SELECTED = 8,
+ ACCEPTOR_SUBKEY = 16
+ } more_flags;
+ struct krb5_ticket *ticket;
+ krb5_keyblock *service_keyblock;
+ krb5_data fwd_data;
+ OM_uint32 lifetime;
+ HEIMDAL_MUTEX ctx_id_mutex;
+ struct gss_msg_order *order;
+} gss_ctx_id_t_desc;
+
+typedef struct gss_cred_id_t_desc_struct {
+ gss_name_t principal;
+ krb5_boolean made_keytab;
+ struct krb5_keytab_data *keytab;
+ OM_uint32 lifetime;
+ gss_cred_usage_t usage;
+ gss_OID_set mechanisms;
+ krb5_boolean made_ccache;
+ struct krb5_ccache_data *ccache;
+ HEIMDAL_MUTEX cred_id_mutex;
+} gss_cred_id_t_desc;
+
+/*
+ *
+ */
+
+extern krb5_context gssapi_krb5_context;
+
+extern krb5_keytab gssapi_krb5_keytab;
+extern HEIMDAL_MUTEX gssapi_keytab_mutex;
+
+struct gssapi_thr_context {
+ HEIMDAL_MUTEX mutex;
+ char *error_string;
+};
+
+/*
+ * Prototypes
+ */
+
+krb5_error_code gssapi_krb5_init (void);
+
+#define GSSAPI_KRB5_INIT() do { \
+ krb5_error_code kret_gss_init; \
+ if((kret_gss_init = gssapi_krb5_init ()) != 0) { \
+ *minor_status = kret_gss_init; \
+ return GSS_S_FAILURE; \
+ } \
+} while (0)
+
+struct gssapi_thr_context *
+gssapi_get_thread_context(int);
+
+OM_uint32
+_gsskrb5_create_ctx(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_channel_bindings_t input_chan_bindings,
+ enum gss_ctx_id_t_state state);
+
+void
+gsskrb5_is_cfx(gss_ctx_id_t, int *);
+
+OM_uint32
+gssapi_krb5_create_8003_checksum (
+ OM_uint32 *minor_status,
+ const gss_channel_bindings_t input_chan_bindings,
+ OM_uint32 flags,
+ const krb5_data *fwd_data,
+ Checksum *result);
+
+OM_uint32
+gssapi_krb5_verify_8003_checksum (
+ OM_uint32 *minor_status,
+ const gss_channel_bindings_t input_chan_bindings,
+ const Checksum *cksum,
+ OM_uint32 *flags,
+ krb5_data *fwd_data);
+
+void
+_gssapi_encap_length (size_t data_len,
+ size_t *len,
+ size_t *total_len,
+ const gss_OID mech);
+
+void
+gssapi_krb5_encap_length (size_t data_len,
+ size_t *len,
+ size_t *total_len,
+ const gss_OID mech);
+
+
+
+OM_uint32
+_gssapi_encapsulate(OM_uint32 *minor_status,
+ const krb5_data *in_data,
+ gss_buffer_t output_token,
+ const gss_OID mech);
+
+
+OM_uint32
+gssapi_krb5_encapsulate(OM_uint32 *minor_status,
+ const krb5_data *in_data,
+ gss_buffer_t output_token,
+ const u_char *type,
+ const gss_OID mech);
+
+OM_uint32
+gssapi_krb5_decapsulate(OM_uint32 *minor_status,
+ gss_buffer_t input_token_buffer,
+ krb5_data *out_data,
+ const char *type,
+ gss_OID oid);
+
+u_char *
+gssapi_krb5_make_header (u_char *p,
+ size_t len,
+ const u_char *type,
+ const gss_OID mech);
+
+u_char *
+_gssapi_make_mech_header(u_char *p,
+ size_t len,
+ const gss_OID mech);
+
+OM_uint32
+_gssapi_verify_mech_header(u_char **str,
+ size_t total_len,
+ gss_OID oid);
+
+OM_uint32
+gssapi_krb5_verify_header(u_char **str,
+ size_t total_len,
+ const u_char *type,
+ gss_OID oid);
+
+OM_uint32
+_gssapi_decapsulate(OM_uint32 *minor_status,
+ gss_buffer_t input_token_buffer,
+ krb5_data *out_data,
+ const gss_OID mech);
+
+
+ssize_t
+gssapi_krb5_get_mech (const u_char *, size_t, const u_char **);
+
+OM_uint32
+_gssapi_verify_pad(gss_buffer_t, size_t, size_t *);
+
+OM_uint32
+gss_verify_mic_internal(OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t * qop_state,
+ char * type);
+
+OM_uint32
+gss_krb5_get_subkey(const gss_ctx_id_t context_handle,
+ krb5_keyblock **key);
+
+krb5_error_code
+gss_address_to_krb5addr(OM_uint32 gss_addr_type,
+ gss_buffer_desc *gss_addr,
+ int16_t port,
+ krb5_address *address);
+
+/* sec_context flags */
+
+#define SC_LOCAL_ADDRESS 0x01
+#define SC_REMOTE_ADDRESS 0x02
+#define SC_KEYBLOCK 0x04
+#define SC_LOCAL_SUBKEY 0x08
+#define SC_REMOTE_SUBKEY 0x10
+
+int
+gss_oid_equal(const gss_OID a, const gss_OID b);
+
+void
+gssapi_krb5_set_error_string (void);
+
+char *
+gssapi_krb5_get_error_string (void);
+
+OM_uint32
+_gss_DES3_get_mic_compat(OM_uint32 *, gss_ctx_id_t);
+
+OM_uint32
+_gss_spnego_require_mechlist_mic(OM_uint32 *, gss_ctx_id_t, krb5_boolean *);
+
+krb5_error_code
+_gss_check_compat(OM_uint32 *, gss_name_t, const char *,
+ krb5_boolean *, krb5_boolean);
+
+OM_uint32
+gssapi_lifetime_left(OM_uint32 *, OM_uint32, OM_uint32 *);
+
+/* sequence */
+
+OM_uint32
+_gssapi_msg_order_create(OM_uint32 *, struct gss_msg_order **,
+ OM_uint32, OM_uint32, OM_uint32, int);
+OM_uint32
+_gssapi_msg_order_destroy(struct gss_msg_order **);
+
+OM_uint32
+_gssapi_msg_order_check(struct gss_msg_order *, OM_uint32);
+
+OM_uint32
+_gssapi_msg_order_f(OM_uint32);
+
+/* 8003 */
+
+krb5_error_code
+gssapi_encode_om_uint32(OM_uint32, u_char *);
+
+krb5_error_code
+gssapi_encode_be_om_uint32(OM_uint32, u_char *);
+
+krb5_error_code
+gssapi_decode_om_uint32(u_char *, OM_uint32 *);
+
+krb5_error_code
+gssapi_decode_be_om_uint32(u_char *, OM_uint32 *);
+
+#endif
diff --git a/source4/heimdal/lib/gssapi/import_name.c b/source4/heimdal/lib/gssapi/import_name.c
new file mode 100644
index 0000000000..423e757146
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/import_name.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: import_name.c,v 1.13 2003/03/16 17:33:31 lha Exp $");
+
+static OM_uint32
+parse_krb5_name (OM_uint32 *minor_status,
+ const char *name,
+ gss_name_t *output_name)
+{
+ krb5_error_code kerr;
+
+ kerr = krb5_parse_name (gssapi_krb5_context, name, output_name);
+
+ if (kerr == 0)
+ return GSS_S_COMPLETE;
+ else if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kerr;
+ return GSS_S_BAD_NAME;
+ } else {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
+}
+
+static OM_uint32
+import_krb5_name (OM_uint32 *minor_status,
+ const gss_buffer_t input_name_buffer,
+ gss_name_t *output_name)
+{
+ OM_uint32 ret;
+ char *tmp;
+
+ tmp = malloc (input_name_buffer->length + 1);
+ if (tmp == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy (tmp,
+ input_name_buffer->value,
+ input_name_buffer->length);
+ tmp[input_name_buffer->length] = '\0';
+
+ ret = parse_krb5_name(minor_status, tmp, output_name);
+ free(tmp);
+
+ return ret;
+}
+
+static OM_uint32
+import_hostbased_name (OM_uint32 *minor_status,
+ const gss_buffer_t input_name_buffer,
+ gss_name_t *output_name)
+{
+ krb5_error_code kerr;
+ char *tmp;
+ char *p;
+ char *host;
+ char local_hostname[MAXHOSTNAMELEN];
+
+ *output_name = NULL;
+
+ tmp = malloc (input_name_buffer->length + 1);
+ if (tmp == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy (tmp,
+ input_name_buffer->value,
+ input_name_buffer->length);
+ tmp[input_name_buffer->length] = '\0';
+
+ p = strchr (tmp, '@');
+ if (p != NULL) {
+ *p = '\0';
+ host = p + 1;
+ } else {
+ if (gethostname(local_hostname, sizeof(local_hostname)) < 0) {
+ *minor_status = errno;
+ free (tmp);
+ return GSS_S_FAILURE;
+ }
+ host = local_hostname;
+ }
+
+ kerr = krb5_sname_to_principal (gssapi_krb5_context,
+ host,
+ tmp,
+ KRB5_NT_SRV_HST,
+ output_name);
+ free (tmp);
+ *minor_status = kerr;
+ if (kerr == 0)
+ return GSS_S_COMPLETE;
+ else if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kerr;
+ return GSS_S_BAD_NAME;
+ } else {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
+}
+
+static OM_uint32
+import_export_name (OM_uint32 *minor_status,
+ const gss_buffer_t input_name_buffer,
+ gss_name_t *output_name)
+{
+ unsigned char *p;
+ uint32_t length;
+ OM_uint32 ret;
+ char *name;
+
+ if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length)
+ return GSS_S_BAD_NAME;
+
+ /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
+
+ p = input_name_buffer->value;
+
+ if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 ||
+ p[3] != GSS_KRB5_MECHANISM->length + 2 ||
+ p[4] != 0x06 ||
+ p[5] != GSS_KRB5_MECHANISM->length ||
+ memcmp(&p[6], GSS_KRB5_MECHANISM->elements,
+ GSS_KRB5_MECHANISM->length) != 0)
+ return GSS_S_BAD_NAME;
+
+ p += 6 + GSS_KRB5_MECHANISM->length;
+
+ length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+ p += 4;
+
+ if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length)
+ return GSS_S_BAD_NAME;
+
+ name = malloc(length + 1);
+ if (name == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(name, p, length);
+ name[length] = '\0';
+
+ ret = parse_krb5_name(minor_status, name, output_name);
+ free(name);
+
+ return ret;
+}
+
+int
+gss_oid_equal(const gss_OID a, const gss_OID b)
+{
+ if (a == b)
+ return 1;
+ else if (a == GSS_C_NO_OID || b == GSS_C_NO_OID || a->length != b->length)
+ return 0;
+ else
+ return memcmp(a->elements, b->elements, a->length) == 0;
+}
+
+OM_uint32 gss_import_name
+ (OM_uint32 * minor_status,
+ const gss_buffer_t input_name_buffer,
+ const gss_OID input_name_type,
+ gss_name_t * output_name
+ )
+{
+ GSSAPI_KRB5_INIT ();
+
+ *minor_status = 0;
+ *output_name = GSS_C_NO_NAME;
+
+ if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE))
+ return import_hostbased_name (minor_status,
+ input_name_buffer,
+ output_name);
+ else if (gss_oid_equal(input_name_type, GSS_C_NO_OID)
+ || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME)
+ || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME))
+ /* default printable syntax */
+ return import_krb5_name (minor_status,
+ input_name_buffer,
+ output_name);
+ else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
+ return import_export_name(minor_status,
+ input_name_buffer,
+ output_name);
+ } else {
+ *minor_status = 0;
+ return GSS_S_BAD_NAMETYPE;
+ }
+}
diff --git a/source4/heimdal/lib/gssapi/init.c b/source4/heimdal/lib/gssapi/init.c
new file mode 100644
index 0000000000..37f46624ae
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/init.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: init.c,v 1.7 2003/07/22 19:50:11 lha Exp $");
+
+static HEIMDAL_MUTEX gssapi_krb5_context_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static int created_key;
+static HEIMDAL_thread_key gssapi_context_key;
+
+static void
+gssapi_destroy_thread_context(void *ptr)
+{
+ struct gssapi_thr_context *ctx = ptr;
+
+ if (ctx == NULL)
+ return;
+ if (ctx->error_string)
+ free(ctx->error_string);
+ HEIMDAL_MUTEX_destroy(&ctx->mutex);
+ free(ctx);
+}
+
+
+struct gssapi_thr_context *
+gssapi_get_thread_context(int createp)
+{
+ struct gssapi_thr_context *ctx;
+ int ret;
+
+ HEIMDAL_MUTEX_lock(&gssapi_krb5_context_mutex);
+
+ if (!created_key)
+ abort();
+ ctx = HEIMDAL_getspecific(gssapi_context_key);
+ if (ctx == NULL) {
+ if (!createp)
+ goto fail;
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ goto fail;
+ ctx->error_string = NULL;
+ HEIMDAL_MUTEX_init(&ctx->mutex);
+ HEIMDAL_setspecific(gssapi_context_key, ctx, ret);
+ if (ret)
+ goto fail;
+ }
+ HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex);
+ return ctx;
+ fail:
+ HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex);
+ if (ctx)
+ free(ctx);
+ return NULL;
+}
+
+krb5_error_code
+gssapi_krb5_init (void)
+{
+ krb5_error_code ret = 0;
+
+ HEIMDAL_MUTEX_lock(&gssapi_krb5_context_mutex);
+
+ if(gssapi_krb5_context == NULL)
+ ret = krb5_init_context (&gssapi_krb5_context);
+ if (ret == 0 && !created_key) {
+ HEIMDAL_key_create(&gssapi_context_key,
+ gssapi_destroy_thread_context,
+ ret);
+ if (ret) {
+ krb5_free_context(gssapi_krb5_context);
+ gssapi_krb5_context = NULL;
+ } else
+ created_key = 1;
+ }
+
+ HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex);
+
+ return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/init_sec_context.c b/source4/heimdal/lib/gssapi/init_sec_context.c
new file mode 100644
index 0000000000..c7e4aa50d6
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/init_sec_context.c
@@ -0,0 +1,1261 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: init_sec_context.c,v 1.57 2005/05/30 20:58:29 lha Exp $");
+
+/*
+ * copy the addresses from `input_chan_bindings' (if any) to
+ * the auth context `ac'
+ */
+
+static OM_uint32
+gsskrb5_set_addresses(
+ krb5_auth_context ac,
+ const gss_channel_bindings_t input_chan_bindings)
+{
+ /* Port numbers are expected to be in application_data.value,
+ * initator's port first */
+
+ krb5_address initiator_addr, acceptor_addr;
+ krb5_error_code kret;
+
+ if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
+ || input_chan_bindings->application_data.length !=
+ 2 * sizeof(ac->local_port))
+ return 0;
+
+ memset(&initiator_addr, 0, sizeof(initiator_addr));
+ memset(&acceptor_addr, 0, sizeof(acceptor_addr));
+
+ ac->local_port =
+ *(int16_t *) input_chan_bindings->application_data.value;
+
+ ac->remote_port =
+ *((int16_t *) input_chan_bindings->application_data.value + 1);
+
+ kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
+ &input_chan_bindings->acceptor_address,
+ ac->remote_port,
+ &acceptor_addr);
+ if (kret)
+ return kret;
+
+ kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
+ &input_chan_bindings->initiator_address,
+ ac->local_port,
+ &initiator_addr);
+ if (kret) {
+ krb5_free_address (gssapi_krb5_context, &acceptor_addr);
+ return kret;
+ }
+
+ kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
+ ac,
+ &initiator_addr, /* local address */
+ &acceptor_addr); /* remote address */
+
+ krb5_free_address (gssapi_krb5_context, &initiator_addr);
+ krb5_free_address (gssapi_krb5_context, &acceptor_addr);
+
+#if 0
+ free(input_chan_bindings->application_data.value);
+ input_chan_bindings->application_data.value = NULL;
+ input_chan_bindings->application_data.length = 0;
+#endif
+
+ return kret;
+}
+
+OM_uint32
+_gsskrb5_create_ctx(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_channel_bindings_t input_chan_bindings,
+ enum gss_ctx_id_t_state state)
+{
+ krb5_error_code kret;
+
+ *context_handle = malloc(sizeof(**context_handle));
+ if (*context_handle == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ (*context_handle)->auth_context = NULL;
+ (*context_handle)->source = NULL;
+ (*context_handle)->target = NULL;
+ (*context_handle)->state = state;
+ (*context_handle)->flags = 0;
+ (*context_handle)->more_flags = 0;
+ (*context_handle)->service_keyblock = NULL;
+ (*context_handle)->ticket = NULL;
+ krb5_data_zero(&(*context_handle)->fwd_data);
+ (*context_handle)->lifetime = GSS_C_INDEFINITE;
+ (*context_handle)->order = NULL;
+ HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex);
+
+ kret = krb5_auth_con_init (gssapi_krb5_context,
+ &(*context_handle)->auth_context);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+
+ HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
+
+ return GSS_S_FAILURE;
+ }
+
+ kret = gsskrb5_set_addresses((*context_handle)->auth_context,
+ input_chan_bindings);
+ if (kret) {
+ *minor_status = kret;
+
+ HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
+
+ krb5_auth_con_free(gssapi_krb5_context, (*context_handle)->auth_context);
+
+ return GSS_S_BAD_BINDINGS;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gsskrb5_get_creds(
+ OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_name_t target_name,
+ OM_uint32 time_req,
+ OM_uint32 * time_rec,
+ krb5_creds ** cred)
+{
+ OM_uint32 ret;
+ krb5_error_code kret;
+ krb5_creds this_cred;
+ krb5_ccache ccache = NULL;
+ OM_uint32 lifetime_rec;
+
+ *cred = NULL;
+
+ if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
+ kret = krb5_cc_default (gssapi_krb5_context, &ccache);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ } else {
+ ccache = initiator_cred_handle->ccache;
+ }
+
+ kret = krb5_cc_get_principal(gssapi_krb5_context,
+ ccache,
+ &(*context_handle)->source);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_copy_principal(gssapi_krb5_context,
+ target_name,
+ &(*context_handle)->target);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ memset(&this_cred, 0, sizeof(this_cred));
+ this_cred.client = (*context_handle)->source;
+ this_cred.server = (*context_handle)->target;
+
+ if (time_req && time_req != GSS_C_INDEFINITE) {
+ krb5_timestamp ts;
+
+ krb5_timeofday (gssapi_krb5_context, &ts);
+ this_cred.times.endtime = ts + time_req;
+ } else {
+ this_cred.times.endtime = 0;
+ }
+
+ this_cred.session.keytype = KEYTYPE_NULL;
+
+ kret = krb5_get_credentials(gssapi_krb5_context,
+ 0,
+ ccache,
+ &this_cred,
+ cred);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ (*context_handle)->lifetime = (*cred)->times.endtime;
+
+ ret = gssapi_lifetime_left(minor_status,
+ (*context_handle)->lifetime,
+ &lifetime_rec);
+ if (ret) return ret;
+
+ if (lifetime_rec == 0) {
+ *minor_status = 0;
+ return GSS_S_CONTEXT_EXPIRED;
+ }
+
+ if (time_rec) *time_rec = lifetime_rec;
+
+ if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
+ krb5_cc_close(gssapi_krb5_context, ccache);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gsskrb5_initiator_ready(
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle)
+{
+ OM_uint32 ret;
+ int32_t seq_number;
+ int is_cfx = 0;
+ u_int32_t flags = (*context_handle)->flags;
+
+ krb5_auth_getremoteseqnumber (gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &seq_number);
+
+ gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+ ret = _gssapi_msg_order_create(minor_status,
+ &(*context_handle)->order,
+ _gssapi_msg_order_f(flags),
+ seq_number, 0, is_cfx);
+ if (ret) return ret;
+
+ (*context_handle)->state = INITIATOR_READY;
+ (*context_handle)->more_flags |= OPEN;
+
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * handle delegated creds in init-sec-context
+ */
+
+static void
+gsskrb5_do_delegation(
+ krb5_auth_context ac,
+ krb5_ccache ccache,
+ krb5_creds *cred,
+ const gss_name_t target_name,
+ krb5_data *fwd_data,
+ int *flags)
+{
+ krb5_creds creds;
+ krb5_kdc_flags fwd_flags;
+ krb5_error_code kret;
+
+ memset (&creds, 0, sizeof(creds));
+ krb5_data_zero (fwd_data);
+
+ kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
+ if (kret)
+ goto out;
+
+ kret = krb5_build_principal(gssapi_krb5_context,
+ &creds.server,
+ strlen(creds.client->realm),
+ creds.client->realm,
+ KRB5_TGS_NAME,
+ creds.client->realm,
+ NULL);
+ if (kret)
+ goto out;
+
+ creds.times.endtime = 0;
+
+ fwd_flags.i = 0;
+ fwd_flags.b.forwarded = 1;
+ fwd_flags.b.forwardable = 1;
+
+ if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
+ target_name->name.name_string.len < 2)
+ goto out;
+
+ kret = krb5_get_forwarded_creds(gssapi_krb5_context,
+ ac,
+ ccache,
+ fwd_flags.i,
+ target_name->name.name_string.val[1],
+ &creds,
+ fwd_data);
+
+ out:
+ if (kret)
+ *flags &= ~GSS_C_DELEG_FLAG;
+ else
+ *flags |= GSS_C_DELEG_FLAG;
+
+ if (creds.client)
+ krb5_free_principal(gssapi_krb5_context, creds.client);
+ if (creds.server)
+ krb5_free_principal(gssapi_krb5_context, creds.server);
+}
+
+/*
+ * first stage of init-sec-context
+ */
+
+static OM_uint32
+gsskrb5_initiator_start(
+ OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec)
+{
+ OM_uint32 ret = GSS_S_FAILURE;
+ krb5_error_code kret;
+ krb5_flags ap_options;
+ krb5_creds *cred = NULL;
+ krb5_data outbuf;
+ krb5_ccache ccache = NULL;
+ u_int32_t flags;
+ krb5_data authenticator;
+ Checksum cksum;
+ krb5_enctype enctype;
+ krb5_data fwd_data;
+
+ krb5_data_zero(&outbuf);
+ krb5_data_zero(&fwd_data);
+
+ (*context_handle)->more_flags |= LOCAL;
+
+ /* We need to get the credentials for the requested target */
+ ret = gsskrb5_get_creds(minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ time_req,
+ time_rec,
+ &cred);
+ if (ret) return ret;
+
+ /*
+ * We need to setup some compat stuff, this assumes that context_handle->target is already set
+ */
+ ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
+ if (ret) return ret;
+
+ /*
+ * We need a sequence number
+ */
+
+ krb5_auth_con_addflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE,
+ NULL);
+
+ /* We need the key and a random local subkey */
+ {
+ kret = krb5_auth_con_setkey(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &cred->session);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &cred->session);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /* We need to prepare the flags used for this context */
+ {
+ flags = 0;
+ ap_options = 0;
+
+ if (req_flags & GSS_C_DELEG_FLAG) {
+ gsskrb5_do_delegation((*context_handle)->auth_context,
+ ccache, cred, target_name, &fwd_data, &flags);
+ }
+
+ if (req_flags & GSS_C_MUTUAL_FLAG) {
+ flags |= GSS_C_MUTUAL_FLAG;
+ ap_options |= AP_OPTS_MUTUAL_REQUIRED;
+ }
+
+ if (req_flags & GSS_C_REPLAY_FLAG) {
+ flags |= GSS_C_REPLAY_FLAG;
+ }
+
+ if (req_flags & GSS_C_SEQUENCE_FLAG) {
+ flags |= GSS_C_SEQUENCE_FLAG;
+ }
+
+ if (req_flags & GSS_C_ANON_FLAG) {
+ ;/* XXX */
+ }
+
+ if (req_flags & GSS_C_DCE_STYLE) {
+ flags |= GSS_C_DCE_STYLE;
+ /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
+ flags |= GSS_C_MUTUAL_FLAG;
+ ap_options |= AP_OPTS_MUTUAL_REQUIRED;
+ }
+
+ if (req_flags & GSS_C_IDENTIFY_FLAG) {
+ flags |= GSS_C_IDENTIFY_FLAG;
+ }
+
+ if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) {
+ flags |= GSS_C_EXTENDED_ERROR_FLAG;
+ }
+
+ /* TODO: why are this always there? --metze */
+ flags |= GSS_C_CONF_FLAG;
+ flags |= GSS_C_INTEG_FLAG;
+ flags |= GSS_C_TRANS_FLAG;
+
+ if (ret_flags) *ret_flags = flags;
+ (*context_handle)->flags = flags;
+ }
+
+ /* We need to generate the 8003 checksum */
+ {
+ ret = gssapi_krb5_create_8003_checksum(minor_status,
+ input_chan_bindings,
+ flags,
+ &fwd_data,
+ &cksum);
+ krb5_data_free (&fwd_data);
+ if (ret) return ret;
+ }
+
+ enctype = (*context_handle)->auth_context->keyblock->keytype;
+
+ /* We need to create an Authenticator */
+ {
+ kret = krb5_build_authenticator (gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ enctype,
+ cred,
+ &cksum,
+ NULL,
+ &authenticator,
+ KRB5_KU_AP_REQ_AUTH);
+ free_Checksum(&cksum);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /* We need to create the AP_REQ */
+ {
+ kret = krb5_build_ap_req(gssapi_krb5_context,
+ enctype,
+ cred,
+ ap_options,
+ authenticator,
+ &outbuf);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /* We need to encapsulate the AP_REQ if GSS_C_DCE_STYLE isn't in use */
+ {
+ if (!(flags & GSS_C_DCE_STYLE)) {
+ ret = gssapi_krb5_encapsulate(minor_status, &outbuf, output_token,
+ "\x01\x00", GSS_KRB5_MECHANISM);
+ krb5_data_free (&outbuf);
+ if (ret) return ret;
+ } else {
+ output_token->length = outbuf.length;
+ output_token->value = outbuf.data;
+ }
+ }
+
+ /* We no longer need the creds */
+ krb5_free_creds(gssapi_krb5_context, cred);
+
+ /* We are done if GSS_C_MUTUAL_FLAG is in use */
+ if (flags & GSS_C_MUTUAL_FLAG) {
+ (*context_handle)->state = INITIATOR_WAIT_FOR_MUTAL;
+ return GSS_S_CONTINUE_NEEDED;
+ }
+
+ return gsskrb5_initiator_ready(minor_status, context_handle);
+}
+
+static OM_uint32
+gsskrb5_initiator_wait_for_mutual(
+ OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec)
+{
+ OM_uint32 ret;
+ krb5_error_code kret;
+ krb5_data inbuf;
+ u_int32_t flags = (*context_handle)->flags;
+ OM_uint32 l_seq_number;
+ OM_uint32 r_seq_number;
+
+ /* We need to decapsulate the AP_REP if GSS_C_DCE_STYLE isn't in use */
+ {
+ if (!(flags & GSS_C_DCE_STYLE)) {
+ ret = gssapi_krb5_decapsulate(minor_status, input_token, &inbuf,
+ "\x02\x00", GSS_KRB5_MECHANISM);
+ if (ret) return ret;
+ } else {
+ inbuf.length = input_token->length;
+ inbuf.data = input_token->value;
+ }
+ }
+
+ /* We need to verify the AP_REP */
+ {
+ krb5_ap_rep_enc_part *repl;
+
+ kret = krb5_rd_rep(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &inbuf,
+ &repl);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
+ }
+
+ /* We need to check the liftime */
+ {
+ OM_uint32 lifetime_rec;
+
+ ret = gssapi_lifetime_left(minor_status,
+ (*context_handle)->lifetime,
+ &lifetime_rec);
+ if (ret) return ret;
+
+ if (lifetime_rec == 0) {
+ return GSS_S_CONTEXT_EXPIRED;
+ }
+
+ if (time_rec) *time_rec = lifetime_rec;
+ }
+
+ /* We need to give the caller the flags which are in use */
+ if (ret_flags) *ret_flags = (*context_handle)->flags;
+
+ /* We are done here if GSS_C_DCE_STYLE isn't in use */
+ if (!(flags & GSS_C_DCE_STYLE)) {
+ return gsskrb5_initiator_ready(minor_status, context_handle);
+ }
+
+ /*
+ * We need to set the local seq_number to the remote one just for the krb5_mk_rep(),
+ * and then we need to use the old local seq_number again for the GSS_Wrap() messages
+ */
+ {
+ kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &r_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &l_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ kret = krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ r_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ /* We need to create an AP_REP */
+ {
+ krb5_data outbuf;
+
+ kret = krb5_mk_rep(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &outbuf);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+
+ output_token->length = outbuf.length;
+ output_token->value = outbuf.data;
+ }
+
+ /* We need to reset the local seq_number */
+ {
+ kret = krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ l_seq_number);
+ if (kret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ return gsskrb5_initiator_ready(minor_status, context_handle);
+}
+
+static OM_uint32
+gsskrb5_init_sec_context(
+ OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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)
+{
+ OM_uint32 ret;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ ret = _gsskrb5_create_ctx(minor_status,
+ context_handle,
+ input_chan_bindings,
+ INITIATOR_START);
+ if (ret) return ret;
+ }
+
+ if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM;
+
+ HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+
+ switch ((*context_handle)->state) {
+ case INITIATOR_START:
+ ret = gsskrb5_initiator_start(minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ output_token,
+ ret_flags,
+ time_rec);
+ break;
+ case INITIATOR_WAIT_FOR_MUTAL:
+ ret = gsskrb5_initiator_wait_for_mutual(minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ output_token,
+ ret_flags,
+ time_rec);
+ break;
+ case INITIATOR_READY:
+ /* should this be GSS_S_BAD_STATUS ? --metze */
+
+ /* We need to check the liftime */
+ {
+ OM_uint32 lifetime_rec;
+
+ ret = gssapi_lifetime_left(minor_status,
+ (*context_handle)->lifetime,
+ &lifetime_rec);
+ if (ret) break;
+
+ if (lifetime_rec == 0) {
+ *minor_status = 0;
+ ret = GSS_S_CONTEXT_EXPIRED;
+ break;
+ }
+
+ if (time_rec) *time_rec = lifetime_rec;
+ }
+
+ /* We need to give the caller the flags which are in use */
+ if (ret_flags) *ret_flags = (*context_handle)->flags;
+
+ ret = GSS_S_COMPLETE;
+ break;
+ default:
+ /* TODO: is this correct here? --metze */
+ ret = GSS_S_BAD_STATUS;
+ break;
+ }
+
+ HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
+
+ return ret;
+}
+
+static OM_uint32
+spnego_reply
+ (OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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
+ )
+{
+ OM_uint32 ret;
+ krb5_data indata;
+ NegTokenTarg targ;
+ u_char oidbuf[17];
+ size_t oidlen;
+ gss_buffer_desc sub_token;
+ ssize_t mech_len;
+ const u_char *p;
+ size_t len, taglen;
+ krb5_boolean require_mic;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ /*
+ * SPNEGO doesn't include gss wrapping on SubsequentContextToken
+ * like the Kerberos 5 mech does. But lets check for it anyway.
+ */
+
+ mech_len = gssapi_krb5_get_mech (input_token->value,
+ input_token->length,
+ &p);
+
+ if (mech_len < 0) {
+ indata.data = input_token->value;
+ indata.length = input_token->length;
+ } else if (mech_len == GSS_KRB5_MECHANISM->length
+ && memcmp(GSS_KRB5_MECHANISM->elements, p, mech_len) == 0)
+ return gsskrb5_init_sec_context (minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ GSS_KRB5_MECHANISM,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+ else if (mech_len == GSS_SPNEGO_MECHANISM->length
+ && memcmp(GSS_SPNEGO_MECHANISM->elements, p, mech_len) == 0){
+ ret = _gssapi_decapsulate (minor_status,
+ input_token,
+ &indata,
+ GSS_SPNEGO_MECHANISM);
+ if (ret)
+ return ret;
+ } else
+ return GSS_S_BAD_MECH;
+
+ ret = der_match_tag_and_length((const char *)indata.data,
+ indata.length,
+ ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
+ if (ret)
+ return ret;
+
+ if(len > indata.length - taglen)
+ return ASN1_OVERRUN;
+
+ ret = decode_NegTokenTarg((const char *)indata.data + taglen,
+ len, &targ, NULL);
+ if (ret) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ if (targ.negResult == NULL
+ || *(targ.negResult) == reject
+ || targ.supportedMech == NULL) {
+ free_NegTokenTarg(&targ);
+ return GSS_S_BAD_MECH;
+ }
+
+ ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
+ sizeof(oidbuf),
+ targ.supportedMech,
+ &oidlen);
+ if (ret || oidlen != GSS_KRB5_MECHANISM->length
+ || memcmp(oidbuf + sizeof(oidbuf) - oidlen,
+ GSS_KRB5_MECHANISM->elements,
+ oidlen) != 0) {
+ free_NegTokenTarg(&targ);
+ return GSS_S_BAD_MECH;
+ }
+
+ if (targ.responseToken != NULL) {
+ sub_token.length = targ.responseToken->length;
+ sub_token.value = targ.responseToken->data;
+ } else {
+ sub_token.length = 0;
+ sub_token.value = NULL;
+ }
+
+ ret = gsskrb5_init_sec_context(minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ GSS_KRB5_MECHANISM,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ &sub_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ return ret;
+ }
+
+ /*
+ * Verify the mechListMIC if CFX was used; or if local policy
+ * dictated so.
+ */
+ ret = _gss_spnego_require_mechlist_mic(minor_status, *context_handle,
+ &require_mic);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ return ret;
+ }
+
+ if (require_mic) {
+ MechTypeList mechlist;
+ MechType m0;
+ size_t buf_len;
+ gss_buffer_desc mic_buf, mech_buf;
+
+ if (targ.mechListMIC == NULL) {
+ free_NegTokenTarg(&targ);
+ *minor_status = 0;
+ return GSS_S_BAD_MIC;
+ }
+
+ mechlist.len = 1;
+ mechlist.val = &m0;
+
+ ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
+ GSS_KRB5_MECHANISM->length,
+ &m0,
+ NULL);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
+ &mechlist, &buf_len, ret);
+ if (ret) {
+ free_NegTokenTarg(&targ);
+ free_oid(&m0);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ if (mech_buf.length != buf_len)
+ abort();
+
+ mic_buf.length = targ.mechListMIC->length;
+ mic_buf.value = targ.mechListMIC->data;
+
+ ret = gss_verify_mic(minor_status, *context_handle,
+ &mech_buf, &mic_buf, NULL);
+ free(mech_buf.value);
+ free_oid(&m0);
+ }
+ free_NegTokenTarg(&targ);
+ return ret;
+}
+
+static OM_uint32
+spnego_initial
+ (OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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
+ )
+{
+ NegTokenInit ni;
+ int ret;
+ OM_uint32 sub, minor;
+ gss_buffer_desc mech_token;
+ u_char *buf;
+ size_t buf_size, buf_len;
+ krb5_data data;
+#if 1
+ size_t ni_len;
+#endif
+
+ memset (&ni, 0, sizeof(ni));
+
+ ALLOC(ni.mechTypes, 1);
+ if (ni.mechTypes == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ ALLOC_SEQ(ni.mechTypes, 1);
+ if (ni.mechTypes->val == NULL) {
+ free_NegTokenInit(&ni);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
+ GSS_KRB5_MECHANISM->length,
+ &ni.mechTypes->val[0],
+ NULL);
+ if (ret) {
+ free_NegTokenInit(&ni);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+#if 0
+ ALLOC(ni.reqFlags, 1);
+ if (ni.reqFlags == NULL) {
+ free_NegTokenInit(&ni);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ ni.reqFlags->delegFlag = req_flags & GSS_C_DELEG_FLAG;
+ ni.reqFlags->mutualFlag = req_flags & GSS_C_MUTUAL_FLAG;
+ ni.reqFlags->replayFlag = req_flags & GSS_C_REPLAY_FLAG;
+ ni.reqFlags->sequenceFlag = req_flags & GSS_C_SEQUENCE_FLAG;
+ ni.reqFlags->anonFlag = req_flags & GSS_C_ANON_FLAG;
+ ni.reqFlags->confFlag = req_flags & GSS_C_CONF_FLAG;
+ ni.reqFlags->integFlag = req_flags & GSS_C_INTEG_FLAG;
+#else
+ ni.reqFlags = NULL;
+#endif
+
+ sub = gsskrb5_init_sec_context(&minor,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ GSS_KRB5_MECHANISM,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ GSS_C_NO_BUFFER,
+ actual_mech_type,
+ &mech_token,
+ ret_flags,
+ time_rec);
+ if (GSS_ERROR(sub)) {
+ free_NegTokenInit(&ni);
+ return sub;
+ }
+ if (mech_token.length != 0) {
+ ALLOC(ni.mechToken, 1);
+ if (ni.mechToken == NULL) {
+ free_NegTokenInit(&ni);
+ gss_release_buffer(&minor, &mech_token);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ ni.mechToken->length = mech_token.length;
+ ni.mechToken->data = malloc(mech_token.length);
+ if (ni.mechToken->data == NULL && mech_token.length != 0) {
+ free_NegTokenInit(&ni);
+ gss_release_buffer(&minor, &mech_token);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(ni.mechToken->data, mech_token.value, mech_token.length);
+ gss_release_buffer(&minor, &mech_token);
+ } else
+ ni.mechToken = NULL;
+
+ /* XXX ignore mech list mic for now */
+ ni.mechListMIC = NULL;
+
+
+#if 0
+ {
+ int ret;
+ NegotiationToken nt;
+
+ nt.element = choice_NegotiationToken_negTokenInit;
+ nt.u.negTokenInit = ni;
+
+ ASN1_MALLOC_ENCODE(NegotiationToken, buf, buf_size,
+ &nt, &buf_len, ret);
+ if (buf_size != buf_len)
+ abort();
+ }
+#else
+ ni_len = length_NegTokenInit(&ni);
+ buf_size = 1 + length_len(ni_len) + ni_len;
+
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ free_NegTokenInit(&ni);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ ret = encode_NegTokenInit(buf + buf_size - 1,
+ ni_len,
+ &ni, &buf_len);
+ if (ret == 0 && ni_len != buf_len)
+ abort();
+
+ if (ret == 0) {
+ size_t tmp;
+
+ ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
+ buf_size - buf_len,
+ buf_len,
+ ASN1_C_CONTEXT,
+ CONS,
+ 0,
+ &tmp);
+ if (ret == 0 && tmp + buf_len != buf_size)
+ abort();
+ }
+ if (ret) {
+ *minor_status = ret;
+ free(buf);
+ free_NegTokenInit(&ni);
+ return GSS_S_FAILURE;
+ }
+
+#endif
+ data.data = buf;
+ data.length = buf_size;
+
+ free_NegTokenInit(&ni);
+ if (ret)
+ return ret;
+
+ sub = _gssapi_encapsulate(minor_status,
+ &data,
+ output_token,
+ GSS_SPNEGO_MECHANISM);
+ free (buf);
+
+ if (sub)
+ return sub;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+spnego_init_sec_context
+ (OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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
+ )
+{
+ if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
+ return spnego_initial (minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+ else
+ return spnego_reply (minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+}
+
+/*
+ * gss_init_sec_context
+ */
+
+OM_uint32 gss_init_sec_context(
+ OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_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)
+{
+ GSSAPI_KRB5_INIT ();
+
+ *minor_status = 0;
+
+ if (actual_mech_type) *actual_mech_type = GSS_C_NO_OID;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (ret_flags) *ret_flags = 0;
+ if (time_rec) *time_rec = 0;
+
+ if (target_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME;
+
+ if (mech_type == GSS_C_NO_OID ||
+ gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) {
+ return gsskrb5_init_sec_context(minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+ } else if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM)) {
+ return spnego_init_sec_context (minor_status,
+ initiator_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+ }
+
+ return GSS_S_BAD_MECH;
+}
diff --git a/source4/heimdal/lib/gssapi/inquire_cred.c b/source4/heimdal/lib/gssapi/inquire_cred.c
new file mode 100644
index 0000000000..9ed1ff4cc4
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/inquire_cred.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1997, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: inquire_cred.c,v 1.7 2004/11/30 19:27:11 lha Exp $");
+
+OM_uint32 gss_inquire_cred
+ (OM_uint32 * minor_status,
+ const gss_cred_id_t cred_handle,
+ gss_name_t * name,
+ OM_uint32 * lifetime,
+ gss_cred_usage_t * cred_usage,
+ gss_OID_set * mechanisms
+ )
+{
+ gss_cred_id_t cred;
+ OM_uint32 ret;
+
+ *minor_status = 0;
+
+ if (name)
+ *name = NULL;
+ if (mechanisms)
+ *mechanisms = GSS_C_NO_OID_SET;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ ret = gss_acquire_cred(minor_status,
+ GSS_C_NO_NAME,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET,
+ GSS_C_BOTH,
+ &cred,
+ NULL,
+ NULL);
+ if (ret)
+ return ret;
+ } else
+ cred = (gss_cred_id_t)cred_handle;
+
+ HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
+
+ if (name != NULL) {
+ if (cred->principal != NULL) {
+ ret = gss_duplicate_name(minor_status, cred->principal,
+ name);
+ if (ret)
+ goto out;
+ } else if (cred->usage == GSS_C_ACCEPT) {
+ *minor_status = krb5_sname_to_principal(gssapi_krb5_context, NULL,
+ NULL, KRB5_NT_SRV_HST, name);
+ if (*minor_status) {
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+ } else {
+ *minor_status = krb5_get_default_principal(gssapi_krb5_context,
+ name);
+ if (*minor_status) {
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+ }
+ }
+ if (lifetime != NULL) {
+ ret = gssapi_lifetime_left(minor_status,
+ cred->lifetime,
+ lifetime);
+ if (ret)
+ goto out;
+ }
+ if (cred_usage != NULL)
+ *cred_usage = cred->usage;
+
+ if (mechanisms != NULL) {
+ ret = gss_create_empty_oid_set(minor_status, mechanisms);
+ if (ret)
+ goto out;
+ ret = gss_add_oid_set_member(minor_status,
+ &cred->mechanisms->elements[0],
+ mechanisms);
+ if (ret)
+ goto out;
+ }
+ ret = GSS_S_COMPLETE;
+ out:
+ HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ ret = gss_release_cred(minor_status, &cred);
+
+ return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/release_buffer.c b/source4/heimdal/lib/gssapi/release_buffer.c
new file mode 100644
index 0000000000..258b76f627
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/release_buffer.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997 - 2000, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: release_buffer.c,v 1.5 2003/03/16 17:58:20 lha Exp $");
+
+OM_uint32 gss_release_buffer
+ (OM_uint32 * minor_status,
+ gss_buffer_t buffer
+ )
+{
+ *minor_status = 0;
+ free (buffer->value);
+ buffer->value = NULL;
+ buffer->length = 0;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/release_cred.c b/source4/heimdal/lib/gssapi/release_cred.c
new file mode 100644
index 0000000000..8ae65dd528
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/release_cred.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: release_cred.c,v 1.10 2003/10/07 00:51:46 lha Exp $");
+
+OM_uint32 gss_release_cred
+ (OM_uint32 * minor_status,
+ gss_cred_id_t * cred_handle
+ )
+{
+ *minor_status = 0;
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL) {
+ return GSS_S_COMPLETE;
+ }
+
+ GSSAPI_KRB5_INIT ();
+
+ HEIMDAL_MUTEX_lock(&(*cred_handle)->cred_id_mutex);
+
+ if ((*cred_handle)->principal != NULL)
+ krb5_free_principal(gssapi_krb5_context, (*cred_handle)->principal);
+ if ((*cred_handle)->made_keytab)
+ krb5_kt_close(gssapi_krb5_context, (*cred_handle)->keytab);
+ if ((*cred_handle)->made_ccache) {
+ const krb5_cc_ops *ops;
+ ops = krb5_cc_get_ops(gssapi_krb5_context, (*cred_handle)->ccache);
+ if (ops == &krb5_mcc_ops)
+ krb5_cc_destroy(gssapi_krb5_context, (*cred_handle)->ccache);
+ else
+ krb5_cc_close(gssapi_krb5_context, (*cred_handle)->ccache);
+ }
+ gss_release_oid_set(NULL, &(*cred_handle)->mechanisms);
+ HEIMDAL_MUTEX_unlock(&(*cred_handle)->cred_id_mutex);
+ HEIMDAL_MUTEX_destroy(&(*cred_handle)->cred_id_mutex);
+ memset(*cred_handle, 0, sizeof(**cred_handle));
+ free(*cred_handle);
+ *cred_handle = GSS_C_NO_CREDENTIAL;
+ return GSS_S_COMPLETE;
+}
+
diff --git a/source4/heimdal/lib/gssapi/release_name.c b/source4/heimdal/lib/gssapi/release_name.c
new file mode 100644
index 0000000000..6894ffae49
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/release_name.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: release_name.c,v 1.7 2003/03/16 17:52:48 lha Exp $");
+
+OM_uint32 gss_release_name
+ (OM_uint32 * minor_status,
+ gss_name_t * input_name
+ )
+{
+ GSSAPI_KRB5_INIT ();
+ if (minor_status)
+ *minor_status = 0;
+ krb5_free_principal(gssapi_krb5_context,
+ *input_name);
+ *input_name = GSS_C_NO_NAME;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/release_oid_set.c b/source4/heimdal/lib/gssapi/release_oid_set.c
new file mode 100644
index 0000000000..04eb01565f
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/release_oid_set.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997 - 2000, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: release_oid_set.c,v 1.5 2003/03/16 17:53:25 lha Exp $");
+
+OM_uint32 gss_release_oid_set
+ (OM_uint32 * minor_status,
+ gss_OID_set * set
+ )
+{
+ if (minor_status)
+ *minor_status = 0;
+ free ((*set)->elements);
+ free (*set);
+ *set = GSS_C_NO_OID_SET;
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/sequence.c b/source4/heimdal/lib/gssapi/sequence.c
new file mode 100755
index 0000000000..973fc6ad05
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/sequence.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: sequence.c,v 1.5 2005/04/27 17:49:43 lha Exp $");
+
+#define DEFAULT_JITTER_WINDOW 20
+
+struct gss_msg_order {
+ OM_uint32 flags;
+ OM_uint32 start;
+ OM_uint32 length;
+ OM_uint32 jitter_window;
+ OM_uint32 first_seq;
+ OM_uint32 elem[1];
+};
+
+/*
+ *
+ */
+
+OM_uint32
+_gssapi_msg_order_create(OM_uint32 *minor_status,
+ struct gss_msg_order **o,
+ OM_uint32 flags,
+ OM_uint32 seq_num,
+ OM_uint32 jitter_window,
+ int use_64)
+{
+ size_t len;
+
+ if (jitter_window == 0)
+ jitter_window = DEFAULT_JITTER_WINDOW;
+
+ len = jitter_window * sizeof((*o)->elem[0]);
+ len += sizeof(**o);
+ len -= sizeof((*o)->elem[0]);
+
+ *o = malloc(len);
+ if (*o == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memset(*o, 0, len);
+ (*o)->flags = flags;
+ (*o)->length = 0;
+ (*o)->first_seq = seq_num;
+ (*o)->jitter_window = jitter_window;
+ (*o)->elem[0] = seq_num - 1;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_gssapi_msg_order_destroy(struct gss_msg_order **m)
+{
+ free(*m);
+ *m = NULL;
+ return GSS_S_COMPLETE;
+}
+
+static void
+elem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val)
+{
+ o->elem[slot % o->jitter_window] = val;
+}
+
+static void
+elem_insert(struct gss_msg_order *o,
+ unsigned int after_slot,
+ OM_uint32 seq_num)
+{
+ assert(o->jitter_window > after_slot);
+
+ if (o->length > after_slot)
+ memmove(&o->elem[after_slot + 1], &o->elem[after_slot],
+ (o->length - after_slot - 1) * sizeof(o->elem[0]));
+
+ elem_set(o, after_slot, seq_num);
+
+ if (o->length < o->jitter_window)
+ o->length++;
+}
+
+/* rule 1: expected sequence number */
+/* rule 2: > expected sequence number */
+/* rule 3: seqnum < seqnum(first) */
+/* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */
+
+OM_uint32
+_gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num)
+{
+ OM_uint32 r;
+ int i;
+
+ if (o == NULL)
+ return GSS_S_COMPLETE;
+
+ if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0)
+ return GSS_S_COMPLETE;
+
+ /* check if the packet is the next in order */
+ if (o->elem[0] == seq_num - 1) {
+ elem_insert(o, 0, seq_num);
+ return GSS_S_COMPLETE;
+ }
+
+ r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG;
+
+ /* sequence number larger then largest sequence number
+ * or smaller then the first sequence number */
+ if (seq_num > o->elem[0]
+ || seq_num < o->first_seq
+ || o->length == 0)
+ {
+ elem_insert(o, 0, seq_num);
+ if (r) {
+ return GSS_S_COMPLETE;
+ } else {
+ return GSS_S_GAP_TOKEN;
+ }
+ }
+
+ assert(o->length > 0);
+
+ /* sequence number smaller the first sequence number */
+ if (seq_num < o->elem[o->length - 1]) {
+ if (r)
+ return(GSS_S_OLD_TOKEN);
+ else
+ return(GSS_S_UNSEQ_TOKEN);
+ }
+
+ if (seq_num == o->elem[o->length - 1]) {
+ return GSS_S_DUPLICATE_TOKEN;
+ }
+
+ for (i = 0; i < o->length - 1; i++) {
+ if (o->elem[i] == seq_num)
+ return GSS_S_DUPLICATE_TOKEN;
+ if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) {
+ elem_insert(o, i, seq_num);
+ if (r)
+ return GSS_S_COMPLETE;
+ else
+ return GSS_S_UNSEQ_TOKEN;
+ }
+ }
+
+ return GSS_S_FAILURE;
+}
+
+OM_uint32
+_gssapi_msg_order_f(OM_uint32 flags)
+{
+ return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG);
+}
diff --git a/source4/heimdal/lib/gssapi/spnego.asn1 b/source4/heimdal/lib/gssapi/spnego.asn1
new file mode 100755
index 0000000000..5dc767cf76
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/spnego.asn1
@@ -0,0 +1,42 @@
+-- $Id: spnego.asn1,v 1.4 2004/03/07 13:38:08 lha Exp $
+
+SPNEGO DEFINITIONS ::=
+BEGIN
+
+MechType::= OBJECT IDENTIFIER
+
+MechTypeList ::= SEQUENCE OF MechType
+
+ContextFlags ::= BIT STRING {
+ delegFlag (0),
+ mutualFlag (1),
+ replayFlag (2),
+ sequenceFlag (3),
+ anonFlag (4),
+ confFlag (5),
+ integFlag (6)
+}
+
+NegTokenInit ::= SEQUENCE {
+ mechTypes [0] MechTypeList OPTIONAL,
+ reqFlags [1] ContextFlags OPTIONAL,
+ mechToken [2] OCTET STRING OPTIONAL,
+ mechListMIC [3] OCTET STRING OPTIONAL
+ }
+
+NegTokenTarg ::= SEQUENCE {
+ negResult [0] ENUMERATED {
+ accept_completed (0),
+ accept_incomplete (1),
+ reject (2) } OPTIONAL,
+ supportedMech [1] MechType OPTIONAL,
+ responseToken [2] OCTET STRING OPTIONAL,
+ mechListMIC [3] OCTET STRING OPTIONAL
+}
+
+NegotiationToken ::= CHOICE {
+ negTokenInit[0] NegTokenInit,
+ negTokenTarg[1] NegTokenTarg
+}
+
+END
diff --git a/source4/heimdal/lib/gssapi/test_oid_set_member.c b/source4/heimdal/lib/gssapi/test_oid_set_member.c
new file mode 100644
index 0000000000..e747c5acc1
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/test_oid_set_member.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1997, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: test_oid_set_member.c,v 1.5 2003/03/16 17:54:06 lha Exp $");
+
+OM_uint32 gss_test_oid_set_member (
+ OM_uint32 * minor_status,
+ const gss_OID member,
+ const gss_OID_set set,
+ int * present
+ )
+{
+ size_t i;
+
+ *minor_status = 0;
+ *present = 0;
+ for (i = 0; i < set->count; ++i)
+ if (gss_oid_equal(member, &set->elements[i]) != 0) {
+ *present = 1;
+ break;
+ }
+ return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/unwrap.c b/source4/heimdal/lib/gssapi/unwrap.c
new file mode 100644
index 0000000000..c358c1aa24
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/unwrap.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: unwrap.c,v 1.34 2005/04/27 17:50:40 lha Exp $");
+
+static OM_uint32
+unwrap_des
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int * conf_state,
+ gss_qop_t * qop_state,
+ krb5_keyblock *key
+ )
+{
+ u_char *p, *seq;
+ size_t len;
+ MD5_CTX md5;
+ u_char hash[16];
+ DES_key_schedule schedule;
+ DES_cblock deskey;
+ DES_cblock zero;
+ int i;
+ int32_t seq_number;
+ size_t padlength;
+ OM_uint32 ret;
+ int cstate;
+ int cmp;
+
+ p = input_message_buffer->value;
+ ret = gssapi_krb5_verify_header (&p,
+ input_message_buffer->length,
+ "\x02\x01",
+ GSS_KRB5_MECHANISM);
+ if (ret)
+ return ret;
+
+ if (memcmp (p, "\x00\x00", 2) != 0)
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp (p, "\x00\x00", 2) == 0) {
+ cstate = 1;
+ } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
+ cstate = 0;
+ } else
+ return GSS_S_BAD_MIC;
+ p += 2;
+ if(conf_state != NULL)
+ *conf_state = cstate;
+ if (memcmp (p, "\xff\xff", 2) != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ p += 2;
+ p += 16;
+
+ len = p - (u_char *)input_message_buffer->value;
+
+ if(cstate) {
+ /* decrypt data */
+ memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+ for (i = 0; i < sizeof(deskey); ++i)
+ deskey[i] ^= 0xf0;
+ DES_set_key (&deskey, &schedule);
+ memset (&zero, 0, sizeof(zero));
+ DES_cbc_encrypt ((void *)p,
+ (void *)p,
+ input_message_buffer->length - len,
+ &schedule,
+ &zero,
+ DES_DECRYPT);
+
+ memset (deskey, 0, sizeof(deskey));
+ memset (&schedule, 0, sizeof(schedule));
+ }
+ /* check pad */
+ ret = _gssapi_verify_pad(input_message_buffer,
+ input_message_buffer->length - len,
+ &padlength);
+ if (ret)
+ return ret;
+
+ MD5_Init (&md5);
+ MD5_Update (&md5, p - 24, 8);
+ MD5_Update (&md5, p, input_message_buffer->length - len);
+ MD5_Final (hash, &md5);
+
+ memset (&zero, 0, sizeof(zero));
+ memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+ &schedule, &zero);
+ if (memcmp (p - 8, hash, 8) != 0)
+ return GSS_S_BAD_MIC;
+
+ /* verify sequence number */
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+ p -= 16;
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_encrypt ((void *)p, (void *)p, 8,
+ &schedule, (DES_cblock *)hash, DES_DECRYPT);
+
+ memset (deskey, 0, sizeof(deskey));
+ memset (&schedule, 0, sizeof(schedule));
+
+ seq = p;
+ gssapi_decode_om_uint32(seq, &seq_number);
+
+ if (context_handle->more_flags & LOCAL)
+ cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+ else
+ cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+ if (cmp != 0) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_BAD_MIC;
+ }
+
+ ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+ if (ret) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return ret;
+ }
+
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /* copy out data */
+
+ output_message_buffer->length = input_message_buffer->length
+ - len - padlength - 8;
+ output_message_buffer->value = malloc(output_message_buffer->length);
+ if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
+ return GSS_S_FAILURE;
+ memcpy (output_message_buffer->value,
+ p + 24,
+ output_message_buffer->length);
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+unwrap_des3
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int * conf_state,
+ gss_qop_t * qop_state,
+ krb5_keyblock *key
+ )
+{
+ u_char *p;
+ size_t len;
+ u_char *seq;
+ krb5_data seq_data;
+ u_char cksum[20];
+ int32_t seq_number;
+ size_t padlength;
+ OM_uint32 ret;
+ int cstate;
+ krb5_crypto crypto;
+ Checksum csum;
+ int cmp;
+
+ p = input_message_buffer->value;
+ ret = gssapi_krb5_verify_header (&p,
+ input_message_buffer->length,
+ "\x02\x01",
+ GSS_KRB5_MECHANISM);
+ if (ret)
+ return ret;
+
+ if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp (p, "\x02\x00", 2) == 0) {
+ cstate = 1;
+ } else if (memcmp (p, "\xff\xff", 2) == 0) {
+ cstate = 0;
+ } else
+ return GSS_S_BAD_MIC;
+ p += 2;
+ if(conf_state != NULL)
+ *conf_state = cstate;
+ if (memcmp (p, "\xff\xff", 2) != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ p += 2;
+ p += 28;
+
+ len = p - (u_char *)input_message_buffer->value;
+
+ if(cstate) {
+ /* decrypt data */
+ krb5_data tmp;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key,
+ ETYPE_DES3_CBC_NONE, &crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ ret = krb5_decrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
+ p, input_message_buffer->length - len, &tmp);
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ assert (tmp.length == input_message_buffer->length - len);
+
+ memcpy (p, tmp.data, tmp.length);
+ krb5_data_free(&tmp);
+ }
+ /* check pad */
+ ret = _gssapi_verify_pad(input_message_buffer,
+ input_message_buffer->length - len,
+ &padlength);
+ if (ret)
+ return ret;
+
+ /* verify sequence number */
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+ p -= 28;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key,
+ ETYPE_DES3_CBC_NONE, &crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_FAILURE;
+ }
+ {
+ DES_cblock ivec;
+
+ memcpy(&ivec, p + 8, 8);
+ ret = krb5_decrypt_ivec (gssapi_krb5_context,
+ crypto,
+ KRB5_KU_USAGE_SEQ,
+ p, 8, &seq_data,
+ &ivec);
+ }
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_FAILURE;
+ }
+ if (seq_data.length != 8) {
+ krb5_data_free (&seq_data);
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_BAD_MIC;
+ }
+
+ seq = seq_data.data;
+ gssapi_decode_om_uint32(seq, &seq_number);
+
+ if (context_handle->more_flags & LOCAL)
+ cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+ else
+ cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+ krb5_data_free (&seq_data);
+ if (cmp != 0) {
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_BAD_MIC;
+ }
+
+ ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+ if (ret) {
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return ret;
+ }
+
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /* verify checksum */
+
+ memcpy (cksum, p + 8, 20);
+
+ memcpy (p + 20, p - 8, 8);
+
+ csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
+ csum.checksum.length = 20;
+ csum.checksum.data = cksum;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = krb5_verify_checksum (gssapi_krb5_context, crypto,
+ KRB5_KU_USAGE_SIGN,
+ p + 20,
+ input_message_buffer->length - len + 8,
+ &csum);
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* copy out data */
+
+ output_message_buffer->length = input_message_buffer->length
+ - len - padlength - 8;
+ output_message_buffer->value = malloc(output_message_buffer->length);
+ if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
+ return GSS_S_FAILURE;
+ memcpy (output_message_buffer->value,
+ p + 36,
+ output_message_buffer->length);
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_unwrap
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int * conf_state,
+ gss_qop_t * qop_state
+ )
+{
+ krb5_keyblock *key;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+
+ output_message_buffer->value = NULL;
+ output_message_buffer->length = 0;
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+ ret = gss_krb5_get_subkey(context_handle, &key);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+ *minor_status = 0;
+
+ switch (keytype) {
+ case KEYTYPE_DES :
+ ret = unwrap_des (minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state, key);
+ break;
+ case KEYTYPE_DES3 :
+ ret = unwrap_des3 (minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state, key);
+ break;
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_unwrap_arcfour (minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state, key);
+ break;
+ default :
+ ret = _gssapi_unwrap_cfx (minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state, key);
+ break;
+ }
+ krb5_free_keyblock (gssapi_krb5_context, key);
+ return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/verify_mic.c b/source4/heimdal/lib/gssapi/verify_mic.c
new file mode 100644
index 0000000000..7b7d437e99
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/verify_mic.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: verify_mic.c,v 1.32 2005/04/27 17:51:04 lha Exp $");
+
+static OM_uint32
+verify_mic_des
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t * qop_state,
+ krb5_keyblock *key,
+ char *type
+ )
+{
+ u_char *p;
+ MD5_CTX md5;
+ u_char hash[16], *seq;
+ DES_key_schedule schedule;
+ DES_cblock zero;
+ DES_cblock deskey;
+ int32_t seq_number;
+ OM_uint32 ret;
+ int cmp;
+
+ p = token_buffer->value;
+ ret = gssapi_krb5_verify_header (&p,
+ token_buffer->length,
+ type,
+ GSS_KRB5_MECHANISM);
+ if (ret)
+ return ret;
+
+ if (memcmp(p, "\x00\x00", 2) != 0)
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
+ return GSS_S_BAD_MIC;
+ p += 4;
+ p += 16;
+
+ /* verify checksum */
+ MD5_Init (&md5);
+ MD5_Update (&md5, p - 24, 8);
+ MD5_Update (&md5, message_buffer->value,
+ message_buffer->length);
+ MD5_Final (hash, &md5);
+
+ memset (&zero, 0, sizeof(zero));
+ memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+ &schedule, &zero);
+ if (memcmp (p - 8, hash, 8) != 0) {
+ memset (deskey, 0, sizeof(deskey));
+ memset (&schedule, 0, sizeof(schedule));
+ return GSS_S_BAD_MIC;
+ }
+
+ /* verify sequence number */
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+ p -= 16;
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_encrypt ((void *)p, (void *)p, 8,
+ &schedule, (DES_cblock *)hash, DES_DECRYPT);
+
+ memset (deskey, 0, sizeof(deskey));
+ memset (&schedule, 0, sizeof(schedule));
+
+ seq = p;
+ gssapi_decode_om_uint32(seq, &seq_number);
+
+ if (context_handle->more_flags & LOCAL)
+ cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+ else
+ cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+ if (cmp != 0) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_BAD_MIC;
+ }
+
+ ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+ if (ret) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return ret;
+ }
+
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+verify_mic_des3
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t * qop_state,
+ krb5_keyblock *key,
+ char *type
+ )
+{
+ u_char *p;
+ u_char *seq;
+ int32_t seq_number;
+ OM_uint32 ret;
+ krb5_crypto crypto;
+ krb5_data seq_data;
+ int cmp, docompat;
+ Checksum csum;
+ char *tmp;
+ char ivec[8];
+
+ p = token_buffer->value;
+ ret = gssapi_krb5_verify_header (&p,
+ token_buffer->length,
+ type,
+ GSS_KRB5_MECHANISM);
+ if (ret)
+ return ret;
+
+ if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
+ return GSS_S_BAD_SIG;
+ p += 2;
+ if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
+ return GSS_S_BAD_MIC;
+ p += 4;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key,
+ ETYPE_DES3_CBC_NONE, &crypto);
+ if (ret){
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* verify sequence number */
+ docompat = 0;
+retry:
+ if (docompat)
+ memset(ivec, 0, 8);
+ else
+ memcpy(ivec, p + 8, 8);
+
+ ret = krb5_decrypt_ivec (gssapi_krb5_context,
+ crypto,
+ KRB5_KU_USAGE_SEQ,
+ p, 8, &seq_data, ivec);
+ if (ret) {
+ if (docompat++) {
+ gssapi_krb5_set_error_string ();
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ } else
+ goto retry;
+ }
+
+ if (seq_data.length != 8) {
+ krb5_data_free (&seq_data);
+ if (docompat++) {
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ return GSS_S_BAD_MIC;
+ } else
+ goto retry;
+ }
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+ seq = seq_data.data;
+ gssapi_decode_om_uint32(seq, &seq_number);
+
+ if (context_handle->more_flags & LOCAL)
+ cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+ else
+ cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+ krb5_data_free (&seq_data);
+ if (cmp != 0) {
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_BAD_MIC;
+ }
+
+ ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+ if (ret) {
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ *minor_status = 0;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return ret;
+ }
+
+ /* verify checksum */
+
+ tmp = malloc (message_buffer->length + 8);
+ if (tmp == NULL) {
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy (tmp, p - 8, 8);
+ memcpy (tmp + 8, message_buffer->value, message_buffer->length);
+
+ csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
+ csum.checksum.length = 20;
+ csum.checksum.data = p + 8;
+
+ ret = krb5_verify_checksum (gssapi_krb5_context, crypto,
+ KRB5_KU_USAGE_SIGN,
+ tmp, message_buffer->length + 8,
+ &csum);
+ free (tmp);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ *minor_status = ret;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ return GSS_S_BAD_MIC;
+ }
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_verify_mic_internal
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t * qop_state,
+ char * type
+ )
+{
+ krb5_keyblock *key;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+
+ ret = gss_krb5_get_subkey(context_handle, &key);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ *minor_status = 0;
+ krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+ switch (keytype) {
+ case KEYTYPE_DES :
+ ret = verify_mic_des (minor_status, context_handle,
+ message_buffer, token_buffer, qop_state, key,
+ type);
+ break;
+ case KEYTYPE_DES3 :
+ ret = verify_mic_des3 (minor_status, context_handle,
+ message_buffer, token_buffer, qop_state, key,
+ type);
+ break;
+ case KEYTYPE_ARCFOUR :
+ case KEYTYPE_ARCFOUR_56 :
+ ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
+ message_buffer, token_buffer,
+ qop_state, key, type);
+ break;
+ default :
+ ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
+ message_buffer, token_buffer, qop_state,
+ key);
+ break;
+ }
+ krb5_free_keyblock (gssapi_krb5_context, key);
+
+ return ret;
+}
+
+OM_uint32
+gss_verify_mic
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t * qop_state
+ )
+{
+ OM_uint32 ret;
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ ret = gss_verify_mic_internal(minor_status, context_handle,
+ message_buffer, token_buffer,
+ qop_state, "\x01\x01");
+
+ return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/wrap.c b/source4/heimdal/lib/gssapi/wrap.c
new file mode 100644
index 0000000000..bdb09e633b
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/wrap.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: wrap.c,v 1.31 2005/01/05 02:52:12 lukeh Exp $");
+
+OM_uint32
+gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t key)
+{
+ krb5_error_code ret;
+ krb5_keyblock *skey = NULL;
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ if (context_handle->more_flags & LOCAL) {
+ ret = krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
+ }
+
+ } else {
+ ret = krb5_auth_con_getremotesubkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
+ }
+
+ }
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ key->length = skey->keyvalue.length;
+ key->value = malloc (key->length);
+ if (!key->value) {
+ krb5_free_keyblock(gssapi_krb5_context, skey);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(key->value, skey->keyvalue.data, key->length);
+ krb5_free_keyblock(gssapi_krb5_context, skey);
+ return 0;
+}
+
+OM_uint32
+gss_krb5_get_subkey(const gss_ctx_id_t context_handle,
+ krb5_keyblock **key)
+{
+ krb5_keyblock *skey = NULL;
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ if (context_handle->more_flags & LOCAL) {
+ krb5_auth_con_getremotesubkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ } else {
+ krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ }
+ /*
+ * Only use the initiator subkey or ticket session key if
+ * an acceptor subkey was not required.
+ */
+ if (skey == NULL &&
+ (context_handle->more_flags & ACCEPTOR_SUBKEY) == 0) {
+ if (context_handle->more_flags & LOCAL) {
+ krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ } else {
+ krb5_auth_con_getremotesubkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ }
+ if(skey == NULL)
+ krb5_auth_con_getkey(gssapi_krb5_context,
+ context_handle->auth_context,
+ &skey);
+ }
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ if(skey == NULL)
+ return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
+ *key = skey;
+ return 0;
+}
+
+static OM_uint32
+sub_wrap_size (
+ OM_uint32 req_output_size,
+ OM_uint32 * max_input_size,
+ int blocksize,
+ int extrasize
+ )
+{
+ size_t len, total_len;
+
+ len = 8 + req_output_size + blocksize + extrasize;
+
+ gssapi_krb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ total_len -= req_output_size; /* token length */
+ if (total_len < req_output_size) {
+ *max_input_size = (req_output_size - total_len);
+ (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
+ } else {
+ *max_input_size = 0;
+ }
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_wrap_size_limit (
+ OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 * max_input_size
+ )
+{
+ krb5_keyblock *key;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+
+ ret = gss_krb5_get_subkey(context_handle, &key);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+ switch (keytype) {
+ case KEYTYPE_DES :
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
+ break;
+ case KEYTYPE_DES3 :
+ ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
+ break;
+ default :
+ ret = _gssapi_wrap_size_cfx(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ req_output_size, max_input_size, key);
+ break;
+ }
+ krb5_free_keyblock (gssapi_krb5_context, key);
+ *minor_status = 0;
+ return ret;
+}
+
+static OM_uint32
+wrap_des
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int * conf_state,
+ gss_buffer_t output_message_buffer,
+ krb5_keyblock *key
+ )
+{
+ u_char *p;
+ MD5_CTX md5;
+ u_char hash[16];
+ DES_key_schedule schedule;
+ DES_cblock deskey;
+ DES_cblock zero;
+ int i;
+ int32_t seq_number;
+ size_t len, total_len, padlength, datalen;
+
+ padlength = 8 - (input_message_buffer->length % 8);
+ datalen = input_message_buffer->length + padlength + 8;
+ len = datalen + 22;
+ gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ output_message_buffer->length = total_len;
+ output_message_buffer->value = malloc (total_len);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = gssapi_krb5_make_header(output_message_buffer->value,
+ len,
+ "\x02\x01", /* TOK_ID */
+ GSS_KRB5_MECHANISM);
+
+ /* SGN_ALG */
+ memcpy (p, "\x00\x00", 2);
+ p += 2;
+ /* SEAL_ALG */
+ if(conf_req_flag)
+ memcpy (p, "\x00\x00", 2);
+ else
+ memcpy (p, "\xff\xff", 2);
+ p += 2;
+ /* Filler */
+ memcpy (p, "\xff\xff", 2);
+ p += 2;
+
+ /* fill in later */
+ memset (p, 0, 16);
+ p += 16;
+
+ /* confounder + data + pad */
+ krb5_generate_random_block(p, 8);
+ memcpy (p + 8, input_message_buffer->value,
+ input_message_buffer->length);
+ memset (p + 8 + input_message_buffer->length, padlength, padlength);
+
+ /* checksum */
+ MD5_Init (&md5);
+ MD5_Update (&md5, p - 24, 8);
+ MD5_Update (&md5, p, datalen);
+ MD5_Final (hash, &md5);
+
+ memset (&zero, 0, sizeof(zero));
+ memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+ &schedule, &zero);
+ memcpy (p - 8, hash, 8);
+
+ /* sequence number */
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+
+ p -= 16;
+ p[0] = (seq_number >> 0) & 0xFF;
+ p[1] = (seq_number >> 8) & 0xFF;
+ p[2] = (seq_number >> 16) & 0xFF;
+ p[3] = (seq_number >> 24) & 0xFF;
+ memset (p + 4,
+ (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+ 4);
+
+ DES_set_key (&deskey, &schedule);
+ DES_cbc_encrypt ((void *)p, (void *)p, 8,
+ &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
+
+ krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /* encrypt the data */
+ p += 16;
+
+ if(conf_req_flag) {
+ memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+ for (i = 0; i < sizeof(deskey); ++i)
+ deskey[i] ^= 0xf0;
+ DES_set_key (&deskey, &schedule);
+ memset (&zero, 0, sizeof(zero));
+ DES_cbc_encrypt ((void *)p,
+ (void *)p,
+ datalen,
+ &schedule,
+ &zero,
+ DES_ENCRYPT);
+ }
+ memset (deskey, 0, sizeof(deskey));
+ memset (&schedule, 0, sizeof(schedule));
+
+ if(conf_state != NULL)
+ *conf_state = conf_req_flag;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+wrap_des3
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int * conf_state,
+ gss_buffer_t output_message_buffer,
+ krb5_keyblock *key
+ )
+{
+ u_char *p;
+ u_char seq[8];
+ int32_t seq_number;
+ size_t len, total_len, padlength, datalen;
+ u_int32_t ret;
+ krb5_crypto crypto;
+ Checksum cksum;
+ krb5_data encdata;
+
+ padlength = 8 - (input_message_buffer->length % 8);
+ datalen = input_message_buffer->length + padlength + 8;
+ len = datalen + 34;
+ gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ output_message_buffer->length = total_len;
+ output_message_buffer->value = malloc (total_len);
+ if (output_message_buffer->value == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = gssapi_krb5_make_header(output_message_buffer->value,
+ len,
+ "\x02\x01", /* TOK_ID */
+ GSS_KRB5_MECHANISM);
+
+ /* SGN_ALG */
+ memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */
+ p += 2;
+ /* SEAL_ALG */
+ if(conf_req_flag)
+ memcpy (p, "\x02\x00", 2); /* DES3-KD */
+ else
+ memcpy (p, "\xff\xff", 2);
+ p += 2;
+ /* Filler */
+ memcpy (p, "\xff\xff", 2);
+ p += 2;
+
+ /* calculate checksum (the above + confounder + data + pad) */
+
+ memcpy (p + 20, p - 8, 8);
+ krb5_generate_random_block(p + 28, 8);
+ memcpy (p + 28 + 8, input_message_buffer->value,
+ input_message_buffer->length);
+ memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ free (output_message_buffer->value);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ ret = krb5_create_checksum (gssapi_krb5_context,
+ crypto,
+ KRB5_KU_USAGE_SIGN,
+ 0,
+ p + 20,
+ datalen + 8,
+ &cksum);
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ free (output_message_buffer->value);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* zero out SND_SEQ + SGN_CKSUM in case */
+ memset (p, 0, 28);
+
+ memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
+ free_Checksum (&cksum);
+
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ /* sequence number */
+ krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ &seq_number);
+
+ seq[0] = (seq_number >> 0) & 0xFF;
+ seq[1] = (seq_number >> 8) & 0xFF;
+ seq[2] = (seq_number >> 16) & 0xFF;
+ seq[3] = (seq_number >> 24) & 0xFF;
+ memset (seq + 4,
+ (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+ 4);
+
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key, ETYPE_DES3_CBC_NONE,
+ &crypto);
+ if (ret) {
+ free (output_message_buffer->value);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ {
+ DES_cblock ivec;
+
+ memcpy (&ivec, p + 8, 8);
+ ret = krb5_encrypt_ivec (gssapi_krb5_context,
+ crypto,
+ KRB5_KU_USAGE_SEQ,
+ seq, 8, &encdata,
+ &ivec);
+ }
+ krb5_crypto_destroy (gssapi_krb5_context, crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ free (output_message_buffer->value);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ assert (encdata.length == 8);
+
+ memcpy (p, encdata.data, encdata.length);
+ krb5_data_free (&encdata);
+
+ krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+ context_handle->auth_context,
+ ++seq_number);
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ /* encrypt the data */
+ p += 28;
+
+ if(conf_req_flag) {
+ krb5_data tmp;
+
+ ret = krb5_crypto_init(gssapi_krb5_context, key,
+ ETYPE_DES3_CBC_NONE, &crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ free (output_message_buffer->value);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ ret = krb5_encrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
+ p, datalen, &tmp);
+ krb5_crypto_destroy(gssapi_krb5_context, crypto);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ free (output_message_buffer->value);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ assert (tmp.length == datalen);
+
+ memcpy (p, tmp.data, datalen);
+ krb5_data_free(&tmp);
+ }
+ if(conf_state != NULL)
+ *conf_state = conf_req_flag;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_wrap
+ (OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int * conf_state,
+ gss_buffer_t output_message_buffer
+ )
+{
+ krb5_keyblock *key;
+ OM_uint32 ret;
+ krb5_keytype keytype;
+
+ ret = gss_krb5_get_subkey(context_handle, &key);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+ switch (keytype) {
+ case KEYTYPE_DES :
+ ret = wrap_des (minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer, key);
+ break;
+ case KEYTYPE_DES3 :
+ ret = wrap_des3 (minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer, key);
+ break;
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_wrap_arcfour (minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer, key);
+ break;
+ default :
+ ret = _gssapi_wrap_cfx (minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer, key);
+ break;
+ }
+ krb5_free_keyblock (gssapi_krb5_context, key);
+ return ret;
+}