Initial revision

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@17692 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Love Hörnquist Åstrand
2006-06-28 08:34:45 +00:00
parent 057d255d5c
commit 2baa7e7d61
98 changed files with 14146 additions and 0 deletions

View File

@@ -0,0 +1 @@
Makefile.in

View File

@@ -0,0 +1,8 @@
2005-01-11 Luke Howard <lukeh@padl.com>
* spnego.asn1: s/request_mic/request-mic
2005-01-10 Luke Howard <lukeh@padl.com>
* initial revision

View File

@@ -0,0 +1,47 @@
# $Id$
include $(top_srcdir)/Makefile.am.common
AM_CPPFLAGS += -I$(srcdir)/../mechglue \
-I${srcdir}/../krb5 \
-I${srcdir}/../asn1/include \
$(INCLUDE_des) \
$(INCLUDE_krb4)
gssdir = $(libdir)/gss
spnego_files = \
asn1_ContextFlags.x \
asn1_MechType.x \
asn1_MechTypeList.x \
asn1_NegotiationToken.x \
asn1_NegHints.x \
asn1_NegTokenInit.x \
asn1_NegTokenResp.x
BUILT_SOURCES = $(spnego_files:.x=.c)
gss_LTLIBRARIES = libmech_spnego.la
libmech_spnego_la_LDFLAGS = -version-info 1:0:0
libmech_spnego_la_LIBADD = ../mechglue/libgssapi.la ../asn1/libasn1.la ../roken/libroken.la
include_HEADERS = gssapi_spnego.h
libmech_spnego_la_SOURCES = \
$(BUILT_SOURCES) \
accept_sec_context.c \
compat.c \
context_stubs.c \
cred_stubs.c \
external.c \
init_sec_context.c
CLEANFILES = $(BUILT_SOURCES) $(spnego_files) spnego_asn1.h asn1_files
$(spnego_files) spnego_asn1.h: asn1_files
asn1_files: ../asn1/asn1_compile$(EXEEXT) $(srcdir)/spnego.asn1
../asn1/asn1_compile$(EXEEXT) $(srcdir)/spnego.asn1 spnego_asn1
$(libmech_spnego_la_OBJECTS): spnego_asn1.h

View File

@@ -0,0 +1,873 @@
/*
* Copyright (c) 1997 - 2004 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* Portions Copyright (c) 2004 PADL Software Pty Ltd.
*
* 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 "spnego_locl.h"
RCSID("$Id$");
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,
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;
}
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;
ALLOC(resp.negResult, 1);
if (resp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
*(resp.negResult) = reject;
resp.supportedMech = NULL;
resp.responseToken = NULL;
resp.mechListMIC = NULL;
ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf);
free_NegTokenResp(&resp);
if (ret != GSS_S_COMPLETE)
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(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 gss_cred_id_t cred_handle,
MechTypeList *mechtypelist,
gss_OID *preferred_mech)
{
OM_uint32 ret;
gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
int i, count;
if (cred_handle != GSS_C_NO_CREDENTIAL) {
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);
}
if (ret != GSS_S_COMPLETE) {
return ret;
}
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;
}
static OM_uint32
send_supported_mechs (OM_uint32 *minor_status,
gss_buffer_t output_token)
{
NegTokenInit ni;
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;
gss_buffer_desc data;
memset(&ni, 0, sizeof(ni));
ni.reqFlags = NULL;
ni.mechToken = NULL;
ni.negHints = NULL;
ni.mechListMIC = NULL;
ret = _gss_spnego_indicate_mechtypelist(minor_status, 1,
GSS_C_NO_CREDENTIAL,
&ni.mechTypes, NULL);
if (ret != GSS_S_COMPLETE) {
return ret;
}
memset(&target_princ, 0, sizeof(target_princ));
if (gethostname(hostname, sizeof(hostname) - 1) != 0) {
*minor_status = errno;
free_NegTokenInit(&ni);
return GSS_S_FAILURE;
}
/* Send the constructed SAM name for this host */
for (p = hostname; *p != '\0' && *p != '.'; p++) {
*p = toupper(*p);
}
*p++ = '$';
*p = '\0';
name_buf.length = strlen(hostname);
name_buf.value = hostname;
ret = gss_import_name(minor_status, &name_buf,
GSS_C_NO_OID,
&target_princ);
if (ret != GSS_S_COMPLETE) {
return ret;
}
name_buf.length = 0;
name_buf.value = NULL;
/* Canonicalize the name using the preferred mechanism */
ret = gss_canonicalize_name(minor_status,
target_princ,
GSS_C_NO_OID,
&canon_princ);
if (ret != GSS_S_COMPLETE) {
gss_release_name(&minor, &target_princ);
return ret;
}
ret = gss_display_name(minor_status, canon_princ,
&name_buf, &name_type);
if (ret != GSS_S_COMPLETE) {
gss_release_name(&minor, &canon_princ);
gss_release_name(&minor, &target_princ);
return ret;
}
gss_release_name(&minor, &canon_princ);
gss_release_name(&minor, &target_princ);
ALLOC(ni.negHints, 1);
if (ni.negHints == NULL) {
*minor_status = ENOMEM;
gss_release_buffer(&minor, &name_buf);
free_NegTokenInit(&ni);
return GSS_S_FAILURE;
}
ALLOC(ni.negHints->hintName, 1);
if (ni.negHints->hintName == NULL) {
*minor_status = ENOMEM;
gss_release_buffer(&minor, &name_buf);
free_NegTokenInit(&ni);
return GSS_S_FAILURE;
}
*(ni.negHints->hintName) = name_buf.value;
name_buf.value = NULL;
ni.negHints->hintAddress = NULL;
buf_size = 1024;
buf = malloc(buf_size);
if (buf == NULL) {
free_NegTokenInit(&ni);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
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,
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);
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);
if (ret != GSS_S_COMPLETE)
return ret;
*minor_status = 0;
return GSS_S_CONTINUE_NEEDED;
}
static OM_uint32
send_accept (OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
gss_buffer_t mech_token,
int initial_response,
gss_buffer_t mech_buf,
gss_buffer_t output_token)
{
NegTokenResp resp;
gss_buffer_desc data;
u_char *buf;
OM_uint32 ret;
gss_buffer_desc mech_mic_buf;
memset(&resp, 0, sizeof(resp));
ALLOC(resp.negResult, 1);
if (resp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
if (context_handle->open) {
if (mech_token != GSS_C_NO_BUFFER
&& mech_token->length != 0
&& mech_buf != GSS_C_NO_BUFFER)
*(resp.negResult) = accept_incomplete;
else
*(resp.negResult) = accept_completed;
} else {
if (initial_response && context_handle->require_mic)
*(resp.negResult) = request_mic;
else
*(resp.negResult) = accept_incomplete;
}
if (initial_response) {
ALLOC(resp.supportedMech, 1);
if (resp.supportedMech == NULL) {
free_NegTokenResp(&resp);
*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,
NULL);
if (ret) {
free_NegTokenResp(&resp);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
} else {
resp.supportedMech = NULL;
}
if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
ALLOC(resp.responseToken, 1);
if (resp.responseToken == NULL) {
free_NegTokenResp(&resp);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
resp.responseToken->length = mech_token->length;
resp.responseToken->data = mech_token->value;
mech_token->length = 0;
mech_token->value = NULL;
} else {
resp.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);
return ret;
}
resp.mechListMIC->length = mech_mic_buf.length;
resp.mechListMIC->data = mech_mic_buf.value;
} else
resp.mechListMIC = NULL;
ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf);
if (ret != GSS_S_COMPLETE) {
free_NegTokenResp(&resp);
return ret;
}
/*
* The response should not be encapsulated, because
* 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);
return ret;
}
static OM_uint32
verify_mechlist_mic
(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
gss_buffer_t mech_buf,
heim_octet_string *mechListMIC
)
{
OM_uint32 ret;
gss_buffer_desc mic_buf;
if (context_handle->verified_mic) {
/* This doesn't make sense, we've already verified it? */
*minor_status = 0;
return GSS_S_DUPLICATE_TOKEN;
}
if (mechListMIC == NULL) {
*minor_status = 0;
return GSS_S_DEFECTIVE_TOKEN;
}
mic_buf.length = mechListMIC->length;
mic_buf.value = mechListMIC->data;
ret = gss_verify_mic(minor_status,
context_handle->negotiated_ctx_id,
mech_buf,
&mic_buf,
NULL);
if (ret != GSS_S_COMPLETE)
ret = GSS_S_DEFECTIVE_TOKEN;
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
)
{
OM_uint32 ret, ret2, minor;
NegTokenInit ni;
NegTokenResp na;
size_t ni_len, na_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_ctx_id_t ctx;
gss_buffer_desc mech_buf;
gss_OID preferred_mech_type = GSS_C_NO_OID;
*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_buf.value = NULL;
if (*context_handle == GSS_C_NO_CONTEXT) {
ret = _gss_spnego_alloc_sec_context(minor_status,
context_handle);
if (ret != GSS_S_COMPLETE)
return ret;
if (input_token_buffer->length == 0) {
return send_supported_mechs (minor_status,
output_token);
}
}
ctx = *context_handle;
/*
* The GSS-API encapsulation is only present on the initial
* context token (negTokenInit).
*/
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;
}
ret = der_match_tag_and_length(data.value, data.length,
CONTEXT, CONS,
initialToken ? 0 : 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;
}
if (initialToken) {
ret = decode_NegTokenInit((const char *)data.value + taglen, len,
&ni, &ni_len);
} else {
ret = decode_NegTokenResp((const 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 (negResult == reject || negResult == request_mic) {
/* request_mic should only be sent by acceptor */
free_NegTokenResp(&na);
return GSS_S_DEFECTIVE_TOKEN;
}
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);
if (ret == 0)
break;
}
if (preferred_mech_type == GSS_C_NO_OID) {
free_NegTokenInit(&ni);
return GSS_S_BAD_MECH;
}
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
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;
}
{
gss_buffer_desc ibuf, obuf;
OM_uint32 minor;
int require_mic, verify_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;
}
} else {
if (na.responseToken != NULL) {
ibuf.length = na.responseToken->length;
ibuf.value = na.responseToken->data;
mech_input_token = &ibuf;
}
}
if (mech_input_token != GSS_C_NO_BUFFER) {
gss_cred_id_t mech_cred;
gss_cred_id_t mech_delegated_cred;
gss_cred_id_t *mech_delegated_cred_p;
if (acceptor_cred_handle != GSS_C_NO_CREDENTIAL)
mech_cred = acceptor_cred_handle->negotiated_cred_id;
else
mech_cred = GSS_C_NO_CREDENTIAL;
if (delegated_cred_handle != NULL) {
mech_delegated_cred = GSS_C_NO_CREDENTIAL;
mech_delegated_cred_p = &mech_delegated_cred;
} else {
mech_delegated_cred_p = NULL;
}
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,
&obuf,
&ctx->mech_flags,
&ctx->mech_time_rec,
mech_delegated_cred_p);
if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
if (mech_delegated_cred_p != NULL &&
mech_delegated_cred != GSS_C_NO_CREDENTIAL) {
ret2 = _gss_spnego_alloc_cred(minor_status,
mech_delegated_cred,
&ctx->delegated_cred_id);
if (ret2 != GSS_S_COMPLETE)
ret = ret2;
}
mech_output_token = &obuf;
}
if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
if (initialToken)
free_NegTokenInit(&ni);
else
free_NegTokenResp(&na);
send_reject (minor_status, output_token);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
if (ret == GSS_S_COMPLETE)
ctx->open = 1;
} else
ret = GSS_S_COMPLETE;
ret2 = _gss_spnego_require_mechlist_mic(minor_status,
ctx,
&require_mic);
if (ret2)
goto out;
ctx->require_mic = require_mic;
mic = initialToken ? ni.mechListMIC : na.mechListMIC;
if (mic != NULL)
require_mic = TRUE;
if (ctx->open && require_mic) {
if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
verify_mic = TRUE;
get_mic = FALSE;
} else if (mech_output_token != GSS_C_NO_BUFFER &&
mech_output_token->length == 0) { /* Odd */
get_mic = verify_mic = TRUE;
} else { /* Even/One */
verify_mic = FALSE;
get_mic = TRUE;
}
if (verify_mic || get_mic) {
krb5_error_code kret;
size_t buf_len;
ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
&ctx->initiator_mech_types, &buf_len, kret);
if (kret) {
ret2 = GSS_S_FAILURE;
*minor_status = kret;
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 = FALSE;
if (ctx->mech_flags & GSS_C_DCE_STYLE)
require_response = (negResult != accept_completed);
else
require_response = 0;
/*
* Check whether we need to send a result: there should be only
* one accept_completed response sent in the entire negotiation
*/
if ((mech_output_token != GSS_C_NO_BUFFER &&
mech_output_token->length != 0)
|| require_response
|| get_mic) {
ret2 = send_accept (minor_status,
ctx,
mech_output_token,
initialToken,
get_mic ? &mech_buf : NULL,
output_token);
if (ret2)
goto out;
}
out:
if (ret2 != GSS_S_COMPLETE)
ret = ret2;
if (mech_output_token != NULL)
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);
}
if (ret == GSS_S_COMPLETE) {
if (src_name != NULL) {
ret2 = gss_duplicate_name(minor_status,
ctx->mech_src_name,
src_name);
if (ret2 != GSS_S_COMPLETE)
ret = ret2;
}
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_delete_sec_context(&minor, context_handle,
GSS_C_NO_BUFFER);
return ret;
}

289
lib/gssapi/spnego/compat.c Normal file
View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2004, 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 "spnego_locl.h"
RCSID("$Id$");
/*
* Apparently Microsoft got the OID wrong, and used
* 1.2.840.48018.1.2.2 instead. We need both this and
* the correct Kerberos OID here in order to deal with
* this. Because this is manifest in SPNEGO only I'd
* prefer to deal with this here rather than inside the
* Kerberos mechanism.
*/
static gss_OID_desc gss_mskrb_mechanism_oid_desc =
{9, (void *)"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"};
static gss_OID_desc gss_krb5_mechanism_oid_desc =
{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
/*
* Allocate a SPNEGO context handle
*/
OM_uint32 _gss_spnego_alloc_sec_context (OM_uint32 * minor_status,
gss_ctx_id_t *context_handle)
{
gss_ctx_id_t ctx;
ctx = malloc(sizeof(gss_ctx_id_t_desc));
if (ctx == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
ctx->initiator_mech_types.len = 0;
ctx->initiator_mech_types.val = NULL;
ctx->preferred_mech_type = NULL;
ctx->negotiated_mech_type = NULL;
ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
/*
* Cache these so we can return them before returning
* GSS_S_COMPLETE, even if the mechanism has itself
* completed earlier
*/
ctx->mech_flags = 0;
ctx->mech_time_rec = 0;
ctx->mech_src_name = GSS_C_NO_NAME;
ctx->delegated_cred_id = GSS_C_NO_CREDENTIAL;
ctx->open = 0;
ctx->local = 0;
ctx->require_mic = 0;
ctx->verified_mic = 0;
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
*context_handle = ctx;
return GSS_S_COMPLETE;
}
/*
* Free a SPNEGO context handle. The caller must have acquired
* the lock before this is called.
*/
OM_uint32 _gss_spnego_delete_sec_context
(OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_buffer_t output_token
)
{
gss_ctx_id_t ctx;
OM_uint32 ret, minor;
*minor_status = 0;
if (context_handle == NULL) {
return GSS_S_NO_CONTEXT;
}
if (output_token != GSS_C_NO_BUFFER) {
output_token->length = 0;
output_token->value = NULL;
}
ctx = *context_handle;
if (ctx == NULL) {
return GSS_S_NO_CONTEXT;
}
if (ctx->initiator_mech_types.val != NULL)
free_MechTypeList(&ctx->initiator_mech_types);
_gss_spnego_release_cred(&minor, &ctx->delegated_cred_id);
gss_release_oid(&minor, &ctx->preferred_mech_type);
gss_release_oid(&minor, &ctx->negotiated_mech_type);
gss_release_name(&minor, &ctx->mech_src_name);
if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) {
ret = gss_delete_sec_context(minor_status,
&ctx->negotiated_ctx_id,
output_token);
ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
} else {
ret = GSS_S_COMPLETE;
}
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
free(ctx);
*context_handle = NULL;
return ret;
}
/*
* For compatability with the Windows SPNEGO implementation, the
* default is to ignore the mechListMIC unless CFX is used and
* a non-preferred mechanism was negotiated
*/
OM_uint32
_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
gss_ctx_id_t ctx,
int *require_mic)
{
gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET;
OM_uint32 minor;
*minor_status = 0;
*require_mic = 0;
if (ctx == GSS_C_NO_CONTEXT) {
return GSS_S_COMPLETE;
}
if (ctx->require_mic) {
/* Acceptor requested it: mandatory to honour */
*require_mic = 1;
return GSS_S_COMPLETE;
}
/*
* Check whether peer indicated implicit support for updated SPNEGO
* (eg. in the Kerberos case by using CFX)
*/
if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id,
GSS_C_PEER_HAS_UPDATED_SPNEGO,
&buffer_set) == GSS_S_COMPLETE) {
*require_mic = 1;
gss_release_buffer_set(&minor, &buffer_set);
}
/* Safe-to-omit MIC rules follow */
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)) {
*require_mic = 0;
}
}
return GSS_S_COMPLETE;
}
OM_uint32 gss_spnego_internal_release_oid(OM_uint32 *minor_status, gss_OID *OID)
{
*minor_status = 0;
if (*OID == GSS_SPNEGO_MECHANISM ||
*OID == &gss_mskrb_mechanism_oid_desc ||
*OID == &gss_krb5_mechanism_oid_desc) {
*OID = GSS_C_NO_OID;
return GSS_S_COMPLETE;
}
return GSS_S_FAILURE;
}
int _gss_spnego_add_mech_type(gss_OID mech_type,
int includeMSCompatOID,
MechTypeList *mechtypelist)
{
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],
NULL);
if (ret)
return ret;
mechtypelist->len++;
}
ret = der_get_oid(mech_type->elements,
mech_type->length,
&mechtypelist->val[mechtypelist->len],
NULL);
if (ret)
return ret;
mechtypelist->len++;
return 0;
}
OM_uint32
_gss_spnego_select_mech(OM_uint32 *minor_status,
MechType *mechType,
gss_OID *mech_p)
{
char mechbuf[64];
size_t mech_len;
gss_OID_desc oid;
OM_uint32 ret;
gss_mechanism mech;
ret = der_put_oid (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_mskrb_mechanism_oid_desc)) {
mech = __gss_get_mechanism(&gss_krb5_mechanism_oid_desc);
if (mech == NULL)
return GSS_S_BAD_MECH;
*mech_p = &gss_mskrb_mechanism_oid_desc;
} else {
mech = __gss_get_mechanism(&oid);
if (mech == NULL)
return GSS_S_BAD_MECH;
*mech_p = &mech->mech_type;
}
return GSS_S_COMPLETE;
}

View File

@@ -0,0 +1,697 @@
/*
* Copyright (c) 2004, 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 "spnego_locl.h"
RCSID("$Id$");
OM_uint32 gss_spnego_process_context_token
(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t token_buffer
)
{
OM_uint32 ret;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
ret = gss_process_context_token(minor_status,
context_handle->negotiated_ctx_id,
token_buffer);
if (ret != GSS_S_COMPLETE) {
HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
return ret;
}
context_handle->negotiated_ctx_id = GSS_C_NO_CONTEXT;
return _gss_spnego_delete_sec_context(minor_status,
(gss_ctx_id_t *)&context_handle,
GSS_C_NO_BUFFER);
}
OM_uint32 gss_spnego_delete_sec_context
(OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_buffer_t output_token
)
{
if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
return GSS_S_NO_CONTEXT;
HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
return _gss_spnego_delete_sec_context(minor_status,
context_handle,
output_token);
}
OM_uint32 gss_spnego_context_time
(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
OM_uint32 *time_rec
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_context_time(minor_status,
context_handle->negotiated_ctx_id,
time_rec);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_get_mic(minor_status, context_handle->negotiated_ctx_id,
qop_req, message_buffer, message_token);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_verify_mic(minor_status,
context_handle->negotiated_ctx_id,
message_buffer,
token_buffer,
qop_state);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_wrap(minor_status,
context_handle->negotiated_ctx_id,
conf_req_flag,
qop_req,
input_message_buffer,
conf_state,
output_message_buffer);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_unwrap(minor_status,
context_handle->negotiated_ctx_id,
input_message_buffer,
output_message_buffer,
conf_state,
qop_state);
}
#if 0
OM_uint32 gss_spnego_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
)
{
return GSS_S_FAILURE;
}
#endif
OM_uint32 gss_spnego_indicate_mechs
(OM_uint32 * minor_status,
gss_OID_set * mech_set
)
{
OM_uint32 ret;
ret = gss_create_empty_oid_set(minor_status, mech_set);
if (ret)
return ret;
ret = gss_add_oid_set_member(minor_status, GSS_SPNEGO_MECHANISM, mech_set);
if (ret) {
gss_release_oid_set(NULL, mech_set);
return ret;
}
return GSS_S_COMPLETE;
}
OM_uint32 gss_spnego_compare_name
(OM_uint32 *minor_status,
const gss_name_t name1,
const gss_name_t name2,
int * name_equal
)
{
return gss_compare_name(minor_status, name1, name2, name_equal);
}
OM_uint32 gss_spnego_display_name
(OM_uint32 * minor_status,
const gss_name_t input_name,
gss_buffer_t output_name_buffer,
gss_OID * output_name_type
)
{
return gss_display_name(minor_status, input_name,
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,
gss_name_t * output_name
)
{
return gss_import_name(minor_status, input_name_buffer,
input_name_type, output_name);
}
OM_uint32 gss_spnego_export_name
(OM_uint32 * minor_status,
const gss_name_t input_name,
gss_buffer_t exported_name
)
{
return gss_export_name(minor_status, input_name,
exported_name);
}
OM_uint32 gss_spnego_release_name
(OM_uint32 * minor_status,
gss_name_t * input_name
)
{
return gss_release_name(minor_status, input_name);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_inquire_context(minor_status,
context_handle->negotiated_ctx_id,
src_name,
targ_name,
lifetime_rec,
mech_type,
ctx_flags,
locally_initiated,
open_context);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_wrap_size_limit(minor_status,
context_handle->negotiated_ctx_id,
conf_req_flag,
qop_req,
req_output_size,
max_input_size);
}
OM_uint32 gss_spnego_export_sec_context (
OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
gss_buffer_t interprocess_token
)
{
gss_ctx_id_t ctx;
OM_uint32 ret;
*minor_status = 0;
if (context_handle == NULL) {
return GSS_S_NO_CONTEXT;
}
ctx = *context_handle;
if (ctx == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_NO_CONTEXT;
}
ret = gss_export_sec_context(minor_status,
&ctx->negotiated_ctx_id,
interprocess_token);
if (ret == GSS_S_COMPLETE) {
ret = _gss_spnego_delete_sec_context(minor_status,
&ctx,
GSS_C_NO_BUFFER);
if (ret == GSS_S_COMPLETE) {
*context_handle = GSS_C_NO_CONTEXT;
return GSS_S_COMPLETE;
}
}
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
OM_uint32 gss_spnego_import_sec_context (
OM_uint32 * minor_status,
const gss_buffer_t interprocess_token,
gss_ctx_id_t *context_handle
)
{
OM_uint32 ret, minor;
gss_ctx_id_t ctx;
ret = _gss_spnego_alloc_sec_context(minor_status, &ctx);
if (ret != GSS_S_COMPLETE) {
return ret;
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = gss_import_sec_context(minor_status,
interprocess_token,
&ctx->negotiated_ctx_id);
if (ret != GSS_S_COMPLETE) {
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
return ret;
}
ctx->open = 1;
/* don't bother filling in the rest of the fields */
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_COMPLETE;
}
OM_uint32 gss_spnego_inquire_names_for_mech (
OM_uint32 * minor_status,
const gss_OID mechanism,
gss_OID_set * name_types
)
{
return gss_create_empty_oid_set(minor_status, name_types);
}
OM_uint32 gss_spnego_canonicalize_name (
OM_uint32 * minor_status,
const gss_name_t input_name,
const gss_OID mech_type,
gss_name_t * output_name
)
{
return gss_canonicalize_name(minor_status,
input_name,
mech_type,
output_name);
}
OM_uint32 gss_spnego_duplicate_name (
OM_uint32 * minor_status,
const gss_name_t src_name,
gss_name_t * dest_name
)
{
return gss_duplicate_name(minor_status, src_name, dest_name);
}
OM_uint32 gss_spnego_sign
(OM_uint32 * minor_status,
gss_ctx_id_t context_handle,
int qop_req,
gss_buffer_t message_buffer,
gss_buffer_t message_token
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_sign(minor_status,
context_handle->negotiated_ctx_id,
qop_req,
message_buffer,
message_token);
}
OM_uint32 gss_spnego_verify
(OM_uint32 * minor_status,
gss_ctx_id_t context_handle,
gss_buffer_t message_buffer,
gss_buffer_t token_buffer,
int * qop_state
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_verify(minor_status,
context_handle->negotiated_ctx_id,
message_buffer,
token_buffer,
qop_state);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_seal(minor_status,
context_handle->negotiated_ctx_id,
conf_req_flag,
qop_req,
input_message_buffer,
conf_state,
output_message_buffer);
}
OM_uint32 gss_spnego_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
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_unseal(minor_status,
context_handle->negotiated_ctx_id,
input_message_buffer,
output_message_buffer,
conf_state,
qop_state);
}
OM_uint32 gss_spnego_unwrap_ex
(OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t token_header_buffer,
const gss_buffer_t associated_data_buffer,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int * conf_state,
gss_qop_t * qop_state)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_unwrap_ex(minor_status,
context_handle->negotiated_ctx_id,
token_header_buffer,
associated_data_buffer,
input_message_buffer,
output_message_buffer,
conf_state,
qop_state);
}
OM_uint32 gss_spnego_wrap_ex
(OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t associated_data_buffer,
const gss_buffer_t input_message_buffer,
int * conf_state,
gss_buffer_t output_token_buffer,
gss_buffer_t output_message_buffer
)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if ((context_handle->mech_flags & GSS_C_DCE_STYLE) == 0 &&
associated_data_buffer->length != input_message_buffer->length) {
*minor_status = EINVAL;
return GSS_S_BAD_QOP;
}
return gss_wrap_ex(minor_status,
context_handle->negotiated_ctx_id,
conf_req_flag,
qop_req,
associated_data_buffer,
input_message_buffer,
conf_state,
output_token_buffer,
output_message_buffer);
}
OM_uint32 gss_spnego_complete_auth_token
(OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
gss_buffer_t input_message_buffer)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_complete_auth_token(minor_status,
context_handle->negotiated_ctx_id,
input_message_buffer);
}
OM_uint32 gss_spnego_inquire_sec_context_by_oid
(OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if (context_handle->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_inquire_sec_context_by_oid(minor_status,
context_handle->negotiated_ctx_id,
desired_object,
data_set);
}
OM_uint32 gss_spnego_set_sec_context_option
(OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_OID desired_object,
const gss_buffer_t value)
{
*minor_status = 0;
if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if ((*context_handle)->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_set_sec_context_option(minor_status,
&(*context_handle)->negotiated_ctx_id,
desired_object,
value);
}

View File

@@ -0,0 +1,277 @@
/*
* Copyright (c) 2004, 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 "spnego_locl.h"
RCSID("$Id$");
OM_uint32
_gss_spnego_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle)
{
OM_uint32 ret;
*minor_status = 0;
if (*cred_handle == GSS_C_NO_CREDENTIAL) {
return GSS_S_COMPLETE;
}
ret = gss_release_cred(minor_status, &(*cred_handle)->negotiated_cred_id);
free(*cred_handle);
*cred_handle = GSS_C_NO_CREDENTIAL;
return ret;
}
OM_uint32
_gss_spnego_alloc_cred(OM_uint32 *minor_status,
gss_cred_id_t mech_cred_handle,
gss_cred_id_t *cred_handle)
{
if (*cred_handle != GSS_C_NO_CREDENTIAL) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
*cred_handle = (gss_cred_id_t)malloc(sizeof(*cred_handle));
if (*cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
(*cred_handle)->negotiated_cred_id = mech_cred_handle;
return GSS_S_COMPLETE;
}
/*
* For now, just a simple wrapper that avoids recursion. When
* we support gss_{get,set}_neg_mechs() we will need to expose
* more functionality.
*/
OM_uint32 gss_spnego_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 ret, tmp;
gss_OID_set_desc actual_desired_mechs;
int i, j;
gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;
*output_cred_handle = GSS_C_NO_CREDENTIAL;
/* Remove ourselves from this list */
actual_desired_mechs.count = desired_mechs->count;
actual_desired_mechs.elements = malloc(actual_desired_mechs.count *
sizeof(gss_OID_desc));
if (actual_desired_mechs.elements == NULL) {
*minor_status = ENOMEM;
ret = GSS_S_FAILURE;
goto out;
}
for (i = 0, j = 0; i < desired_mechs->count; i++) {
if (gss_oid_equal(&desired_mechs->elements[i],
GSS_SPNEGO_MECHANISM))
continue;
actual_desired_mechs.elements[j].length =
desired_mechs->elements[i].length;
actual_desired_mechs.elements[j].elements =
desired_mechs->elements[i].elements;
j++;
}
actual_desired_mechs.count = j;
ret = _gss_spnego_alloc_cred(minor_status, GSS_C_NO_CREDENTIAL,
&cred_handle);
if (ret != GSS_S_COMPLETE)
goto out;
ret = gss_acquire_cred(minor_status, desired_name,
time_req, &actual_desired_mechs,
cred_usage,
&cred_handle->negotiated_cred_id,
actual_mechs, time_rec);
if (ret != GSS_S_COMPLETE)
goto out;
*output_cred_handle = (gss_cred_id_t)cred_handle;
out:
if (actual_desired_mechs.elements != NULL) {
free(actual_desired_mechs.elements);
}
if (ret != GSS_S_COMPLETE) {
_gss_spnego_release_cred(&tmp, &cred_handle);
}
return ret;
}
OM_uint32 gss_spnego_release_cred
(OM_uint32 *minor_status,
gss_cred_id_t *cred_handle
)
{
return _gss_spnego_release_cred(minor_status, cred_handle);
}
OM_uint32 gss_spnego_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 ret;
if (cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = 0;
return GSS_S_NO_CRED;
}
ret = gss_inquire_cred(minor_status,
cred_handle->negotiated_cred_id,
name,
lifetime,
cred_usage,
mechanisms);
return ret;
}
OM_uint32 gss_spnego_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
)
{
gss_cred_id_t spnego_output_cred_handle = GSS_C_NO_CREDENTIAL;
OM_uint32 ret, tmp;
*output_cred_handle = GSS_C_NO_CREDENTIAL;
ret = _gss_spnego_alloc_cred(minor_status, GSS_C_NO_CREDENTIAL,
&spnego_output_cred_handle);
if (ret)
return ret;
ret = gss_add_cred(minor_status,
input_cred_handle->negotiated_cred_id,
desired_name,
desired_mech,
cred_usage,
initiator_time_req,
acceptor_time_req,
&spnego_output_cred_handle->negotiated_cred_id,
actual_mechs,
initiator_time_rec,
acceptor_time_rec);
if (ret) {
_gss_spnego_release_cred(&tmp, &spnego_output_cred_handle);
return ret;
}
*output_cred_handle = spnego_output_cred_handle;
return GSS_S_COMPLETE;
}
OM_uint32 gss_spnego_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 ret;
if (cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = 0;
return GSS_S_NO_CRED;
}
ret = gss_inquire_cred_by_mech(minor_status,
cred_handle->negotiated_cred_id,
mech_type,
name,
initiator_lifetime,
acceptor_lifetime,
cred_usage);
return ret;
}
OM_uint32 gss_spnego_inquire_cred_by_oid
(OM_uint32 * minor_status,
const gss_cred_id_t cred_handle,
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
OM_uint32 ret;
if (cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = 0;
return GSS_S_NO_CRED;
}
ret = gss_inquire_cred_by_oid(minor_status,
cred_handle->negotiated_cred_id,
desired_object,
data_set);
return ret;
}

View File

@@ -0,0 +1,8 @@
#ident $Id$
GSSAPI_2.0 {
global:
gss_spnego_initialize;
GSS_SPNEGO_MECHANISM;
local:
*;
};

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2004, 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 "spnego_locl.h"
RCSID("$Id$");
/*
* 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 struct gss_config spnego_mech = {
{6, (void *)"\x2b\x06\x01\x05\x05\x02"},
NULL,
gss_spnego_acquire_cred,
gss_spnego_release_cred,
gss_spnego_init_sec_context,
gss_spnego_accept_sec_context,
gss_spnego_process_context_token,
gss_spnego_delete_sec_context,
gss_spnego_context_time,
gss_spnego_sign,
gss_spnego_verify,
gss_spnego_seal,
gss_spnego_unseal,
NULL, /*gss_spnego_display_status,*/
gss_spnego_indicate_mechs,
gss_spnego_compare_name,
gss_spnego_display_name,
gss_spnego_import_name,
gss_spnego_release_name,
gss_spnego_inquire_cred,
gss_spnego_add_cred,
gss_spnego_export_sec_context,
gss_spnego_import_sec_context,
gss_spnego_inquire_cred_by_mech,
gss_spnego_inquire_names_for_mech,
gss_spnego_inquire_context,
gss_spnego_internal_release_oid,
gss_spnego_wrap_size_limit,
NULL, /*gss_spnego_pname_to_uid,*/
gss_spnego_duplicate_name,
NULL, /*gss_spnego_set_allowable_enctypes */
gss_spnego_verify_mic,
gss_spnego_get_mic,
gss_spnego_wrap,
gss_spnego_unwrap,
gss_spnego_canonicalize_name,
gss_spnego_export_name,
gss_spnego_wrap_ex,
gss_spnego_unwrap_ex,
gss_spnego_complete_auth_token,
NULL, /*gss_spnego_set_neg_mechs*/
NULL, /*gss_spnego_get_neg_mechs*/
gss_spnego_inquire_sec_context_by_oid,
gss_spnego_inquire_cred_by_oid,
gss_spnego_set_sec_context_option,
NULL /*gss_spnego_userok*/
};
gss_OID GSS_SPNEGO_MECHANISM = &spnego_mech.mech_type;
gss_mechanism gss_spnego_initialize(void)
{
return &spnego_mech;
}

View File

@@ -0,0 +1,58 @@
/*
* 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$ */
#ifndef GSSAPI_SPNEGO_H_
#define GSSAPI_SPNEGO_H_
#include <gssapi.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* 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;
#define gss_mech_spnego GSS_SPNEGO_MECHANISM
#ifdef __cplusplus
}
#endif
#endif /* GSSAPI_SPNEGO_H_ */

View File

@@ -0,0 +1,576 @@
/*
* Copyright (c) 1997 - 2004 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* Portions Copyright (c) 2004 PADL Software Pty Ltd.
*
* 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 "spnego_locl.h"
RCSID("$Id$");
/*
* Send a reply. Note that we only need to send a reply if we
* need to send a MIC or a mechanism token. Otherwise, we can
* return an empty buffer.
*
* The return value of this will be returned to the API, so it
* must return GSS_S_CONTINUE_NEEDED if a token was generated.
*/
static OM_uint32
spnego_reply_internal(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
const gss_buffer_t mech_buf,
gss_buffer_t mech_token,
gss_buffer_t output_token)
{
NegTokenResp resp;
gss_buffer_desc mic_buf;
OM_uint32 ret;
gss_buffer_desc data;
u_char *buf;
if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) {
output_token->length = 0;
output_token->value = NULL;
return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE;
}
memset(&resp, 0, sizeof(resp));
ALLOC(resp.negResult, 1);
if (resp.negResult == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
resp.supportedMech = NULL;
output_token->length = 0;
output_token->value = NULL;
if (mech_token->length == 0) {
resp.responseToken = NULL;
*(resp.negResult) = accept_completed;
} else {
ALLOC(resp.responseToken, 1);
if (resp.responseToken == NULL) {
free_NegTokenResp(&resp);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
resp.responseToken->length = mech_token->length;
resp.responseToken->data = mech_token->value;
mech_token->length = 0;
mech_token->value = NULL;
*(resp.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);
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
resp.mechListMIC->length = mic_buf.length;
resp.mechListMIC->data = mic_buf.value;
} else {
resp.mechListMIC = NULL;
}
ret = _gss_spnego_encode_response (minor_status, &resp,
&data, &buf);
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(buf);
if (*(resp.negResult) == accept_completed)
ret = GSS_S_COMPLETE;
else
ret = GSS_S_CONTINUE_NEEDED;
free_NegTokenResp(&resp);
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;
gss_buffer_desc data;
size_t ni_len;
gss_ctx_id_t ctx;
memset (&ni, 0, sizeof(ni));
*context_handle = GSS_C_NO_CONTEXT;
*minor_status = 0;
sub = _gss_spnego_alloc_sec_context(&minor, &ctx);
if (GSS_ERROR(sub)) {
*minor_status = minor;
return sub;
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ctx->local = 1;
sub = _gss_spnego_indicate_mechtypelist(&minor, 0,
initiator_cred_handle,
&ni.mechTypes,
&ctx->preferred_mech_type);
if (GSS_ERROR(sub)) {
*minor_status = minor;
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
return sub;
}
ni.reqFlags = NULL;
/*
* If we have a credential handle, use it to select the mechanism
* that we will use
*/
/* generate optimistic token */
sub = gss_init_sec_context(&minor,
initiator_cred_handle ?
initiator_cred_handle->negotiated_cred_id :
GSS_C_NO_CREDENTIAL,
&ctx->negotiated_ctx_id,
target_name,
GSS_C_NO_OID,
req_flags,
time_req,
input_chan_bindings,
input_token,
&ctx->negotiated_mech_type,
&mech_token,
&ctx->mech_flags,
&ctx->mech_time_rec);
if (GSS_ERROR(sub)) {
free_NegTokenInit(&ni);
*minor_status = minor;
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
return sub;
}
if (mech_token.length != 0) {
ALLOC(ni.mechToken, 1);
if (ni.mechToken == NULL) {
free_NegTokenInit(&ni);
gss_release_buffer(&minor, &mech_token);
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
*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;
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
return GSS_S_FAILURE;
}
memcpy(ni.mechToken->data, mech_token.value, mech_token.length);
gss_release_buffer(&minor, &mech_token);
} else
ni.mechToken = NULL;
ni.mechListMIC = NULL;
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;
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
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,
CONTEXT,
CONS,
0,
&tmp);
if (ret == 0 && tmp + buf_len != buf_size)
abort();
}
if (ret) {
*minor_status = ret;
free(buf);
free_NegTokenInit(&ni);
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
return GSS_S_FAILURE;
}
data.value = buf;
data.length = buf_size;
ctx->initiator_mech_types.len = ni.mechTypes.len;
ctx->initiator_mech_types.val = ni.mechTypes.val;
ni.mechTypes.len = 0;
ni.mechTypes.val = NULL;
free_NegTokenInit(&ni);
sub = gss_encapsulate_token(&data,
GSS_SPNEGO_MECHANISM,
output_token);
free (buf);
if (sub) {
_gss_spnego_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
return sub;
}
if (actual_mech_type)
*actual_mech_type = ctx->negotiated_mech_type;
if (ret_flags)
*ret_flags = ctx->mech_flags;
if (time_rec)
*time_rec = ctx->mech_time_rec;
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
*context_handle = ctx;
return GSS_S_CONTINUE_NEEDED;
}
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, minor;
gss_buffer_desc indata;
NegTokenResp resp;
u_char oidbuf[17];
size_t oidlen;
size_t len, taglen;
gss_OID_desc mech;
int require_mic;
size_t buf_len;
gss_buffer_desc mic_buf, mech_buf;
gss_buffer_desc mech_output_token;
gss_ctx_id_t ctx;
*minor_status = 0;
ctx = *context_handle;
output_token->length = 0;
output_token->value = NULL;
mech_output_token.length = 0;
mech_output_token.value = NULL;
mech_buf.value = NULL;
mech_buf.length = 0;
ret = der_match_tag_and_length(input_token->value, input_token->length,
CONTEXT, CONS, 1, &len, &taglen);
if (ret)
return ret;
if (len > indata.length - taglen)
return ASN1_OVERRUN;
ret = decode_NegTokenResp((const char *)input_token->value + taglen,
len, &resp, NULL);
if (ret) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
if (resp.negResult == NULL
|| *(resp.negResult) == reject
|| 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)) {
/* Avoid recursively embedded SPNEGO */
free_NegTokenResp(&resp);
return GSS_S_BAD_MECH;
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
if (resp.responseToken != NULL) {
gss_buffer_desc mech_input_token;
mech_input_token.length = resp.responseToken->length;
mech_input_token.value = resp.responseToken->data;
mech.length = oidlen;
mech.elements = oidbuf + sizeof(oidbuf) - oidlen;
/* Fall through as if the negotiated mechanism was requested explicitly */
ret = gss_init_sec_context(&minor,
initiator_cred_handle ?
initiator_cred_handle->negotiated_cred_id :
GSS_C_NO_CREDENTIAL,
&ctx->negotiated_ctx_id,
target_name,
&mech,
req_flags,
time_req,
input_chan_bindings,
&mech_input_token,
&ctx->negotiated_mech_type,
&mech_output_token,
&ctx->mech_flags,
&ctx->mech_time_rec);
if (GSS_ERROR(ret)) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free_NegTokenResp(&resp);
*minor_status = minor;
return ret;
}
if (ret == GSS_S_COMPLETE) {
ctx->open = 1;
}
}
if (*(resp.negResult) == request_mic) {
ctx->require_mic = 1;
}
if (ctx->open) {
/*
* Verify the mechListMIC if one was provided or CFX was
* used and a non-preferred mechanism was selected
*/
if (resp.mechListMIC != NULL) {
require_mic = TRUE;
} else {
ret = _gss_spnego_require_mechlist_mic(minor_status, ctx,
&require_mic);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free_NegTokenResp(&resp);
gss_release_buffer(&minor, &mech_output_token);
return ret;
}
}
} else {
require_mic = FALSE;
}
if (require_mic) {
ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
&ctx->initiator_mech_types, &buf_len, ret);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free_NegTokenResp(&resp);
gss_release_buffer(&minor, &mech_output_token);
*minor_status = ret;
return GSS_S_FAILURE;
}
if (mech_buf.length != buf_len)
abort();
if (resp.mechListMIC == NULL) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free(mech_buf.value);
free_NegTokenResp(&resp);
*minor_status = 0;
return GSS_S_DEFECTIVE_TOKEN;
}
mic_buf.length = resp.mechListMIC->length;
mic_buf.value = resp.mechListMIC->data;
if (mech_output_token.length == 0) {
ret = gss_verify_mic(minor_status,
ctx->negotiated_ctx_id,
&mech_buf,
&mic_buf,
NULL);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free(mech_buf.value);
gss_release_buffer(&minor, &mech_output_token);
free_NegTokenResp(&resp);
return GSS_S_DEFECTIVE_TOKEN;
}
ctx->verified_mic = 1;
}
}
ret = spnego_reply_internal(minor_status, ctx,
require_mic ? &mech_buf : NULL,
&mech_output_token,
output_token);
if (mech_buf.value != NULL)
free(mech_buf.value);
free_NegTokenResp(&resp);
gss_release_buffer(&minor, &mech_output_token);
if (actual_mech_type)
*actual_mech_type = ctx->negotiated_mech_type;
if (ret_flags)
*ret_flags = ctx->mech_flags;
if (time_rec)
*time_rec = ctx->mech_time_rec;
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
OM_uint32 gss_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 (*context_handle == GSS_C_NO_CONTEXT)
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);
}

View File

@@ -0,0 +1,51 @@
-- $Id$
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)
}
NegHints ::= SEQUENCE {
hintName [0] GeneralString OPTIONAL,
hintAddress [1] OCTET STRING OPTIONAL
}
NegTokenInit ::= SEQUENCE {
mechTypes [0] MechTypeList,
reqFlags [1] ContextFlags OPTIONAL,
mechToken [2] OCTET STRING OPTIONAL,
negHints [3] NegHints OPTIONAL,
mechListMIC [4] OCTET STRING OPTIONAL
}
-- NB: negResult is not OPTIONAL in the new SPNEGO spec but
-- Windows clients do not always send it
NegTokenResp ::= SEQUENCE {
negResult [0] ENUMERATED {
accept_completed (0),
accept_incomplete (1),
reject (2),
request-mic (3) } OPTIONAL,
supportedMech [1] MechType OPTIONAL,
responseToken [2] OCTET STRING OPTIONAL,
mechListMIC [3] OCTET STRING OPTIONAL
}
NegotiationToken ::= CHOICE {
negTokenInit[0] NegTokenInit,
negTokenResp[1] NegTokenResp
}
END

View File

@@ -0,0 +1,458 @@
/*
* Copyright (c) 2004, 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$ */
#ifndef SPNEGO_LOCL_H
#define SPNEGO_LOCL_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#include <krb5_locl.h>
#include <gssapi_spnego.h>
#include <assert.h>
#include <der.h>
#include <mechglue.h>
#include "spnego_asn1.h"
gss_mechanism gss_spnego_initialize(void);
typedef struct gss_cred_id_t_desc_struct {
gss_cred_id_t negotiated_cred_id;
} gss_cred_id_t_desc;
typedef struct gss_ctx_id_t_desc_struct {
MechTypeList initiator_mech_types;
gss_OID preferred_mech_type;
gss_OID negotiated_mech_type;
gss_ctx_id_t negotiated_ctx_id;
OM_uint32 mech_flags;
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;
HEIMDAL_MUTEX ctx_id_mutex;
} gss_ctx_id_t_desc;
OM_uint32
_gss_spnego_encode_response(OM_uint32 *, const NegTokenResp *,
gss_buffer_t, u_char **);
OM_uint32
_gss_spnego_indicate_mechtypelist (OM_uint32 *, int,
const gss_cred_id_t cred_handle,
MechTypeList *,
gss_OID *preferred_mech);
OM_uint32 _gss_spnego_alloc_sec_context (OM_uint32 *,
gss_ctx_id_t *);
/*
* NB: caller must acquire ctx_id_mutex before
* calling _gss_spnego_delete_sec_context()
*/
OM_uint32 _gss_spnego_delete_sec_context (OM_uint32 *, gss_ctx_id_t *, gss_buffer_t);
OM_uint32 _gss_spnego_require_mechlist_mic(OM_uint32 *, gss_ctx_id_t, int *);
OM_uint32 gss_spnego_internal_release_oid(OM_uint32 *minor_status, gss_OID *OID);
int _gss_spnego_add_mech_type(gss_OID, int, MechTypeList *);
OM_uint32 _gss_spnego_select_mech(OM_uint32 *, MechType *, gss_OID *);
OM_uint32 _gss_spnego_alloc_cred(OM_uint32 *, gss_cred_id_t, gss_cred_id_t *);
OM_uint32 _gss_spnego_release_cred(OM_uint32 *, gss_cred_id_t *);
/*
* Finally, function prototypes for the GSS-API routines.
*/
OM_uint32 gss_spnego_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_spnego_release_cred
(OM_uint32 * /*minor_status*/,
gss_cred_id_t * /*cred_handle*/
);
OM_uint32 gss_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*/
);
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*/
);
OM_uint32 gss_spnego_process_context_token
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
const gss_buffer_t /*token_buffer*/
);
OM_uint32 gss_spnego_delete_sec_context
(OM_uint32 * /*minor_status*/,
gss_ctx_id_t * /*context_handle*/,
gss_buffer_t /*output_token*/
);
OM_uint32 gss_spnego_context_time
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
OM_uint32 * /*time_rec*/
);
OM_uint32 gss_spnego_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_spnego_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_spnego_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_spnego_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_spnego_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_spnego_indicate_mechs
(OM_uint32 * /*minor_status*/,
gss_OID_set * /*mech_set*/
);
OM_uint32 gss_spnego_compare_name
(OM_uint32 * /*minor_status*/,
const gss_name_t /*name1*/,
const gss_name_t /*name2*/,
int * /*name_equal*/
);
OM_uint32 gss_spnego_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_spnego_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_spnego_export_name
(OM_uint32 * /*minor_status*/,
const gss_name_t /*input_name*/,
gss_buffer_t /*exported_name*/
);
OM_uint32 gss_spnego_release_name
(OM_uint32 * /*minor_status*/,
gss_name_t * /*input_name*/
);
OM_uint32 gss_spnego_release_buffer
(OM_uint32 * /*minor_status*/,
gss_buffer_t /*buffer*/
);
OM_uint32 gss_spnego_release_oid_set
(OM_uint32 * /*minor_status*/,
gss_OID_set * /*set*/
);
OM_uint32 gss_spnego_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_spnego_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_spnego_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_spnego_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_spnego_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_spnego_export_sec_context (
OM_uint32 * /*minor_status*/,
gss_ctx_id_t * /*context_handle*/,
gss_buffer_t /*interprocess_token*/
);
OM_uint32 gss_spnego_import_sec_context (
OM_uint32 * /*minor_status*/,
const gss_buffer_t /*interprocess_token*/,
gss_ctx_id_t * /*context_handle*/
);
OM_uint32 gss_spnego_create_empty_oid_set (
OM_uint32 * /*minor_status*/,
gss_OID_set * /*oid_set*/
);
OM_uint32 gss_spnego_add_oid_set_member (
OM_uint32 * /*minor_status*/,
const gss_OID /*member_oid*/,
gss_OID_set * /*oid_set*/
);
OM_uint32 gss_spnego_test_oid_set_member (
OM_uint32 * /*minor_status*/,
const gss_OID /*member*/,
const gss_OID_set /*set*/,
int * /*present*/
);
OM_uint32 gss_spnego_inquire_names_for_mech (
OM_uint32 * /*minor_status*/,
const gss_OID /*mechanism*/,
gss_OID_set * /*name_types*/
);
OM_uint32 gss_spnego_inquire_mechs_for_name (
OM_uint32 * /*minor_status*/,
const gss_name_t /*input_name*/,
gss_OID_set * /*mech_types*/
);
OM_uint32 gss_spnego_duplicate_name (
OM_uint32 * /*minor_status*/,
const gss_name_t /*src_name*/,
gss_name_t * /*dest_name*/
);
OM_uint32 gss_spnego_canonicalize_name (
OM_uint32 * minor_status,
const gss_name_t src_name,
const gss_OID mech_type,
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_spnego_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_spnego_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_spnego_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_spnego_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*/
);
OM_uint32 gss_spnego_unwrap_ex
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
const gss_buffer_t /*token_header_buffer*/,
const gss_buffer_t /*associated_data_buffer*/,
const gss_buffer_t /*input_message_buffer*/,
gss_buffer_t /*output_message_buffer*/,
int * /*conf_state*/,
gss_qop_t * /*qop_state*/);
OM_uint32 gss_spnego_wrap_ex
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
int /*conf_req_flag*/,
gss_qop_t /*qop_req*/,
const gss_buffer_t /*associated_data_buffer*/,
const gss_buffer_t /*input_message_buffer*/,
int * /*conf_state*/,
gss_buffer_t /*output_token_buffer*/,
gss_buffer_t /*output_message_buffer*/
);
OM_uint32 gss_spnego_complete_auth_token
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
gss_buffer_t /*input_message_buffer*/);
OM_uint32 gss_spnego_inquire_sec_context_by_oid
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
const gss_OID /*desired_object*/,
gss_buffer_set_t */*data_set*/);
OM_uint32 gss_spnego_inquire_cred_by_oid
(OM_uint32 * /*minor_status*/,
const gss_cred_id_t /*cred_handle*/,
const gss_OID /*desired_object*/,
gss_buffer_set_t */*data_set*/);
OM_uint32 gss_spnego_set_sec_context_option
(OM_uint32 * /*minor_status*/,
gss_ctx_id_t * /*cred_handle*/,
const gss_OID /*desired_object*/,
const gss_buffer_t /*value*/);
#endif /* SPNEGO_LOCL_H */