#include "k5-int.h"
#include "gssapiP_krb5.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <stdlib.h>
#include <assert.h>
int krb5_gss_dbg_client_expcreds = 0;
static krb5_error_code
get_credentials(krb5_context context, krb5_gss_cred_id_t cred,
krb5_gss_name_t server, krb5_timestamp now,
krb5_timestamp endtime, krb5_creds **out_creds)
{
krb5_error_code code;
krb5_creds in_creds, evidence_creds, mcreds, *result_creds = NULL;
krb5_flags flags = 0;
krb5_principal_data server_data;
*out_creds = NULL;
k5_mutex_assert_locked(&cred->lock);
memset(&in_creds, 0, sizeof(krb5_creds));
memset(&evidence_creds, 0, sizeof(krb5_creds));
in_creds.client = in_creds.server = NULL;
assert(cred->name != NULL);
server_data = *server->princ;
if (cred->impersonator != NULL && server_data.type == KRB5_NT_SRV_HST)
server_data.realm = empty_data();
in_creds.server = &server_data;
in_creds.client = cred->name->princ;
in_creds.times.endtime = endtime;
in_creds.authdata = NULL;
in_creds.keyblock.enctype = 0;
if (cred->name->ad_context != NULL) {
code = krb5_authdata_export_authdata(context,
cred->name->ad_context,
AD_USAGE_TGS_REQ,
&in_creds.authdata);
if (code != 0)
goto cleanup;
}
if (cred->impersonator != NULL) {
if (krb5_principal_compare(context, cred->impersonator,
server->princ)) {
flags |= KRB5_GC_CACHED;
} else {
memset(&mcreds, 0, sizeof(mcreds));
mcreds.magic = KV5M_CREDS;
mcreds.server = cred->impersonator;
mcreds.client = cred->name->princ;
code = krb5_cc_retrieve_cred(context, cred->ccache,
KRB5_TC_MATCH_AUTHDATA, &mcreds,
&evidence_creds);
if (code)
goto cleanup;
in_creds.client = cred->impersonator;
in_creds.second_ticket = evidence_creds.ticket;
flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
}
}
if (cred->iakerb_mech)
flags |= KRB5_GC_CACHED;
code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, &result_creds);
if (code)
goto cleanup;
if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
if (!krb5_principal_compare(context, cred->name->princ,
result_creds->client)) {
code = KRB5_KDCREP_MODIFIED;
goto cleanup;
}
}
if (!krb5_gss_dbg_client_expcreds &&
ts_after(now, result_creds->times.endtime)) {
code = KRB5KRB_AP_ERR_TKT_EXPIRED;
goto cleanup;
}
*out_creds = result_creds;
result_creds = NULL;
cleanup:
krb5_free_authdata(context, in_creds.authdata);
krb5_free_cred_contents(context, &evidence_creds);
krb5_free_creds(context, result_creds);
return code;
}
struct gss_checksum_data {
krb5_gss_ctx_id_rec *ctx;
krb5_gss_cred_id_t cred;
krb5_checksum md5;
krb5_data checksum_data;
krb5_gss_ctx_ext_t exts;
};
#ifdef CFX_EXERCISE
#include "../../krb5/krb/auth_con.h"
#endif
static krb5_error_code KRB5_CALLCONV
make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
void *cksum_data, krb5_data **out)
{
krb5_error_code code;
krb5_int32 con_flags;
struct gss_checksum_data *data = cksum_data;
krb5_data credmsg;
unsigned int junk;
krb5_data *finished = NULL;
krb5_key send_subkey;
struct k5buf buf;
data->checksum_data = empty_data();
credmsg.data = 0;
if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
krb5_auth_con_getflags(context, auth_context, &con_flags);
krb5_auth_con_setflags(context, auth_context,
con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
assert(data->cred->name != NULL);
krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
krb5_auth_con_setsendsubkey_k(context, auth_context, NULL);
code = krb5_fwd_tgt_creds(context, auth_context, 0,
data->cred->name->princ, data->ctx->there->princ,
data->cred->ccache, 1,
&credmsg);
krb5_auth_con_setflags(context, auth_context, con_flags);
krb5_auth_con_setsendsubkey_k(context, auth_context, send_subkey);
krb5_k_free_key(context, send_subkey);
if (code) {
data->ctx->gss_flags &= ~(GSS_C_DELEG_FLAG |
GSS_C_DELEG_POLICY_FLAG);
} else {
if (credmsg.length+28 > KRB5_INT16_MAX) {
code = KRB5KRB_ERR_FIELD_TOOLONG;
goto cleanup;
}
}
}
#ifdef CFX_EXERCISE
if (data->ctx->auth_context->keyblock != NULL
&& data->ctx->auth_context->keyblock->enctype == 18) {
srand(time(0) ^ getpid());
junk = rand() & 0xff;
} else
junk = 0;
#else
junk = 0;
#endif
assert(data->exts != NULL);
if (data->exts->iakerb.conv) {
krb5_key key;
code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key);
if (code != 0)
goto cleanup;
code = iakerb_make_finished(context, key, data->exts->iakerb.conv,
&finished);
if (code != 0) {
krb5_k_free_key(context, key);
goto cleanup;
}
krb5_k_free_key(context, key);
}
k5_buf_init_dynamic(&buf);
k5_buf_add_uint32_le(&buf, data->md5.length);
k5_buf_add_len(&buf, data->md5.contents, data->md5.length);
k5_buf_add_uint32_le(&buf, data->ctx->gss_flags);
if (credmsg.data != NULL) {
k5_buf_add_uint16_le(&buf, KRB5_GSS_FOR_CREDS_OPTION);
k5_buf_add_uint16_le(&buf, credmsg.length);
k5_buf_add_len(&buf, credmsg.data, credmsg.length);
}
if (data->exts->iakerb.conv != NULL) {
k5_buf_add_uint32_be(&buf, GSS_EXTS_FINISHED);
k5_buf_add_uint32_be(&buf, finished->length);
k5_buf_add_len(&buf, finished->data, finished->length);
}
while (junk--)
k5_buf_add_byte(&buf, 'i');
code = k5_buf_status(&buf);
if (code)
goto cleanup;
data->checksum_data = make_data(buf.data, buf.len);
*out = &data->checksum_data;
code = 0;
cleanup:
krb5_free_data_contents(context, &credmsg);
krb5_free_data(context, finished);
return code;
}
static krb5_error_code
make_ap_req_v1(krb5_context context, krb5_gss_ctx_id_rec *ctx,
krb5_gss_cred_id_t cred, krb5_creds *k_cred,
krb5_authdata_context ad_context,
gss_channel_bindings_t chan_bindings, gss_OID mech_type,
int cbt_flag, gss_buffer_t token, krb5_gss_ctx_ext_t exts)
{
krb5_flags mk_req_flags = 0;
krb5_error_code code;
struct gss_checksum_data cksum_struct;
krb5_checksum md5;
krb5_data ap_req;
unsigned char *t;
unsigned int tlen;
struct k5buf buf;
k5_mutex_assert_locked(&cred->lock);
ap_req.data = 0;
if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5)))
return(code);
krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
CKSUMTYPE_KG_CB);
cksum_struct.md5 = md5;
cksum_struct.ctx = ctx;
cksum_struct.cred = cred;
cksum_struct.checksum_data.data = NULL;
cksum_struct.exts = exts;
krb5_auth_con_set_checksum_func(context, ctx->auth_context,
make_gss_checksum, &cksum_struct);
mk_req_flags = AP_OPTS_USE_SUBKEY;
if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION;
if (cbt_flag)
mk_req_flags |= AP_OPTS_CBT_FLAG;
krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context);
code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
NULL, k_cred, &ap_req);
krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL);
krb5_free_checksum_contents(context, &cksum_struct.md5);
krb5_free_data_contents(context, &cksum_struct.checksum_data);
if (code)
goto cleanup;
ctx->krb_times = k_cred->times;
ctx->krb_flags = k_cred->ticket_flags;
if (ctx->gss_flags & GSS_C_DCE_STYLE) {
code = data_to_gss(&ap_req, token);
if (code)
goto cleanup;
} else {
tlen = g_token_size((gss_OID) mech_type, ap_req.length);
t = gssalloc_malloc(tlen);
if (t == NULL) {
code = ENOMEM;
goto cleanup;
}
k5_buf_init_fixed(&buf, t, tlen);
g_make_token_header(&buf, mech_type, ap_req.length, KG_TOK_CTX_AP_REQ);
k5_buf_add_len(&buf, ap_req.data, ap_req.length);
assert(buf.len == tlen);
token->length = tlen;
token->value = (void *) t;
}
code = 0;
cleanup:
if (ap_req.data)
krb5_free_data_contents(context, &ap_req);
return (code);
}
static OM_uint32
kg_new_connection(
OM_uint32 *minor_status,
krb5_gss_cred_id_t cred,
gss_ctx_id_t *context_handle,
gss_name_t target_name,
gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_OID *actual_mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
krb5_context context,
krb5_gss_ctx_ext_t exts)
{
OM_uint32 major_status;
krb5_error_code code;
krb5_creds *k_cred = NULL;
krb5_gss_ctx_id_rec *ctx, *ctx_free;
krb5_timestamp now;
gss_buffer_desc token;
krb5_keyblock *keyblock;
int cbt_flag = (req_flags & GSS_C_CHANNEL_BOUND_FLAG) != 0;
k5_mutex_assert_locked(&cred->lock);
major_status = GSS_S_FAILURE;
token.length = 0;
token.value = NULL;
if ((cred->usage != GSS_C_INITIATE) &&
(cred->usage != GSS_C_BOTH)) {
*minor_status = 0;
return(GSS_S_NO_CRED);
}
if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
*minor_status = 0;
return(GSS_S_DEFECTIVE_TOKEN);
}
if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
== NULL) {
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
ctx->magic = KG_CONTEXT;
ctx_free = ctx;
if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
goto cleanup;
krb5_auth_con_setflags(context, ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE);
if (cred->req_enctypes) {
if ((code = krb5_set_default_tgs_enctypes(context,
cred->req_enctypes))) {
goto cleanup;
}
}
ctx->initiate = 1;
ctx->seed_init = 0;
ctx->seqstate = 0;
if (context->enforce_ok_as_delegate && (req_flags & GSS_C_DELEG_FLAG)) {
req_flags &= ~GSS_C_DELEG_FLAG;
req_flags |= GSS_C_DELEG_POLICY_FLAG;
}
ctx->gss_flags = req_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG |
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
GSS_C_EXTENDED_ERROR_FLAG);
ctx->gss_flags |= GSS_C_TRANS_FLAG;
if (!cred->suppress_ci_flags)
ctx->gss_flags |= (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
if (req_flags & GSS_C_DCE_STYLE)
ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
if ((code = krb5_timeofday(context, &now)))
goto cleanup;
if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
ctx->krb_times.endtime = 0;
} else {
ctx->krb_times.endtime = ts_incr(now, time_req);
}
if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
goto cleanup;
if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name,
&ctx->there)))
goto cleanup;
code = get_credentials(context, cred, ctx->there, now,
ctx->krb_times.endtime, &k_cred);
if (code)
goto cleanup;
ctx->krb_times = k_cred->times;
if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
&& (k_cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE))
ctx->gss_flags |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
!= GSS_S_COMPLETE) {
code = *minor_status;
goto cleanup;
}
ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
{
krb5_int32 seq_temp;
if ((code = make_ap_req_v1(context, ctx,
cred, k_cred, ctx->here->ad_context,
input_chan_bindings, mech_type, cbt_flag,
&token, exts))) {
if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
(code == KG_EMPTY_CCACHE))
major_status = GSS_S_NO_CRED;
if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
major_status = GSS_S_CREDENTIALS_EXPIRED;
goto cleanup;
}
krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
ctx->seq_send = (uint32_t)seq_temp;
code = krb5_auth_con_getsendsubkey(context, ctx->auth_context,
&keyblock);
if (code != 0)
goto cleanup;
code = krb5_k_create_key(context, keyblock, &ctx->subkey);
krb5_free_keyblock(context, keyblock);
if (code != 0)
goto cleanup;
}
ctx->enc = NULL;
ctx->seq = NULL;
ctx->have_acceptor_subkey = 0;
code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
if (code != 0)
goto cleanup;
if (!(ctx->gss_flags & GSS_C_MUTUAL_FLAG)) {
ctx->seq_recv = ctx->seq_send;
code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
ctx->proto);
if (code != 0)
goto cleanup;
}
if (time_rec) {
if ((code = krb5_timeofday(context, &now)))
goto cleanup;
*time_rec = ts_interval(now, ctx->krb_times.endtime);
}
*output_token = token;
if (ret_flags)
*ret_flags = ctx->gss_flags;
if (actual_mech_type)
*actual_mech_type = mech_type;
*context_handle = (gss_ctx_id_t) ctx;
ctx_free = NULL;
if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
ctx->established = 0;
major_status = GSS_S_CONTINUE_NEEDED;
} else {
ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
ctx->established = 1;
major_status = GSS_S_COMPLETE;
}
cleanup:
krb5_free_creds(context, k_cred);
if (ctx_free) {
if (ctx_free->auth_context)
krb5_auth_con_free(context, ctx_free->auth_context);
if (ctx_free->here)
kg_release_name(context, &ctx_free->here);
if (ctx_free->there)
kg_release_name(context, &ctx_free->there);
if (ctx_free->subkey)
krb5_k_free_key(context, ctx_free->subkey);
xfree(ctx_free);
}
*minor_status = code;
return (major_status);
}
static OM_uint32
mutual_auth(
OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_name_t target_name,
gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_OID *actual_mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
krb5_context context)
{
OM_uint32 major_status;
struct k5input in;
uint16_t toktype;
krb5_data body;
krb5_ap_rep_enc_part *ap_rep_data;
krb5_timestamp now;
krb5_gss_ctx_id_rec *ctx;
krb5_error *krb_error;
krb5_error_code code;
krb5int_access kaccess;
major_status = GSS_S_FAILURE;
code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
if (code)
goto fail;
ctx = (krb5_gss_ctx_id_t) *context_handle;
if ((ctx->established) ||
((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
code = KG_CONTEXT_ESTABLISHED;
goto fail;
}
if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) {
(void)krb5_gss_delete_sec_context(minor_status,
context_handle, NULL);
code = 0;
major_status = GSS_S_BAD_NAME;
goto fail;
}
if (input_token == GSS_C_NO_BUFFER) {
(void)krb5_gss_delete_sec_context(minor_status,
context_handle, NULL);
code = 0;
major_status = GSS_S_DEFECTIVE_TOKEN;
goto fail;
}
if (ctx->gss_flags & GSS_C_DCE_STYLE) {
body = make_data(input_token->value, input_token->length);
} else {
k5_input_init(&in, input_token->value, input_token->length);
if (!g_verify_token_header(&in, ctx->mech_used)) {
*minor_status = 0;
return(GSS_S_DEFECTIVE_TOKEN);
}
toktype = k5_input_get_uint16_be(&in);
body = make_data((uint8_t *)in.ptr, in.len);
if (toktype == KG_TOK_CTX_ERROR) {
code = krb5_rd_error(context, &body, &krb_error);
if (code)
goto fail;
if (krb_error->error)
code = (krb5_error_code)krb_error->error + ERROR_TABLE_BASE_krb5;
else
code = 0;
krb5_free_error(context, krb_error);
goto fail;
} else if (toktype != KG_TOK_CTX_AP_REP) {
*minor_status = 0;
return(GSS_S_DEFECTIVE_TOKEN);
}
}
code = krb5_rd_rep(context, ctx->auth_context, &body, &ap_rep_data);
if (code) {
krb5_auth_con_setuseruserkey(context, ctx->auth_context,
&ctx->subkey->keyblock);
if (krb5_rd_rep(context, ctx->auth_context, &body, &ap_rep_data) != 0)
goto fail;
}
ctx->seq_recv = ap_rep_data->seq_number;
code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
ctx->proto);
if (code) {
krb5_free_ap_rep_enc_part(context, ap_rep_data);
goto fail;
}
if (ap_rep_data->subkey != NULL &&
(ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
ap_rep_data->subkey->enctype != ctx->subkey->keyblock.enctype)) {
ctx->have_acceptor_subkey = 1;
code = krb5_k_create_key(context, ap_rep_data->subkey,
&ctx->acceptor_subkey);
if (code) {
krb5_free_ap_rep_enc_part(context, ap_rep_data);
goto fail;
}
code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
&ctx->acceptor_subkey_cksumtype);
if (code) {
krb5_free_ap_rep_enc_part(context, ap_rep_data);
goto fail;
}
}
krb5_free_ap_rep_enc_part(context, ap_rep_data);
if (ctx->gss_flags & GSS_C_DCE_STYLE) {
krb5_data outbuf;
code = krb5_mk_rep_dce(context, ctx->auth_context, &outbuf);
if (code)
goto fail;
code = data_to_gss(&outbuf, output_token);
if (code)
goto fail;
}
ctx->established = 1;
if (time_rec) {
if ((code = krb5_timeofday(context, &now)))
goto fail;
*time_rec = ts_interval(now, ctx->krb_times.endtime);
}
if (ret_flags)
*ret_flags = ctx->gss_flags;
if (actual_mech_type)
*actual_mech_type = mech_type;
*minor_status = 0;
return GSS_S_COMPLETE;
fail:
(void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
*minor_status = code;
return (major_status);
}
OM_uint32
krb5_gss_init_sec_context_ext(
OM_uint32 *minor_status,
gss_cred_id_t claimant_cred_handle,
gss_ctx_id_t *context_handle,
gss_name_t target_name,
gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_OID *actual_mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
krb5_gss_ctx_ext_t exts)
{
krb5_context context;
gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
krb5_gss_cred_id_t cred;
krb5_error_code kerr;
OM_uint32 major_status;
OM_uint32 tmp_min_stat;
if (*context_handle == GSS_C_NO_CONTEXT) {
kerr = krb5_gss_init_context(&context);
if (kerr) {
*minor_status = kerr;
return GSS_S_FAILURE;
}
if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
save_error_info(*minor_status, context);
krb5_free_context(context);
return GSS_S_FAILURE;
}
} else {
context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
}
major_status = GSS_S_FAILURE;
output_token->length = 0;
output_token->value = NULL;
if (actual_mech_type)
*actual_mech_type = NULL;
if (mech_type == GSS_C_NULL_OID || g_OID_equal(mech_type, gss_mech_krb5)) {
mech_type = (gss_OID) gss_mech_krb5;
} else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
mech_type = (gss_OID) gss_mech_krb5_old;
} else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
mech_type = (gss_OID) gss_mech_krb5_wrong;
} else if (g_OID_equal(mech_type, gss_mech_iakerb)) {
mech_type = (gss_OID) gss_mech_iakerb;
} else {
*minor_status = 0;
if (*context_handle == GSS_C_NO_CONTEXT)
krb5_free_context(context);
return(GSS_S_BAD_MECH);
}
if (*context_handle == GSS_C_NO_CONTEXT) {
if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
major_status = kg_get_defcred(minor_status, &defcred);
if (major_status && GSS_ERROR(major_status)) {
if (*context_handle == GSS_C_NO_CONTEXT)
krb5_free_context(context);
return(major_status);
}
claimant_cred_handle = defcred;
}
major_status = kg_cred_resolve(minor_status, context,
claimant_cred_handle, target_name);
if (GSS_ERROR(major_status)) {
save_error_info(*minor_status, context);
krb5_gss_release_cred(&tmp_min_stat, &defcred);
if (*context_handle == GSS_C_NO_CONTEXT)
krb5_free_context(context);
return(major_status);
}
cred = (krb5_gss_cred_id_t)claimant_cred_handle;
major_status = kg_new_connection(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,
context, exts);
k5_mutex_unlock(&cred->lock);
krb5_gss_release_cred(&tmp_min_stat, &defcred);
if (*context_handle == GSS_C_NO_CONTEXT) {
save_error_info (*minor_status, context);
krb5_free_context(context);
} else
((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
} else {
major_status = mutual_auth(minor_status, context_handle,
target_name, mech_type, req_flags,
time_req, input_chan_bindings,
input_token, actual_mech_type,
output_token, ret_flags, time_rec,
context);
}
return(major_status);
}
#ifndef _WIN32
k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
static int kdc_flag = 0;
#endif
krb5_error_code
krb5_gss_init_context (krb5_context *ctxp)
{
krb5_error_code err;
#ifndef _WIN32
int is_kdc;
#endif
err = gss_krb5int_initialize_library();
if (err)
return err;
#ifndef _WIN32
k5_mutex_lock(&kg_kdc_flag_mutex);
is_kdc = kdc_flag;
k5_mutex_unlock(&kg_kdc_flag_mutex);
if (is_kdc)
return krb5int_init_context_kdc(ctxp);
#endif
return krb5_init_context(ctxp);
}
#ifndef _WIN32
OM_uint32
krb5int_gss_use_kdc_context(OM_uint32 *minor_status,
const gss_OID desired_mech,
const gss_OID desired_object,
gss_buffer_t value)
{
OM_uint32 err;
*minor_status = 0;
err = gss_krb5int_initialize_library();
if (err)
return err;
k5_mutex_lock(&kg_kdc_flag_mutex);
kdc_flag = 1;
k5_mutex_unlock(&kg_kdc_flag_mutex);
return GSS_S_COMPLETE;
}
#endif
OM_uint32 KRB5_CALLCONV
krb5_gss_init_sec_context(OM_uint32 *minor_status,
gss_cred_id_t claimant_cred_handle,
gss_ctx_id_t *context_handle,
gss_name_t target_name, gss_OID mech_type,
OM_uint32 req_flags, OM_uint32 time_req,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token, gss_OID *actual_mech_type,
gss_buffer_t output_token, OM_uint32 *ret_flags,
OM_uint32 *time_rec)
{
krb5_gss_ctx_ext_rec exts;
memset(&exts, 0, sizeof(exts));
return krb5_gss_init_sec_context_ext(minor_status,
claimant_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,
&exts);
}