summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/gssapi/spnego
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/gssapi/spnego')
-rw-r--r--source4/heimdal/lib/gssapi/spnego/accept_sec_context.c978
-rw-r--r--source4/heimdal/lib/gssapi/spnego/compat.c154
-rw-r--r--source4/heimdal/lib/gssapi/spnego/context_stubs.c88
-rw-r--r--source4/heimdal/lib/gssapi/spnego/init_sec_context.c219
-rw-r--r--source4/heimdal/lib/gssapi/spnego/spnego-private.h25
-rw-r--r--source4/heimdal/lib/gssapi/spnego/spnego.asn117
-rw-r--r--source4/heimdal/lib/gssapi/spnego/spnego_locl.h27
7 files changed, 940 insertions, 568 deletions
diff --git a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
index 8a885a3e2f..2c86b3f794 100644
--- a/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/spnego/accept_sec_context.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* Portions Copyright (c) 2004 PADL Software Pty Ltd.
*
@@ -33,203 +33,85 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: accept_sec_context.c,v 1.6 2006/10/07 22:26:57 lha Exp $");
-
-OM_uint32
-_gss_spnego_encode_response(OM_uint32 *minor_status,
- const NegTokenResp *resp,
- gss_buffer_t 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_NegTokenResp(buf + buf_size - 1,
- buf_size,
- resp, &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->value = buf + buf_size - buf_len;
- data->length = buf_len;
- *ret_buf = buf;
-
- return GSS_S_COMPLETE;
-}
+RCSID("$Id: accept_sec_context.c,v 1.16 2006/12/19 12:10:35 lha Exp $");
static OM_uint32
send_reject (OM_uint32 *minor_status,
gss_buffer_t output_token)
{
- NegTokenResp resp;
- gss_buffer_desc data;
- u_char *buf;
- OM_uint32 ret;
+ NegotiationToken nt;
+ size_t size;
+
+ nt.element = choice_NegotiationToken_negTokenResp;
- ALLOC(resp.negResult, 1);
- if (resp.negResult == NULL) {
+ ALLOC(nt.u.negTokenResp.negResult, 1);
+ if (nt.u.negTokenResp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- *(resp.negResult) = reject;
- resp.supportedMech = NULL;
- resp.responseToken = NULL;
- resp.mechListMIC = NULL;
+ *(nt.u.negTokenResp.negResult) = reject;
+ nt.u.negTokenResp.supportedMech = NULL;
+ nt.u.negTokenResp.responseToken = NULL;
+ nt.u.negTokenResp.mechListMIC = NULL;
- ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf);
- free_NegTokenResp(&resp);
- if (ret != GSS_S_COMPLETE)
- return ret;
+ ASN1_MALLOC_ENCODE(NegotiationToken,
+ output_token->value, output_token->length, &nt,
+ &size, *minor_status);
+ free_NegotiationToken(&nt);
+ if (*minor_status != 0)
+ return GSS_S_FAILURE;
- 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.value, output_token->length);
- }
- free(buf);
- if (ret != GSS_S_COMPLETE)
- return ret;
return GSS_S_BAD_MECH;
}
-OM_uint32
-_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
- int includeMSCompatOID,
- const gssspnego_cred cred_handle,
- MechTypeList *mechtypelist,
- gss_OID *preferred_mech)
+static OM_uint32
+acceptor_approved(gss_name_t target_name, gss_OID mech)
{
- OM_uint32 ret;
- gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
- int i, count;
-
- if (cred_handle != NULL) {
- ret = gss_inquire_cred(minor_status,
- cred_handle->negotiated_cred_id,
- NULL,
- NULL,
- NULL,
- &supported_mechs);
- } else {
- ret = gss_indicate_mechs(minor_status, &supported_mechs);
- }
+ gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+ gss_OID_set oidset;
+ OM_uint32 junk, ret;
- if (ret != GSS_S_COMPLETE) {
- return ret;
- }
+ if (target_name == GSS_C_NO_NAME)
+ return GSS_S_COMPLETE;
- if (supported_mechs->count == 0) {
- *minor_status = ENOENT;
- gss_release_oid_set(minor_status, &supported_mechs);
- return GSS_S_FAILURE;
- }
-
- count = supported_mechs->count;
- if (includeMSCompatOID)
- count++;
-
- mechtypelist->len = 0;
- mechtypelist->val = calloc(count, sizeof(MechType));
- if (mechtypelist->val == NULL) {
- *minor_status = ENOMEM;
- gss_release_oid_set(minor_status, &supported_mechs);
- return GSS_S_FAILURE;
- }
-
- for (i = 0; i < supported_mechs->count; i++) {
- ret = _gss_spnego_add_mech_type(&supported_mechs->elements[i],
- includeMSCompatOID,
- mechtypelist);
- if (ret != 0) {
- *minor_status = ENOMEM;
- ret = GSS_S_FAILURE;
- break;
- }
- }
-
- if (ret == GSS_S_COMPLETE && preferred_mech != NULL) {
- ret = gss_duplicate_oid(minor_status,
- &supported_mechs->elements[0],
- preferred_mech);
- }
-
- if (ret != GSS_S_COMPLETE) {
- free_MechTypeList(mechtypelist);
- mechtypelist->len = 0;
- mechtypelist->val = NULL;
- }
- gss_release_oid_set(minor_status, &supported_mechs);
-
- return ret;
+ gss_create_empty_oid_set(&junk, &oidset);
+ gss_add_oid_set_member(&junk, mech, &oidset);
+
+ ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,
+ GSS_C_ACCEPT, &cred, NULL, NULL);
+ gss_release_oid_set(&junk, &oidset);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+ gss_release_cred(&junk, &cred);
+
+ return GSS_S_COMPLETE;
}
static OM_uint32
send_supported_mechs (OM_uint32 *minor_status,
gss_buffer_t output_token)
{
- NegTokenInit ni;
+ NegotiationTokenWin nt;
char hostname[MAXHOSTNAMELEN], *p;
gss_buffer_desc name_buf;
gss_OID name_type;
gss_name_t target_princ;
gss_name_t canon_princ;
- OM_uint32 ret, minor;
- u_char *buf;
- size_t buf_size, buf_len;
+ OM_uint32 minor;
+ size_t buf_len;
gss_buffer_desc data;
+ OM_uint32 ret;
- memset(&ni, 0, sizeof(ni));
+ memset(&nt, 0, sizeof(nt));
- ni.reqFlags = NULL;
- ni.mechToken = NULL;
- ni.negHints = NULL;
- ni.mechListMIC = NULL;
+ nt.element = choice_NegotiationTokenWin_negTokenInit;
+ nt.u.negTokenInit.reqFlags = NULL;
+ nt.u.negTokenInit.mechToken = NULL;
+ nt.u.negTokenInit.negHints = NULL;
- ret = _gss_spnego_indicate_mechtypelist(minor_status, 1,
- NULL,
- &ni.mechTypes, NULL);
+ ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME,
+ acceptor_approved, 1, NULL,
+ &nt.u.negTokenInit.mechTypes, NULL);
if (ret != GSS_S_COMPLETE) {
return ret;
}
@@ -237,7 +119,7 @@ send_supported_mechs (OM_uint32 *minor_status,
memset(&target_princ, 0, sizeof(target_princ));
if (gethostname(hostname, sizeof(hostname) - 1) != 0) {
*minor_status = errno;
- free_NegTokenInit(&ni);
+ free_NegotiationTokenWin(&nt);
return GSS_S_FAILURE;
}
@@ -255,6 +137,7 @@ send_supported_mechs (OM_uint32 *minor_status,
GSS_C_NO_OID,
&target_princ);
if (ret != GSS_S_COMPLETE) {
+ free_NegotiationTokenWin(&nt);
return ret;
}
@@ -267,6 +150,7 @@ send_supported_mechs (OM_uint32 *minor_status,
GSS_C_NO_OID,
&canon_princ);
if (ret != GSS_S_COMPLETE) {
+ free_NegotiationTokenWin(&nt);
gss_release_name(&minor, &target_princ);
return ret;
}
@@ -274,6 +158,7 @@ send_supported_mechs (OM_uint32 *minor_status,
ret = gss_display_name(minor_status, canon_princ,
&name_buf, &name_type);
if (ret != GSS_S_COMPLETE) {
+ free_NegotiationTokenWin(&nt);
gss_release_name(&minor, &canon_princ);
gss_release_name(&minor, &target_princ);
return ret;
@@ -282,81 +167,38 @@ send_supported_mechs (OM_uint32 *minor_status,
gss_release_name(&minor, &canon_princ);
gss_release_name(&minor, &target_princ);
- ALLOC(ni.negHints, 1);
- if (ni.negHints == NULL) {
+ ALLOC(nt.u.negTokenInit.negHints, 1);
+ if (nt.u.negTokenInit.negHints == NULL) {
*minor_status = ENOMEM;
gss_release_buffer(&minor, &name_buf);
- free_NegTokenInit(&ni);
+ free_NegotiationTokenWin(&nt);
return GSS_S_FAILURE;
}
- ALLOC(ni.negHints->hintName, 1);
- if (ni.negHints->hintName == NULL) {
+ ALLOC(nt.u.negTokenInit.negHints->hintName, 1);
+ if (nt.u.negTokenInit.negHints->hintName == NULL) {
*minor_status = ENOMEM;
gss_release_buffer(&minor, &name_buf);
- free_NegTokenInit(&ni);
+ free_NegotiationTokenWin(&nt);
return GSS_S_FAILURE;
}
- *(ni.negHints->hintName) = name_buf.value;
+ *(nt.u.negTokenInit.negHints->hintName) = name_buf.value;
name_buf.value = NULL;
- ni.negHints->hintAddress = NULL;
+ nt.u.negTokenInit.negHints->hintAddress = NULL;
- buf_size = 1024;
- buf = malloc(buf_size);
- if (buf == NULL) {
- free_NegTokenInit(&ni);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
+ ASN1_MALLOC_ENCODE(NegotiationTokenWin,
+ data.value, data.length, &nt, &buf_len, ret);
+ free_NegotiationTokenWin(&nt);
+ if (ret) {
+ return ret;
}
+ if (data.length != buf_len)
+ abort();
- do {
- ret = encode_NegTokenInit(buf + buf_size - 1,
- buf_size,
- &ni, &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,
- 0,
- &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);
- free_NegTokenInit(&ni);
- return GSS_S_FAILURE;
- }
- buf = tmp;
- } else {
- *minor_status = ret;
- free(buf);
- free_NegTokenInit(&ni);
- return GSS_S_FAILURE;
- }
- }
- } while (ret == ASN1_OVERFLOW);
+ ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);
- data.value = buf + buf_size - buf_len;
- data.length = buf_len;
-
- ret = gss_encapsulate_token(&data,
- GSS_SPNEGO_MECHANISM,
- output_token);
- free (buf);
- free_NegTokenInit (&ni);
+ free (data.value);
if (ret != GSS_S_COMPLETE)
return ret;
@@ -374,16 +216,17 @@ send_accept (OM_uint32 *minor_status,
gss_buffer_t mech_buf,
gss_buffer_t output_token)
{
- NegTokenResp resp;
- gss_buffer_desc data;
- u_char *buf;
+ NegotiationToken nt;
OM_uint32 ret;
gss_buffer_desc mech_mic_buf;
+ size_t size;
- memset(&resp, 0, sizeof(resp));
+ memset(&nt, 0, sizeof(nt));
- ALLOC(resp.negResult, 1);
- if (resp.negResult == NULL) {
+ nt.element = choice_NegotiationToken_negTokenResp;
+
+ ALLOC(nt.u.negTokenResp.negResult, 1);
+ if (nt.u.negTokenResp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
@@ -392,79 +235,85 @@ send_accept (OM_uint32 *minor_status,
if (mech_token != GSS_C_NO_BUFFER
&& mech_token->length != 0
&& mech_buf != GSS_C_NO_BUFFER)
- *(resp.negResult) = accept_incomplete;
+ *(nt.u.negTokenResp.negResult) = accept_incomplete;
else
- *(resp.negResult) = accept_completed;
+ *(nt.u.negTokenResp.negResult) = accept_completed;
} else {
if (initial_response && context_handle->require_mic)
- *(resp.negResult) = request_mic;
+ *(nt.u.negTokenResp.negResult) = request_mic;
else
- *(resp.negResult) = accept_incomplete;
+ *(nt.u.negTokenResp.negResult) = accept_incomplete;
}
if (initial_response) {
- ALLOC(resp.supportedMech, 1);
- if (resp.supportedMech == NULL) {
- free_NegTokenResp(&resp);
+ ALLOC(nt.u.negTokenResp.supportedMech, 1);
+ if (nt.u.negTokenResp.supportedMech == NULL) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
ret = der_get_oid(context_handle->preferred_mech_type->elements,
context_handle->preferred_mech_type->length,
- resp.supportedMech,
+ nt.u.negTokenResp.supportedMech,
NULL);
if (ret) {
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
} else {
- resp.supportedMech = NULL;
+ nt.u.negTokenResp.supportedMech = NULL;
}
if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
- ALLOC(resp.responseToken, 1);
- if (resp.responseToken == NULL) {
- free_NegTokenResp(&resp);
+ ALLOC(nt.u.negTokenResp.responseToken, 1);
+ if (nt.u.negTokenResp.responseToken == NULL) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- resp.responseToken->length = mech_token->length;
- resp.responseToken->data = mech_token->value;
+ nt.u.negTokenResp.responseToken->length = mech_token->length;
+ nt.u.negTokenResp.responseToken->data = mech_token->value;
mech_token->length = 0;
mech_token->value = NULL;
} else {
- resp.responseToken = NULL;
+ nt.u.negTokenResp.responseToken = NULL;
}
if (mech_buf != GSS_C_NO_BUFFER) {
- ALLOC(resp.mechListMIC, 1);
- if (resp.mechListMIC == NULL) {
- free_NegTokenResp(&resp);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
-
ret = gss_get_mic(minor_status,
context_handle->negotiated_ctx_id,
0,
mech_buf,
&mech_mic_buf);
- if (ret != GSS_S_COMPLETE) {
- free_NegTokenResp(&resp);
+ if (ret == GSS_S_COMPLETE) {
+ ALLOC(nt.u.negTokenResp.mechListMIC, 1);
+ if (nt.u.negTokenResp.mechListMIC == NULL) {
+ gss_release_buffer(minor_status, &mech_mic_buf);
+ free_NegotiationToken(&nt);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;
+ nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value;
+ } else if (ret == GSS_S_UNAVAILABLE) {
+ nt.u.negTokenResp.mechListMIC = NULL;
+ } else {
+ free_NegotiationToken(&nt);
return ret;
}
- resp.mechListMIC->length = mech_mic_buf.length;
- resp.mechListMIC->data = mech_mic_buf.value;
} else
- resp.mechListMIC = NULL;
+ nt.u.negTokenResp.mechListMIC = NULL;
- ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf);
- if (ret != GSS_S_COMPLETE) {
- free_NegTokenResp(&resp);
- return ret;
+ ASN1_MALLOC_ENCODE(NegotiationToken,
+ output_token->value, output_token->length,
+ &nt, &size, ret);
+ if (ret) {
+ free_NegotiationToken(&nt);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
}
/*
@@ -472,23 +321,12 @@ send_accept (OM_uint32 *minor_status,
* it is a SubsequentContextToken (note though RFC 1964
* specifies encapsulation for all _Kerberos_ tokens).
*/
- 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.value, output_token->length);
- }
- free(buf);
- if (ret != GSS_S_COMPLETE) {
- free_NegTokenResp(&resp);
- return ret;
- }
- ret = (*(resp.negResult) == accept_completed) ? GSS_S_COMPLETE :
- GSS_S_CONTINUE_NEEDED;
- free_NegTokenResp(&resp);
+ if (*(nt.u.negTokenResp.negResult) == accept_completed)
+ ret = GSS_S_COMPLETE;
+ else
+ ret = GSS_S_CONTINUE_NEEDED;
+ free_NegotiationToken(&nt);
return ret;
}
@@ -530,8 +368,164 @@ verify_mechlist_mic
return ret;
}
-OM_uint32
-_gss_spnego_accept_sec_context
+static OM_uint32
+select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p,
+ gss_OID *mech_p)
+{
+ char mechbuf[64];
+ size_t mech_len;
+ gss_OID_desc oid;
+ OM_uint32 ret, junk;
+
+ ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
+ sizeof(mechbuf),
+ mechType,
+ &mech_len);
+ if (ret) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ oid.length = mech_len;
+ oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
+
+ if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
+ return GSS_S_BAD_MECH;
+ }
+
+ *minor_status = 0;
+
+ /* Translate broken MS Kebreros OID */
+ if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) {
+ gssapi_mech_interface mech;
+
+ mech = __gss_get_mechanism(&_gss_spnego_krb5_mechanism_oid_desc);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ ret = gss_duplicate_oid(minor_status,
+ &_gss_spnego_mskrb_mechanism_oid_desc,
+ mech_p);
+ } else {
+ gssapi_mech_interface mech;
+
+ mech = __gss_get_mechanism(&oid);
+ if (mech == NULL)
+ return GSS_S_BAD_MECH;
+
+ ret = gss_duplicate_oid(minor_status,
+ &mech->gm_mech_oid,
+ mech_p);
+ }
+
+ if (verify_p) {
+ gss_name_t name = GSS_C_NO_NAME;
+ gss_buffer_desc namebuf;
+ char *str = NULL, *host, hostname[MAXHOSTNAMELEN];
+
+ host = getenv("GSSAPI_SPNEGO_NAME");
+ if (host == NULL || issuid()) {
+ if (gethostname(hostname, sizeof(hostname)) != 0) {
+ *minor_status = errno;
+ return GSS_S_FAILURE;
+ }
+ asprintf(&str, "host@%s", hostname);
+ host = str;
+ }
+
+ namebuf.length = strlen(host);
+ namebuf.value = host;
+
+ ret = gss_import_name(minor_status, &namebuf,
+ GSS_C_NT_HOSTBASED_SERVICE, &name);
+ if (str)
+ free(str);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+
+ ret = acceptor_approved(name, *mech_p);
+ gss_release_name(&junk, &name);
+ }
+
+ return ret;
+}
+
+
+static OM_uint32
+acceptor_complete(OM_uint32 * minor_status,
+ gssspnego_ctx ctx,
+ int *get_mic,
+ gss_buffer_t mech_buf,
+ gss_buffer_t mech_input_token,
+ gss_buffer_t mech_output_token,
+ heim_octet_string *mic,
+ gss_buffer_t output_token)
+{
+ OM_uint32 ret;
+ int require_mic, verify_mic;
+ gss_buffer_desc buf;
+
+ buf.length = 0;
+ buf.value = NULL;
+
+ ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic);
+ if (ret)
+ return ret;
+
+ ctx->require_mic = require_mic;
+
+ if (mic != NULL)
+ require_mic = 1;
+
+ if (ctx->open && require_mic) {
+ if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
+ verify_mic = 1;
+ *get_mic = 0;
+ } else if (mech_output_token != GSS_C_NO_BUFFER &&
+ mech_output_token->length == 0) { /* Odd */
+ *get_mic = verify_mic = 1;
+ } else { /* Even/One */
+ verify_mic = 0;
+ *get_mic = 1;
+ }
+
+ if (verify_mic || get_mic) {
+ int eret;
+ size_t buf_len;
+
+ ASN1_MALLOC_ENCODE(MechTypeList,
+ mech_buf->value, mech_buf->length,
+ &ctx->initiator_mech_types, &buf_len, eret);
+ if (eret) {
+ *minor_status = eret;
+ return GSS_S_FAILURE;
+ }
+ if (buf.length != buf_len)
+ abort();
+ }
+
+ if (verify_mic) {
+ ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);
+ if (ret) {
+ if (get_mic)
+ send_reject (minor_status, output_token);
+ if (buf.value)
+ free(buf.value);
+ return ret;
+ }
+ ctx->verified_mic = 1;
+ }
+ if (buf.value)
+ free(buf.value);
+
+ } else
+ *get_mic = verify_mic = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+
+static OM_uint32
+acceptor_start
(OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_cred_id_t acceptor_cred_handle,
@@ -547,40 +541,21 @@ _gss_spnego_accept_sec_context
{
OM_uint32 ret, ret2, minor;
NegTokenInit ni;
- NegTokenResp na;
- size_t ni_len, na_len;
+ size_t ni_len;
int i;
gss_buffer_desc data;
size_t len, taglen;
- int initialToken;
- unsigned int negResult = accept_incomplete;
gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
- gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
+ gss_buffer_desc mech_output_token;
gss_buffer_desc mech_buf;
gss_OID preferred_mech_type = GSS_C_NO_OID;
gssspnego_ctx ctx;
gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle;
+ int get_mic = 0;
+ int first_ok = 0;
- *minor_status = 0;
-
- output_token->length = 0;
- output_token->value = NULL;
-
- if (src_name != NULL)
- *src_name = GSS_C_NO_NAME;
-
- if (mech_type != NULL)
- *mech_type = GSS_C_NO_OID;
-
- if (ret_flags != NULL)
- *ret_flags = 0;
-
- if (time_rec != NULL)
- *time_rec = 0;
-
- if (delegated_cred_handle != NULL)
- *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
-
+ mech_output_token.value = NULL;
+ mech_output_token.length = 0;
mech_buf.value = NULL;
if (*context_handle == GSS_C_NO_CONTEXT) {
@@ -590,8 +565,7 @@ _gss_spnego_accept_sec_context
return ret;
if (input_token_buffer->length == 0) {
- return send_supported_mechs (minor_status,
- output_token);
+ return send_supported_mechs (minor_status, output_token);
}
}
@@ -604,16 +578,12 @@ _gss_spnego_accept_sec_context
ret = gss_decapsulate_token (input_token_buffer,
GSS_SPNEGO_MECHANISM,
&data);
- initialToken = (ret == GSS_S_COMPLETE);
-
- if (!initialToken) {
- data.value = input_token_buffer->value;
- data.length = input_token_buffer->length;
- }
+ if (ret)
+ return ret;
ret = der_match_tag_and_length(data.value, data.length,
ASN1_C_CONTEXT, CONS,
- initialToken ? 0 : 1,
+ 0,
&len, &taglen);
if (ret) {
*minor_status = ret;
@@ -625,70 +595,263 @@ _gss_spnego_accept_sec_context
return GSS_S_FAILURE;
}
- if (initialToken) {
- ret = decode_NegTokenInit((const unsigned char *)data.value + taglen,
+ ret = decode_NegTokenInit((const unsigned char *)data.value + taglen,
len, &ni, &ni_len);
- } else {
- ret = decode_NegTokenResp((const unsigned char *)data.value + taglen,
- len, &na, &na_len);
- }
if (ret) {
*minor_status = ret;
return GSS_S_DEFECTIVE_TOKEN;
}
- if (!initialToken && na.negResult != NULL) {
- negResult = *(na.negResult);
+ if (ni.mechTypes.len < 1) {
+ free_NegTokenInit(&ni);
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
}
- if (negResult == reject || negResult == request_mic) {
- /* request_mic should only be sent by acceptor */
- free_NegTokenResp(&na);
- return GSS_S_DEFECTIVE_TOKEN;
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+
+ ret = copy_MechTypeList(&ni.mechTypes, &ctx->initiator_mech_types);
+ if (ret) {
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ free_NegTokenInit(&ni);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
}
- if (initialToken) {
- for (i = 0; i < ni.mechTypes.len; ++i) {
- /* Call glue layer to find first mech we support */
- ret = _gss_spnego_select_mech(minor_status, &ni.mechTypes.val[i],
- &preferred_mech_type);
+ /*
+ * First we try the opportunistic token if we have support for it,
+ * don't try to verify we have credential for the token,
+ * gss_accept_sec_context will (hopefully) tell us that.
+ * If that failes,
+ */
+
+ ret = select_mech(minor_status,
+ &ni.mechTypes.val[0],
+ 0,
+ &preferred_mech_type);
+
+ if (ret == 0 && ni.mechToken != NULL) {
+ gss_cred_id_t mech_delegated_cred = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t mech_cred;
+ gss_buffer_desc ibuf;
+
+ ibuf.length = ni.mechToken->length;
+ ibuf.value = ni.mechToken->data;
+ mech_input_token = &ibuf;
+
+ if (acceptor_cred != NULL)
+ mech_cred = acceptor_cred->negotiated_cred_id;
+ else
+ mech_cred = GSS_C_NO_CREDENTIAL;
+
+ if (ctx->mech_src_name != GSS_C_NO_NAME)
+ gss_release_name(&minor, &ctx->mech_src_name);
+
+ if (ctx->delegated_cred_id != GSS_C_NO_CREDENTIAL)
+ _gss_spnego_release_cred(&minor, &ctx->delegated_cred_id);
+
+ ret = gss_accept_sec_context(&minor,
+ &ctx->negotiated_ctx_id,
+ mech_cred,
+ mech_input_token,
+ input_chan_bindings,
+ &ctx->mech_src_name,
+ &ctx->negotiated_mech_type,
+ &mech_output_token,
+ &ctx->mech_flags,
+ &ctx->mech_time_rec,
+ &mech_delegated_cred);
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+ if (delegated_cred_handle)
+ ret = _gss_spnego_alloc_cred(minor_status,
+ mech_delegated_cred,
+ delegated_cred_handle);
+ else
+ gss_release_cred(&ret2, &mech_delegated_cred);
+
+ ctx->preferred_mech_type = preferred_mech_type;
+ ctx->negotiated_mech_type = preferred_mech_type;
+ if (ret == GSS_S_COMPLETE)
+ ctx->open = 1;
+
+ ret = acceptor_complete(minor_status,
+ ctx,
+ &get_mic,
+ &mech_buf,
+ mech_input_token,
+ &mech_output_token,
+ ni.mechListMIC,
+ output_token);
+ if (ret != GSS_S_COMPLETE)
+ goto out;
+
+ first_ok = 1;
+ }
+ }
+
+ /*
+ * If opportunistic token failed, lets try the other mechs.
+ */
+
+ if (!first_ok) {
+
+ /* Call glue layer to find first mech we support */
+ for (i = 1; i < ni.mechTypes.len; ++i) {
+ ret = select_mech(minor_status,
+ &ni.mechTypes.val[i],
+ 1,
+ &preferred_mech_type);
if (ret == 0)
break;
}
if (preferred_mech_type == GSS_C_NO_OID) {
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free_NegTokenInit(&ni);
return GSS_S_BAD_MECH;
}
+
+ ctx->preferred_mech_type = preferred_mech_type;
+ ctx->negotiated_mech_type = preferred_mech_type;
}
- HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ /*
+ * The initial token always have a response
+ */
- if (initialToken) {
- ctx->preferred_mech_type = preferred_mech_type;
- ctx->initiator_mech_types.len = ni.mechTypes.len;
- ctx->initiator_mech_types.val = ni.mechTypes.val;
- ni.mechTypes.len = 0;
- ni.mechTypes.val = NULL;
+ ret = send_accept (minor_status,
+ ctx,
+ &mech_output_token,
+ 1,
+ get_mic ? &mech_buf : NULL,
+ output_token);
+ if (ret)
+ goto out;
+
+out:
+ if (mech_output_token.value != NULL)
+ gss_release_buffer(&minor, &mech_output_token);
+ if (mech_buf.value != NULL) {
+ free(mech_buf.value);
+ mech_buf.value = NULL;
+ }
+ free_NegTokenInit(&ni);
+
+ if (ret == GSS_S_COMPLETE) {
+ if (src_name != NULL && ctx->mech_src_name != NULL) {
+ spnego_name name;
+
+ name = calloc(1, sizeof(*name));
+ if (name) {
+ name->mech = ctx->mech_src_name;
+ ctx->mech_src_name = NULL;
+ *src_name = (gss_name_t)name;
+ } else
+ *src_name = GSS_C_NO_NAME;
+ }
+ if (delegated_cred_handle != NULL) {
+ *delegated_cred_handle = ctx->delegated_cred_id;
+ ctx->delegated_cred_id = GSS_C_NO_CREDENTIAL;
+ }
+ }
+
+ if (mech_type != NULL)
+ *mech_type = ctx->negotiated_mech_type;
+ if (ret_flags != NULL)
+ *ret_flags = ctx->mech_flags;
+ if (time_rec != NULL)
+ *time_rec = ctx->mech_time_rec;
+
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ return ret;
}
+ _gss_spnego_internal_delete_sec_context(&minor, context_handle,
+ GSS_C_NO_BUFFER);
+
+ return ret;
+}
+
+
+static OM_uint32
+acceptor_continue
+ (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, minor;
+ NegTokenResp na;
+ size_t na_len;
+ gss_buffer_desc data;
+ size_t len, taglen;
+ unsigned int negResult = accept_incomplete;
+ gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
+ gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
+ gss_buffer_desc mech_buf;
+ gssspnego_ctx ctx;
+ gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle;
+
+ mech_buf.value = NULL;
+
+ ctx = (gssspnego_ctx)*context_handle;
+
+ /*
+ * The GSS-API encapsulation is only present on the initial
+ * context token (negTokenInit).
+ */
+
+ data.value = input_token_buffer->value;
+ data.length = input_token_buffer->length;
+
+ ret = der_match_tag_and_length(data.value, data.length,
+ ASN1_C_CONTEXT, CONS,
+ 1,
+ &len, &taglen);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ if (len > data.length - taglen) {
+ *minor_status = ASN1_OVERRUN;
+ return GSS_S_FAILURE;
+ }
+
+ ret = decode_NegTokenResp((const unsigned char *)data.value + taglen,
+ len, &na, &na_len);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (na.negResult != NULL) {
+ negResult = *(na.negResult);
+ }
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+
{
gss_buffer_desc ibuf, obuf;
- int require_mic, verify_mic, get_mic;
+ int require_mic, get_mic;
int require_response;
heim_octet_string *mic;
- if (initialToken) {
- if (ni.mechToken != NULL) {
- ibuf.length = ni.mechToken->length;
- ibuf.value = ni.mechToken->data;
- mech_input_token = &ibuf;
- }
+ if (na.responseToken != NULL) {
+ ibuf.length = na.responseToken->length;
+ ibuf.value = na.responseToken->data;
+ mech_input_token = &ibuf;
} else {
- if (na.responseToken != NULL) {
- ibuf.length = na.responseToken->length;
- ibuf.value = na.responseToken->data;
- mech_input_token = &ibuf;
- }
+ ibuf.value = NULL;
+ ibuf.length = 0;
}
if (mech_input_token != GSS_C_NO_BUFFER) {
@@ -737,10 +900,7 @@ _gss_spnego_accept_sec_context
mech_output_token = &obuf;
}
if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
- if (initialToken)
- free_NegTokenInit(&ni);
- else
- free_NegTokenResp(&na);
+ free_NegTokenResp(&na);
send_reject (minor_status, output_token);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
@@ -758,50 +918,19 @@ _gss_spnego_accept_sec_context
ctx->require_mic = require_mic;
- mic = initialToken ? ni.mechListMIC : na.mechListMIC;
+ mic = na.mechListMIC;
if (mic != NULL)
require_mic = 1;
- if (ctx->open && require_mic) {
- if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
- verify_mic = 1;
- get_mic = 0;
- } else if (mech_output_token != GSS_C_NO_BUFFER &&
- mech_output_token->length == 0) { /* Odd */
- get_mic = verify_mic = 1;
- } else { /* Even/One */
- verify_mic = 0;
- get_mic = 1;
- }
-
- if (verify_mic || get_mic) {
- int eret;
- size_t buf_len;
-
- ASN1_MALLOC_ENCODE(MechTypeList,
- mech_buf.value, mech_buf.length,
- &ctx->initiator_mech_types, &buf_len, eret);
- if (eret) {
- ret2 = GSS_S_FAILURE;
- *minor_status = eret;
- goto out;
- }
- if (mech_buf.length != buf_len)
- abort();
- }
-
- if (verify_mic) {
- ret2 = verify_mechlist_mic(minor_status, ctx, &mech_buf, mic);
- if (ret2) {
- if (get_mic)
- send_reject (minor_status, output_token);
- goto out;
- }
-
- ctx->verified_mic = 1;
- }
- } else
- verify_mic = get_mic = 0;
+ if (ret == GSS_S_COMPLETE)
+ ret = acceptor_complete(minor_status,
+ ctx,
+ &get_mic,
+ &mech_buf,
+ mech_input_token,
+ mech_output_token,
+ na.mechListMIC,
+ output_token);
if (ctx->mech_flags & GSS_C_DCE_STYLE)
require_response = (negResult != accept_completed);
@@ -814,12 +943,13 @@ _gss_spnego_accept_sec_context
*/
if ((mech_output_token != GSS_C_NO_BUFFER &&
mech_output_token->length != 0)
+ || (ctx->open && negResult == accept_incomplete)
|| require_response
|| get_mic) {
ret2 = send_accept (minor_status,
ctx,
mech_output_token,
- initialToken,
+ 0,
get_mic ? &mech_buf : NULL,
output_token);
if (ret2)
@@ -833,10 +963,7 @@ _gss_spnego_accept_sec_context
gss_release_buffer(&minor, mech_output_token);
if (mech_buf.value != NULL)
free(mech_buf.value);
- if (initialToken)
- free_NegTokenInit(&ni);
- else
- free_NegTokenResp(&na);
+ free_NegTokenResp(&na);
}
if (ret == GSS_S_COMPLETE) {
@@ -871,3 +998,48 @@ _gss_spnego_accept_sec_context
return ret;
}
+OM_uint32
+_gss_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
+ )
+{
+ _gss_accept_sec_context_t *func;
+
+ *minor_status = 0;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ func = acceptor_start;
+ else
+ func = acceptor_continue;
+
+
+ return (*func)(minor_status, context_handle, acceptor_cred_handle,
+ input_token_buffer, input_chan_bindings,
+ src_name, mech_type, output_token, ret_flags,
+ time_rec, delegated_cred_handle);
+}
diff --git a/source4/heimdal/lib/gssapi/spnego/compat.c b/source4/heimdal/lib/gssapi/spnego/compat.c
index aeae088258..786eac1340 100644
--- a/source4/heimdal/lib/gssapi/spnego/compat.c
+++ b/source4/heimdal/lib/gssapi/spnego/compat.c
@@ -32,7 +32,7 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $");
+RCSID("$Id: compat.c,v 1.9 2006/12/18 17:52:26 lha Exp $");
/*
* Apparently Microsoft got the OID wrong, and used
@@ -42,10 +42,10 @@ RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $");
* prefer to deal with this here rather than inside the
* Kerberos mechanism.
*/
-static gss_OID_desc gss_mskrb_mechanism_oid_desc =
+gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc =
{9, (void *)"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"};
-static gss_OID_desc gss_krb5_mechanism_oid_desc =
+gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
/*
@@ -191,8 +191,8 @@ _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
if (*require_mic) {
if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) {
*require_mic = 0;
- } else if (gss_oid_equal(ctx->negotiated_mech_type, &gss_krb5_mechanism_oid_desc) &&
- gss_oid_equal(ctx->preferred_mech_type, &gss_mskrb_mechanism_oid_desc)) {
+ } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) &&
+ gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) {
*require_mic = 0;
}
}
@@ -200,86 +200,122 @@ _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
-int _gss_spnego_add_mech_type(gss_OID mech_type,
- int includeMSCompatOID,
- MechTypeList *mechtypelist)
+static int
+add_mech_type(gss_OID mech_type,
+ int includeMSCompatOID,
+ MechTypeList *mechtypelist)
{
+ MechType mech;
int ret;
if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM))
return 0;
if (includeMSCompatOID &&
- gss_oid_equal(mech_type, &gss_krb5_mechanism_oid_desc)) {
- ret = der_get_oid(gss_mskrb_mechanism_oid_desc.elements,
- gss_mskrb_mechanism_oid_desc.length,
- &mechtypelist->val[mechtypelist->len],
+ gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) {
+ ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements,
+ _gss_spnego_mskrb_mechanism_oid_desc.length,
+ &mech,
NULL);
if (ret)
return ret;
- mechtypelist->len++;
+ ret = add_MechTypeList(mechtypelist, &mech);
+ free_MechType(&mech);
+ if (ret)
+ return ret;
}
- ret = der_get_oid(mech_type->elements,
- mech_type->length,
- &mechtypelist->val[mechtypelist->len],
- NULL);
+ ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL);
if (ret)
return ret;
- mechtypelist->len++;
-
- return 0;
+ ret = add_MechTypeList(mechtypelist, &mech);
+ free_MechType(&mech);
+ return ret;
}
+
OM_uint32
-_gss_spnego_select_mech(OM_uint32 *minor_status,
- MechType *mechType,
- gss_OID *mech_p)
+_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
+ gss_name_t target_name,
+ OM_uint32 (*func)(gss_name_t, gss_OID),
+ int includeMSCompatOID,
+ const gssspnego_cred cred_handle,
+ MechTypeList *mechtypelist,
+ gss_OID *preferred_mech)
{
- char mechbuf[64];
- size_t mech_len;
- gss_OID_desc oid;
+ gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
+ gss_OID first_mech = GSS_C_NO_OID;
OM_uint32 ret;
-
- ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
- sizeof(mechbuf),
- mechType,
- &mech_len);
- if (ret) {
- return GSS_S_DEFECTIVE_TOKEN;
+ int i;
+
+ mechtypelist->len = 0;
+ mechtypelist->val = NULL;
+
+ if (cred_handle != NULL) {
+ ret = gss_inquire_cred(minor_status,
+ cred_handle->negotiated_cred_id,
+ NULL,
+ NULL,
+ NULL,
+ &supported_mechs);
+ } else {
+ ret = gss_indicate_mechs(minor_status, &supported_mechs);
}
- oid.length = mech_len;
- oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
-
- if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
- return GSS_S_BAD_MECH;
+ if (ret != GSS_S_COMPLETE) {
+ return ret;
}
- *minor_status = 0;
-
- /* Translate broken MS Kebreros OID */
- if (gss_oid_equal(&oid, &gss_mskrb_mechanism_oid_desc)) {
- gssapi_mech_interface mech;
-
- mech = __gss_get_mechanism(&gss_krb5_mechanism_oid_desc);
- if (mech == NULL)
- return GSS_S_BAD_MECH;
+ if (supported_mechs->count == 0) {
+ *minor_status = ENOENT;
+ gss_release_oid_set(minor_status, &supported_mechs);
+ return GSS_S_FAILURE;
+ }
- ret = gss_duplicate_oid(minor_status,
- &gss_mskrb_mechanism_oid_desc,
- mech_p);
- } else {
- gssapi_mech_interface mech;
+ ret = (*func)(target_name, GSS_KRB5_MECHANISM);
+ if (ret == GSS_S_COMPLETE) {
+ ret = add_mech_type(GSS_KRB5_MECHANISM,
+ includeMSCompatOID,
+ mechtypelist);
+ if (!GSS_ERROR(ret))
+ first_mech = GSS_KRB5_MECHANISM;
+ }
+ ret = GSS_S_COMPLETE;
+
+ for (i = 0; i < supported_mechs->count; i++) {
+ OM_uint32 subret;
+ if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
+ continue;
+ if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
+ continue;
+
+ subret = (*func)(target_name, &supported_mechs->elements[i]);
+ if (subret != GSS_S_COMPLETE)
+ continue;
+
+ ret = add_mech_type(&supported_mechs->elements[i],
+ includeMSCompatOID,
+ mechtypelist);
+ if (ret != 0) {
+ *minor_status = ret;
+ ret = GSS_S_FAILURE;
+ break;
+ }
+ if (first_mech == GSS_C_NO_OID)
+ first_mech = &supported_mechs->elements[i];
+ }
- mech = __gss_get_mechanism(&oid);
- if (mech == NULL)
- return GSS_S_BAD_MECH;
+ if (mechtypelist->len == 0) {
+ gss_release_oid_set(minor_status, &supported_mechs);
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
+ }
- ret = gss_duplicate_oid(minor_status,
- &mech->gm_mech_oid,
- mech_p);
+ if (preferred_mech != NULL) {
+ ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech);
+ if (ret != GSS_S_COMPLETE)
+ free_MechTypeList(mechtypelist);
}
+ gss_release_oid_set(minor_status, &supported_mechs);
return ret;
}
-
diff --git a/source4/heimdal/lib/gssapi/spnego/context_stubs.c b/source4/heimdal/lib/gssapi/spnego/context_stubs.c
index 902ddbbdf9..57bc45a492 100644
--- a/source4/heimdal/lib/gssapi/spnego/context_stubs.c
+++ b/source4/heimdal/lib/gssapi/spnego/context_stubs.c
@@ -32,7 +32,7 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: context_stubs.c,v 1.8 2006/10/07 22:27:01 lha Exp $");
+RCSID("$Id: context_stubs.c,v 1.9 2006/12/18 12:59:44 lha Exp $");
static OM_uint32
spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs)
@@ -282,7 +282,21 @@ OM_uint32 _gss_spnego_compare_name
int * name_equal
)
{
- return gss_compare_name(minor_status, name1, name2, name_equal);
+ spnego_name n1 = (spnego_name)name1;
+ spnego_name n2 = (spnego_name)name2;
+
+ *name_equal = 0;
+
+ if (!gss_oid_equal(&n1->type, &n2->type))
+ return GSS_S_COMPLETE;
+ if (n1->value.length != n2->value.length)
+ return GSS_S_COMPLETE;
+ if (memcmp(n1->value.value, n2->value.value, n2->value.length) != 0)
+ return GSS_S_COMPLETE;
+
+ *name_equal = 1;
+
+ return GSS_S_COMPLETE;
}
OM_uint32 _gss_spnego_display_name
@@ -292,19 +306,51 @@ OM_uint32 _gss_spnego_display_name
gss_OID * output_name_type
)
{
- return gss_display_name(minor_status, input_name,
+ spnego_name name = (spnego_name)input_name;
+
+ *minor_status = 0;
+
+ if (name->mech == GSS_C_NO_NAME)
+ return GSS_S_FAILURE;
+
+ return gss_display_name(minor_status, name->mech,
output_name_buffer, output_name_type);
}
OM_uint32 _gss_spnego_import_name
(OM_uint32 * minor_status,
- const gss_buffer_t input_name_buffer,
- const gss_OID input_name_type,
+ const gss_buffer_t name_buffer,
+ const gss_OID name_type,
gss_name_t * output_name
)
{
- return gss_import_name(minor_status, input_name_buffer,
- input_name_type, output_name);
+ spnego_name name;
+ OM_uint32 maj_stat;
+
+ *minor_status = 0;
+
+ name = calloc(1, sizeof(*name));
+ if (name == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ maj_stat = _gss_copy_oid(minor_status, name_type, &name->type);
+ if (maj_stat) {
+ free(name);
+ return GSS_S_FAILURE;
+ }
+
+ maj_stat = _gss_copy_buffer(minor_status, name_buffer, &name->value);
+ if (maj_stat) {
+ gss_name_t rname = (gss_name_t)name;
+ _gss_spnego_release_name(minor_status, &rname);
+ return GSS_S_FAILURE;
+ }
+ name->mech = GSS_C_NO_NAME;
+ *output_name = (gss_name_t)name;
+
+ return GSS_S_COMPLETE;
}
OM_uint32 _gss_spnego_export_name
@@ -313,8 +359,17 @@ OM_uint32 _gss_spnego_export_name
gss_buffer_t exported_name
)
{
- return gss_export_name(minor_status, input_name,
- exported_name);
+ spnego_name name;
+ *minor_status = 0;
+
+ if (input_name == GSS_C_NO_NAME)
+ return GSS_S_BAD_NAME;
+
+ name = (spnego_name)input_name;
+ if (name->mech == GSS_C_NO_NAME)
+ return GSS_S_BAD_NAME;
+
+ return gss_export_name(minor_status, name->mech, exported_name);
}
OM_uint32 _gss_spnego_release_name
@@ -322,7 +377,20 @@ OM_uint32 _gss_spnego_release_name
gss_name_t * input_name
)
{
- return gss_release_name(minor_status, input_name);
+ *minor_status = 0;
+
+ if (*input_name != GSS_C_NO_NAME) {
+ OM_uint32 junk;
+ spnego_name name = (spnego_name)*input_name;
+ _gss_free_oid(&junk, &name->type);
+ gss_release_buffer(&junk, &name->value);
+ if (name->mech != GSS_C_NO_NAME)
+ gss_release_name(&junk, &name->mech);
+ free(name);
+
+ *input_name = GSS_C_NO_NAME;
+ }
+ return GSS_S_COMPLETE;
}
OM_uint32 _gss_spnego_inquire_context (
diff --git a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c
index 5a652fdb2e..a221281a70 100644
--- a/source4/heimdal/lib/gssapi/spnego/init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/spnego/init_sec_context.c
@@ -33,7 +33,39 @@
#include "spnego/spnego_locl.h"
-RCSID("$Id: init_sec_context.c,v 1.6 2006/10/14 10:09:15 lha Exp $");
+RCSID("$Id: init_sec_context.c,v 1.11 2006/12/18 15:42:03 lha Exp $");
+
+/*
+ * Is target_name an sane target for `mech´.
+ */
+
+static OM_uint32
+initiator_approved(gss_name_t target_name, gss_OID mech)
+{
+ OM_uint32 min_stat, maj_stat;
+ gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+ gss_buffer_desc out;
+
+ maj_stat = gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &ctx,
+ target_name,
+ mech,
+ 0,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER,
+ NULL,
+ &out,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ return GSS_S_BAD_MECH;
+ gss_release_buffer(&min_stat, &out);
+ gss_delete_sec_context(&min_stat, &ctx, NULL);
+
+ return GSS_S_COMPLETE;
+}
/*
* Send a reply. Note that we only need to send a reply if we
@@ -50,11 +82,10 @@ spnego_reply_internal(OM_uint32 *minor_status,
gss_buffer_t mech_token,
gss_buffer_t output_token)
{
- NegTokenResp resp;
+ NegotiationToken nt;
gss_buffer_desc mic_buf;
OM_uint32 ret;
- gss_buffer_desc data;
- u_char *buf;
+ size_t size;
if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) {
output_token->length = 0;
@@ -63,85 +94,83 @@ spnego_reply_internal(OM_uint32 *minor_status,
return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE;
}
- memset(&resp, 0, sizeof(resp));
+ memset(&nt, 0, sizeof(nt));
- ALLOC(resp.negResult, 1);
- if (resp.negResult == NULL) {
+ nt.element = choice_NegotiationToken_negTokenResp;
+
+ ALLOC(nt.u.negTokenResp.negResult, 1);
+ if (nt.u.negTokenResp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- resp.supportedMech = NULL;
+ nt.u.negTokenResp.supportedMech = NULL;
output_token->length = 0;
output_token->value = NULL;
if (mech_token->length == 0) {
- resp.responseToken = NULL;
- *(resp.negResult) = accept_completed;
+ nt.u.negTokenResp.responseToken = NULL;
+ *(nt.u.negTokenResp.negResult) = accept_completed;
} else {
- ALLOC(resp.responseToken, 1);
- if (resp.responseToken == NULL) {
- free_NegTokenResp(&resp);
+ ALLOC(nt.u.negTokenResp.responseToken, 1);
+ if (nt.u.negTokenResp.responseToken == NULL) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
- resp.responseToken->length = mech_token->length;
- resp.responseToken->data = mech_token->value;
+ nt.u.negTokenResp.responseToken->length = mech_token->length;
+ nt.u.negTokenResp.responseToken->data = mech_token->value;
mech_token->length = 0;
mech_token->value = NULL;
- *(resp.negResult) = accept_incomplete;
+ *(nt.u.negTokenResp.negResult) = accept_incomplete;
}
if (mech_buf != GSS_C_NO_BUFFER) {
- ALLOC(resp.mechListMIC, 1);
- if (resp.mechListMIC == NULL) {
- free_NegTokenResp(&resp);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
ret = gss_get_mic(minor_status,
context_handle->negotiated_ctx_id,
0,
mech_buf,
&mic_buf);
- if (ret) {
- free_NegTokenResp(&resp);
+ if (ret == GSS_S_COMPLETE) {
+ ALLOC(nt.u.negTokenResp.mechListMIC, 1);
+ if (nt.u.negTokenResp.mechListMIC == NULL) {
+ gss_release_buffer(minor_status, &mic_buf);
+ free_NegotiationToken(&nt);
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ nt.u.negTokenResp.mechListMIC->length = mic_buf.length;
+ nt.u.negTokenResp.mechListMIC->data = mic_buf.value;
+ } else if (ret == GSS_S_UNAVAILABLE) {
+ nt.u.negTokenResp.mechListMIC = NULL;
+ } if (ret) {
+ free_NegotiationToken(&nt);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
-
- resp.mechListMIC->length = mic_buf.length;
- resp.mechListMIC->data = mic_buf.value;
} else {
- resp.mechListMIC = NULL;
+ nt.u.negTokenResp.mechListMIC = NULL;
}
- ret = _gss_spnego_encode_response (minor_status, &resp,
- &data, &buf);
+ ASN1_MALLOC_ENCODE(NegotiationToken,
+ output_token->value, output_token->length,
+ &nt, &size, ret);
if (ret) {
- free_NegTokenResp(&resp);
- return ret;
- }
-
- 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.value, output_token->length);
+ free_NegotiationToken(&nt);
+ *minor_status = ret;
+ return GSS_S_FAILURE;
}
- free(buf);
- if (*(resp.negResult) == accept_completed)
+ if (*(nt.u.negTokenResp.negResult) == accept_completed)
ret = GSS_S_COMPLETE;
else
ret = GSS_S_CONTINUE_NEEDED;
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&nt);
return ret;
}
@@ -172,12 +201,16 @@ spnego_initial
size_t ni_len;
gss_ctx_id_t context;
gssspnego_ctx ctx;
+ spnego_name name = (spnego_name)target_name;
+
+ *minor_status = 0;
memset (&ni, 0, sizeof(ni));
*context_handle = GSS_C_NO_CONTEXT;
- *minor_status = 0;
+ if (target_name == GSS_C_NO_NAME)
+ return GSS_S_BAD_NAME;
sub = _gss_spnego_alloc_sec_context(&minor, &context);
if (GSS_ERROR(sub)) {
@@ -190,7 +223,17 @@ spnego_initial
ctx->local = 1;
- sub = _gss_spnego_indicate_mechtypelist(&minor, 0,
+ sub = gss_import_name(&minor, &name->value, &name->type, &ctx->target_name);
+ if (GSS_ERROR(sub)) {
+ *minor_status = minor;
+ _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
+ return sub;
+ }
+
+ sub = _gss_spnego_indicate_mechtypelist(&minor,
+ ctx->target_name,
+ initiator_approved,
+ 0,
cred,
&ni.mechTypes,
&ctx->preferred_mech_type);
@@ -212,8 +255,8 @@ spnego_initial
(cred != NULL) ? cred->negotiated_cred_id :
GSS_C_NO_CREDENTIAL,
&ctx->negotiated_ctx_id,
- target_name,
- GSS_C_NO_OID,
+ ctx->target_name,
+ ctx->preferred_mech_type,
req_flags,
time_req,
input_chan_bindings,
@@ -228,6 +271,8 @@ spnego_initial
_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
return sub;
}
+ if (sub == GSS_S_COMPLETE)
+ ctx->maybe_open = 1;
if (mech_token.length != 0) {
ALLOC(ni.mechToken, 1);
@@ -345,8 +390,6 @@ spnego_reply
{
OM_uint32 ret, minor;
NegTokenResp resp;
- u_char oidbuf[17];
- size_t oidlen;
size_t len, taglen;
gss_OID_desc mech;
int require_mic;
@@ -385,34 +428,73 @@ spnego_reply
if (resp.negResult == NULL
|| *(resp.negResult) == reject
- || resp.supportedMech == NULL) {
+ /* || resp.supportedMech == NULL */
+ )
+ {
free_NegTokenResp(&resp);
return GSS_S_BAD_MECH;
}
- ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
- sizeof(oidbuf),
- resp.supportedMech,
- &oidlen);
- if (ret || (oidlen == GSS_SPNEGO_MECHANISM->length &&
- memcmp(oidbuf + sizeof(oidbuf) - oidlen,
- GSS_SPNEGO_MECHANISM->elements,
- oidlen) == 0)) {
+ /*
+ * Pick up the mechanism that the acceptor selected, only allow it
+ * to be sent in packet.
+ */
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+
+ if (resp.supportedMech) {
+
+ if (ctx->oidlen) {
+ free_NegTokenResp(&resp);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ return GSS_S_BAD_MECH;
+ }
+ ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1,
+ sizeof(ctx->oidbuf),
+ resp.supportedMech,
+ &ctx->oidlen);
/* Avoid recursively embedded SPNEGO */
+ if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length &&
+ memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
+ GSS_SPNEGO_MECHANISM->elements,
+ ctx->oidlen) == 0))
+ {
+ free_NegTokenResp(&resp);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ return GSS_S_BAD_MECH;
+ }
+
+ /* check if the acceptor took our optimistic token */
+ if (ctx->oidlen != ctx->preferred_mech_type->length ||
+ memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
+ ctx->preferred_mech_type->elements,
+ ctx->oidlen) != 0)
+ {
+ gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id,
+ GSS_C_NO_BUFFER);
+ ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
+ }
+ } else if (ctx->oidlen == 0) {
free_NegTokenResp(&resp);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_BAD_MECH;
}
- HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
-
- if (resp.responseToken != NULL) {
+ if (resp.responseToken != NULL ||
+ ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
gss_buffer_desc mech_input_token;
- mech_input_token.length = resp.responseToken->length;
- mech_input_token.value = resp.responseToken->data;
+ if (resp.responseToken) {
+ mech_input_token.length = resp.responseToken->length;
+ mech_input_token.value = resp.responseToken->data;
+ } else {
+ mech_input_token.length = 0;
+ mech_input_token.value = NULL;
+ }
- mech.length = oidlen;
- mech.elements = oidbuf + sizeof(oidbuf) - oidlen;
+
+ mech.length = ctx->oidlen;
+ mech.elements = ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen;
/* Fall through as if the negotiated mechanism
was requested explicitly */
@@ -420,7 +502,7 @@ spnego_reply
(cred != NULL) ? cred->negotiated_cred_id :
GSS_C_NO_CREDENTIAL,
&ctx->negotiated_ctx_id,
- target_name,
+ ctx->target_name,
&mech,
req_flags,
time_req,
@@ -439,6 +521,9 @@ spnego_reply
if (ret == GSS_S_COMPLETE) {
ctx->open = 1;
}
+ } else if (*(resp.negResult) == accept_completed) {
+ if (ctx->maybe_open)
+ ctx->open = 1;
}
if (*(resp.negResult) == request_mic) {
diff --git a/source4/heimdal/lib/gssapi/spnego/spnego-private.h b/source4/heimdal/lib/gssapi/spnego/spnego-private.h
index df50f65580..d80db0018a 100644
--- a/source4/heimdal/lib/gssapi/spnego/spnego-private.h
+++ b/source4/heimdal/lib/gssapi/spnego/spnego-private.h
@@ -46,12 +46,6 @@ _gss_spnego_add_cred (
OM_uint32 * /*initiator_time_rec*/,
OM_uint32 * acceptor_time_rec );
-int
-_gss_spnego_add_mech_type (
- gss_OID /*mech_type*/,
- int /*includeMSCompatOID*/,
- MechTypeList */*mechtypelist*/);
-
OM_uint32
_gss_spnego_alloc_cred (
OM_uint32 */*minor_status*/,
@@ -112,13 +106,6 @@ _gss_spnego_duplicate_name (
gss_name_t * dest_name );
OM_uint32
-_gss_spnego_encode_response (
- OM_uint32 */*minor_status*/,
- const NegTokenResp */*resp*/,
- gss_buffer_t /*data*/,
- u_char **/*ret_buf*/);
-
-OM_uint32
_gss_spnego_export_name (
OM_uint32 * /*minor_status*/,
const gss_name_t /*input_name*/,
@@ -141,8 +128,8 @@ _gss_spnego_get_mic (
OM_uint32
_gss_spnego_import_name (
OM_uint32 * /*minor_status*/,
- const gss_buffer_t /*input_name_buffer*/,
- const gss_OID /*input_name_type*/,
+ const gss_buffer_t /*name_buffer*/,
+ const gss_OID /*name_type*/,
gss_name_t * output_name );
OM_uint32
@@ -154,6 +141,8 @@ _gss_spnego_import_sec_context (
OM_uint32
_gss_spnego_indicate_mechtypelist (
OM_uint32 */*minor_status*/,
+ gss_name_t /*target_name*/,
+ OM_uint32 (*/*func*/)(gss_name_t, gss_OID),
int /*includeMSCompatOID*/,
const gssspnego_cred /*cred_handle*/,
MechTypeList */*mechtypelist*/,
@@ -271,12 +260,6 @@ _gss_spnego_seal (
gss_buffer_t output_message_buffer );
OM_uint32
-_gss_spnego_select_mech (
- OM_uint32 */*minor_status*/,
- MechType */*mechType*/,
- gss_OID */*mech_p*/);
-
-OM_uint32
_gss_spnego_set_sec_context_option (
OM_uint32 * /*minor_status*/,
gss_ctx_id_t * /*context_handle*/,
diff --git a/source4/heimdal/lib/gssapi/spnego/spnego.asn1 b/source4/heimdal/lib/gssapi/spnego/spnego.asn1
index 187ce0a0a6..76fafa356c 100644
--- a/source4/heimdal/lib/gssapi/spnego/spnego.asn1
+++ b/source4/heimdal/lib/gssapi/spnego/spnego.asn1
@@ -1,4 +1,4 @@
--- $Id: spnego.asn1,v 1.1.1.1 2006/06/28 08:34:45 lha Exp $
+-- $Id: spnego.asn1,v 1.3 2006/12/18 18:28:49 lha Exp $
SPNEGO DEFINITIONS ::=
BEGIN
@@ -22,14 +22,21 @@ NegHints ::= SEQUENCE {
hintAddress [1] OCTET STRING OPTIONAL
}
+NegTokenInitWin ::= SEQUENCE {
+ mechTypes [0] MechTypeList,
+ reqFlags [1] ContextFlags OPTIONAL,
+ mechToken [2] OCTET STRING OPTIONAL,
+ negHints [3] NegHints OPTIONAL
+ }
+
NegTokenInit ::= SEQUENCE {
mechTypes [0] MechTypeList,
reqFlags [1] ContextFlags OPTIONAL,
mechToken [2] OCTET STRING OPTIONAL,
- negHints [3] NegHints OPTIONAL,
- mechListMIC [4] OCTET STRING OPTIONAL
+ mechListMIC [3] OCTET STRING OPTIONAL
}
+
-- NB: negResult is not OPTIONAL in the new SPNEGO spec but
-- Windows clients do not always send it
NegTokenResp ::= SEQUENCE {
@@ -48,4 +55,8 @@ NegotiationToken ::= CHOICE {
negTokenResp[1] NegTokenResp
}
+NegotiationTokenWin ::= CHOICE {
+ negTokenInit[0] NegTokenInitWin
+}
+
END
diff --git a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h
index 255e07d056..45dff04313 100644
--- a/source4/heimdal/lib/gssapi/spnego/spnego_locl.h
+++ b/source4/heimdal/lib/gssapi/spnego/spnego_locl.h
@@ -30,7 +30,7 @@
* SUCH DAMAGE.
*/
-/* $Id: spnego_locl.h,v 1.12 2006/11/07 19:53:40 lha Exp $ */
+/* $Id: spnego_locl.h,v 1.15 2006/12/18 15:42:03 lha Exp $ */
#ifndef SPNEGO_LOCL_H
#define SPNEGO_LOCL_H
@@ -67,6 +67,7 @@
#include <gssapi_mech.h>
#include "spnego_asn1.h"
+#include "mech/utils.h"
#include <der.h>
#include <roken.h>
@@ -86,13 +87,29 @@ typedef struct {
OM_uint32 mech_time_rec;
gss_name_t mech_src_name;
gss_cred_id_t delegated_cred_id;
- int open : 1;
- int local : 1;
- int require_mic : 1;
- int verified_mic : 1;
+ unsigned int open : 1;
+ unsigned int local : 1;
+ unsigned int require_mic : 1;
+ unsigned int verified_mic : 1;
+ unsigned int maybe_open : 1;
HEIMDAL_MUTEX ctx_id_mutex;
+
+ gss_name_t target_name;
+
+ u_char oidbuf[17];
+ size_t oidlen;
+
} *gssspnego_ctx;
+typedef struct {
+ gss_OID_desc type;
+ gss_buffer_desc value;
+ gss_name_t mech;
+} *spnego_name;
+
+extern gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc;
+extern gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc;
+
#include <spnego/spnego-private.h>
#endif /* SPNEGO_LOCL_H */