wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
@@ -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/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;
}
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 gssspnego_cred 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 != 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);
}
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,
NULL,
&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((unsigned char)*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,
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);
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,
gssspnego_ctx 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,
gssspnego_ctx 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_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;
*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 = (gssspnego_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,
ASN1_C_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 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 (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;
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 != NULL)
mech_cred = acceptor_cred->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 = 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 (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_internal_delete_sec_context(&minor, context_handle,
GSS_C_NO_BUFFER);
return ret;
}
@@ -0,0 +1,285 @@
/*
* 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/spnego_locl.h"
RCSID("$Id: compat.c,v 1.6 2006/10/07 22:26:59 lha Exp $");
/*
* 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)
{
gssspnego_ctx ctx;
ctx = calloc(1, sizeof(*ctx));
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 = GSS_C_NO_OID;
ctx->negotiated_mech_type = GSS_C_NO_OID;
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 = (gss_ctx_id_t)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_internal_delete_sec_context
(OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_buffer_t output_token
)
{
gssspnego_ctx 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 = (gssspnego_ctx)*context_handle;
*context_handle = GSS_C_NO_CONTEXT;
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);
ctx->negotiated_mech_type = GSS_C_NO_OID;
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,
gssspnego_ctx 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 == NULL) {
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;
}
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;
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_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;
ret = gss_duplicate_oid(minor_status,
&gss_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);
}
return ret;
}
@@ -0,0 +1,835 @@
/*
* 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/spnego_locl.h"
RCSID("$Id: context_stubs.c,v 1.8 2006/10/07 22:27:01 lha Exp $");
static OM_uint32
spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs)
{
OM_uint32 ret, junk;
gss_OID_set m;
int i;
ret = gss_indicate_mechs(minor_status, &m);
if (ret != GSS_S_COMPLETE)
return ret;
ret = gss_create_empty_oid_set(minor_status, mechs);
if (ret != GSS_S_COMPLETE) {
gss_release_oid_set(&junk, &m);
return ret;
}
for (i = 0; i < m->count; i++) {
if (gss_oid_equal(&m->elements[i], GSS_SPNEGO_MECHANISM))
continue;
ret = gss_add_oid_set_member(minor_status, &m->elements[i], mechs);
if (ret) {
gss_release_oid_set(&junk, &m);
gss_release_oid_set(&junk, mechs);
return ret;
}
}
return ret;
}
OM_uint32 _gss_spnego_process_context_token
(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_buffer_t token_buffer
)
{
gss_ctx_id_t context ;
gssspnego_ctx ctx;
OM_uint32 ret;
if (context_handle == GSS_C_NO_CONTEXT)
return GSS_S_NO_CONTEXT;
context = context_handle;
ctx = (gssspnego_ctx)context_handle;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = gss_process_context_token(minor_status,
ctx->negotiated_ctx_id,
token_buffer);
if (ret != GSS_S_COMPLETE) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
return _gss_spnego_internal_delete_sec_context(minor_status,
&context,
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
)
{
gssspnego_ctx ctx;
if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
return GSS_S_NO_CONTEXT;
ctx = (gssspnego_ctx)*context_handle;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
return _gss_spnego_internal_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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_context_time(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_get_mic(minor_status, ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_verify_mic(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_wrap(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_unwrap(minor_status,
ctx->negotiated_ctx_id,
input_message_buffer,
output_message_buffer,
conf_state,
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
)
{
return GSS_S_FAILURE;
}
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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_inquire_context(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_wrap_size_limit(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
OM_uint32 ret;
*minor_status = 0;
if (context_handle == NULL) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)*context_handle;
if (ctx == NULL)
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_internal_delete_sec_context(minor_status,
context_handle,
GSS_C_NO_BUFFER);
if (ret == GSS_S_COMPLETE)
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 context;
gssspnego_ctx ctx;
ret = _gss_spnego_alloc_sec_context(minor_status, &context);
if (ret != GSS_S_COMPLETE) {
return ret;
}
ctx = (gssspnego_ctx)context;
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_internal_delete_sec_context(&minor, context_handle, 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);
*context_handle = (gss_ctx_id_t)ctx;
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
)
{
gss_OID_set mechs, names, n;
OM_uint32 ret, junk;
int i, j;
*name_types = NULL;
ret = spnego_supported_mechs(minor_status, &mechs);
if (ret != GSS_S_COMPLETE)
return ret;
ret = gss_create_empty_oid_set(minor_status, &names);
if (ret != GSS_S_COMPLETE)
goto out;
for (i = 0; i < mechs->count; i++) {
ret = gss_inquire_names_for_mech(minor_status,
&mechs->elements[i],
&n);
if (ret)
continue;
for (j = 0; j < n->count; j++)
gss_add_oid_set_member(minor_status,
&n->elements[j],
&names);
gss_release_oid_set(&junk, &n);
}
ret = GSS_S_COMPLETE;
*name_types = names;
out:
gss_release_oid_set(&junk, &mechs);
return GSS_S_COMPLETE;
}
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 ret, junk;
ret = gss_create_empty_oid_set(minor_status, mech_types);
if (ret)
return ret;
ret = gss_add_oid_set_member(minor_status,
GSS_SPNEGO_MECHANISM,
mech_types);
if (ret)
gss_release_oid_set(&junk, mech_types);
return ret;
}
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
)
{
/* XXX */
return gss_duplicate_name(minor_status, input_name, 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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_sign(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_verify(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_seal(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_unseal(minor_status,
ctx->negotiated_ctx_id,
input_message_buffer,
output_message_buffer,
conf_state,
qop_state);
}
#if 0
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)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_unwrap_ex(minor_status,
ctx->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
)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
if ((ctx->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,
ctx->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)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_complete_auth_token(minor_status,
ctx->negotiated_ctx_id,
input_message_buffer);
}
#endif
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)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_inquire_sec_context_by_oid(minor_status,
ctx->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)
{
gssspnego_ctx ctx;
*minor_status = 0;
if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
ctx = (gssspnego_ctx)context_handle;
if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
return GSS_S_NO_CONTEXT;
}
return gss_set_sec_context_option(minor_status,
&ctx->negotiated_ctx_id,
desired_object,
value);
}
@@ -0,0 +1,291 @@
/*
* 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/spnego_locl.h"
RCSID("$Id: cred_stubs.c,v 1.5 2006/10/07 22:27:04 lha Exp $");
OM_uint32
_gss_spnego_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle)
{
gssspnego_cred cred;
OM_uint32 ret;
*minor_status = 0;
if (*cred_handle == GSS_C_NO_CREDENTIAL) {
return GSS_S_COMPLETE;
}
cred = (gssspnego_cred)*cred_handle;
ret = gss_release_cred(minor_status, &cred->negotiated_cred_id);
free(cred);
*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)
{
gssspnego_cred cred;
if (*cred_handle != GSS_C_NO_CREDENTIAL) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
cred = calloc(1, sizeof(*cred));
if (cred == NULL) {
*cred_handle = GSS_C_NO_CREDENTIAL;
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
cred->negotiated_cred_id = mech_cred_handle;
*cred_handle = (gss_cred_id_t)cred;
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;
gss_OID_set mechs;
int i, j;
gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;
gssspnego_cred cred;
*output_cred_handle = GSS_C_NO_CREDENTIAL;
ret = gss_indicate_mechs(minor_status, &mechs);
if (ret != GSS_S_COMPLETE)
return ret;
/* Remove ourselves from this list */
actual_desired_mechs.count = 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 < mechs->count; i++) {
if (gss_oid_equal(&mechs->elements[i], GSS_SPNEGO_MECHANISM))
continue;
actual_desired_mechs.elements[j] = mechs->elements[i];
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;
cred = (gssspnego_cred)cred_handle;
ret = gss_acquire_cred(minor_status, desired_name,
time_req, &actual_desired_mechs,
cred_usage,
&cred->negotiated_cred_id,
actual_mechs, time_rec);
if (ret != GSS_S_COMPLETE)
goto out;
*output_cred_handle = cred_handle;
out:
gss_release_oid_set(&tmp, &mechs);
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_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
)
{
gssspnego_cred cred;
OM_uint32 ret;
if (cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = 0;
return GSS_S_NO_CRED;
}
cred = (gssspnego_cred)cred_handle;
ret = gss_inquire_cred(minor_status,
cred->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;
gssspnego_cred input_cred, output_cred;
*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;
input_cred = (gssspnego_cred)input_cred_handle;
output_cred = (gssspnego_cred)spnego_output_cred_handle;
ret = gss_add_cred(minor_status,
input_cred->negotiated_cred_id,
desired_name,
desired_mech,
cred_usage,
initiator_time_req,
acceptor_time_req,
&output_cred->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
)
{
gssspnego_cred cred;
OM_uint32 ret;
if (cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = 0;
return GSS_S_NO_CRED;
}
cred = (gssspnego_cred)cred_handle;
ret = gss_inquire_cred_by_mech(minor_status,
cred->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)
{
gssspnego_cred cred;
OM_uint32 ret;
if (cred_handle == GSS_C_NO_CREDENTIAL) {
*minor_status = 0;
return GSS_S_NO_CRED;
}
cred = (gssspnego_cred)cred_handle;
ret = gss_inquire_cred_by_oid(minor_status,
cred->negotiated_cred_id,
desired_object,
data_set);
return ret;
}
@@ -0,0 +1,89 @@
/*
* 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/spnego_locl.h"
#include <gssapi_mech.h>
RCSID("$Id: external.c,v 1.7 2006/10/07 22:27:06 lha Exp $");
/*
* 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 gssapi_mech_interface_desc spnego_mech = {
GMI_VERSION,
"spnego",
{6, (void *)"\x2b\x06\x01\x05\x05\x02"},
_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_internal_delete_sec_context,
_gss_spnego_context_time,
_gss_spnego_get_mic,
_gss_spnego_verify_mic,
_gss_spnego_wrap,
_gss_spnego_unwrap,
_gss_spnego_display_status,
NULL,
_gss_spnego_compare_name,
_gss_spnego_display_name,
_gss_spnego_import_name,
_gss_spnego_export_name,
_gss_spnego_release_name,
_gss_spnego_inquire_cred,
_gss_spnego_inquire_context,
_gss_spnego_wrap_size_limit,
_gss_spnego_add_cred,
_gss_spnego_inquire_cred_by_mech,
_gss_spnego_export_sec_context,
_gss_spnego_import_sec_context,
_gss_spnego_inquire_names_for_mech,
_gss_spnego_inquire_mechs_for_name,
_gss_spnego_canonicalize_name,
_gss_spnego_duplicate_name
};
gssapi_mech_interface
__gss_spnego_initialize(void)
{
return &spnego_mech;
}
static gss_OID_desc _gss_spnego_mechanism_desc =
{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
gss_OID GSS_SPNEGO_MECHANISM = &_gss_spnego_mechanism_desc;
@@ -0,0 +1,578 @@
/*
* 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/spnego_locl.h"
RCSID("$Id: init_sec_context.c,v 1.6 2006/10/14 10:09:15 lha Exp $");
/*
* 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,
gssspnego_ctx 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,
gssspnego_cred cred,
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 context;
gssspnego_ctx ctx;
memset (&ni, 0, sizeof(ni));
*context_handle = GSS_C_NO_CONTEXT;
*minor_status = 0;
sub = _gss_spnego_alloc_sec_context(&minor, &context);
if (GSS_ERROR(sub)) {
*minor_status = minor;
return sub;
}
ctx = (gssspnego_ctx)context;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ctx->local = 1;
sub = _gss_spnego_indicate_mechtypelist(&minor, 0,
cred,
&ni.mechTypes,
&ctx->preferred_mech_type);
if (GSS_ERROR(sub)) {
*minor_status = minor;
_gss_spnego_internal_delete_sec_context(&minor, &context, 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,
(cred != NULL) ? cred->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_internal_delete_sec_context(&minor, &context, 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_internal_delete_sec_context(&minor, &context, 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_internal_delete_sec_context(&minor, &context, 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 + der_length_len(ni_len) + ni_len;
buf = malloc(buf_size);
if (buf == NULL) {
free_NegTokenInit(&ni);
*minor_status = ENOMEM;
_gss_spnego_internal_delete_sec_context(&minor, &context, 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,
ASN1_C_CONTEXT,
CONS,
0,
&tmp);
if (ret == 0 && tmp + buf_len != buf_size)
abort();
}
if (ret) {
*minor_status = ret;
free(buf);
free_NegTokenInit(&ni);
_gss_spnego_internal_delete_sec_context(&minor, &context, 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_internal_delete_sec_context(&minor, &context, 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 = context;
return GSS_S_CONTINUE_NEEDED;
}
static OM_uint32
spnego_reply
(OM_uint32 * minor_status,
const gssspnego_cred cred,
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;
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;
gssspnego_ctx ctx;
*minor_status = 0;
ctx = (gssspnego_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,
ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
if (ret)
return ret;
if (len > input_token->length - taglen)
return ASN1_OVERRUN;
ret = decode_NegTokenResp((const unsigned 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,
(cred != NULL) ? cred->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 = 1;
} 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 = 0;
}
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
)
{
gssspnego_cred cred = (gssspnego_cred)initiator_cred_handle;
if (*context_handle == GSS_C_NO_CONTEXT)
return spnego_initial (minor_status,
cred,
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,
cred,
context_handle,
target_name,
mech_type,
req_flags,
time_req,
input_chan_bindings,
input_token,
actual_mech_type,
output_token,
ret_flags,
time_rec);
}
@@ -0,0 +1,347 @@
/* This is a generated file */
#ifndef __spnego_private_h__
#define __spnego_private_h__
#include <stdarg.h>
gssapi_mech_interface
__gss_spnego_initialize (void);
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_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_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 );
int
_gss_spnego_add_mech_type (
gss_OID /*mech_type*/,
int /*includeMSCompatOID*/,
MechTypeList */*mechtypelist*/);
OM_uint32
_gss_spnego_alloc_cred (
OM_uint32 */*minor_status*/,
gss_cred_id_t /*mech_cred_handle*/,
gss_cred_id_t */*cred_handle*/);
OM_uint32
_gss_spnego_alloc_sec_context (
OM_uint32 * /*minor_status*/,
gss_ctx_id_t */*context_handle*/);
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 );
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_context_time (
OM_uint32 */*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
OM_uint32 *time_rec );
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_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_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_duplicate_name (
OM_uint32 * /*minor_status*/,
const gss_name_t /*src_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*/,
gss_buffer_t exported_name );
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_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_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_import_sec_context (
OM_uint32 * /*minor_status*/,
const gss_buffer_t /*interprocess_token*/,
gss_ctx_id_t *context_handle );
OM_uint32
_gss_spnego_indicate_mechtypelist (
OM_uint32 */*minor_status*/,
int /*includeMSCompatOID*/,
const gssspnego_cred /*cred_handle*/,
MechTypeList */*mechtypelist*/,
gss_OID */*preferred_mech*/);
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_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_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_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_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_inquire_mechs_for_name (
OM_uint32 * /*minor_status*/,
const gss_name_t /*input_name*/,
gss_OID_set * mech_types );
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_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_internal_delete_sec_context (
OM_uint32 */*minor_status*/,
gss_ctx_id_t */*context_handle*/,
gss_buffer_t output_token );
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_release_cred (
OM_uint32 */*minor_status*/,
gss_cred_id_t */*cred_handle*/);
OM_uint32
_gss_spnego_release_name (
OM_uint32 * /*minor_status*/,
gss_name_t * input_name );
OM_uint32
_gss_spnego_require_mechlist_mic (
OM_uint32 */*minor_status*/,
gssspnego_ctx /*ctx*/,
int */*require_mic*/);
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_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*/,
const gss_OID /*desired_object*/,
const gss_buffer_t /*value*/);
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_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 (
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_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_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_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 );
#endif /* __spnego_private_h__ */
@@ -0,0 +1,51 @@
-- $Id: spnego.asn1,v 1.1.1.1 2006/06/28 08:34:45 lha Exp $
SPNEGO DEFINITIONS ::=
BEGIN
MechType::= OBJECT IDENTIFIER
MechTypeList ::= SEQUENCE OF MechType
ContextFlags ::= BIT STRING {
delegFlag (0),
mutualFlag (1),
replayFlag (2),
sequenceFlag (3),
anonFlag (4),
confFlag (5),
integFlag (6)
}
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
@@ -0,0 +1,98 @@
/*
* 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: spnego_locl.h,v 1.12 2006/11/07 19:53:40 lha Exp $ */
#ifndef SPNEGO_LOCL_H
#define SPNEGO_LOCL_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#include <gssapi/gssapi_spnego.h>
#include <gssapi.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <heim_threads.h>
#include <asn1_err.h>
#include <gssapi_mech.h>
#include "spnego_asn1.h"
#include <der.h>
#include <roken.h>
#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
typedef struct {
gss_cred_id_t negotiated_cred_id;
} *gssspnego_cred;
typedef 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;
} *gssspnego_ctx;
#include <spnego/spnego-private.h>
#endif /* SPNEGO_LOCL_H */