#include "gssapiP_krb5.h"
OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_context(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
gss_name_t *initiator_name, gss_name_t *acceptor_name,
OM_uint32 *lifetime_rec, gss_OID *mech_type,
OM_uint32 *ret_flags, int *locally_initiated,
int *opened)
{
krb5_context context;
krb5_error_code code;
krb5_gss_ctx_id_rec *ctx;
krb5_gss_name_t initiator, acceptor;
krb5_timestamp now, start;
OM_uint32 lifetime;
if (initiator_name)
*initiator_name = (gss_name_t) NULL;
if (acceptor_name)
*acceptor_name = (gss_name_t) NULL;
ctx = (krb5_gss_ctx_id_rec *) context_handle;
context = ctx->k5_context;
if (ctx->established) {
initiator = NULL;
acceptor = NULL;
if ((code = krb5_timeofday(context, &now))) {
*minor_status = code;
save_error_info(*minor_status, context);
return(GSS_S_FAILURE);
}
start = ctx->initiate ? now : ts_incr(now, -context->clockskew);
lifetime = ts_interval(start, ctx->krb_times.endtime);
if (initiator_name) {
code = kg_duplicate_name(context,
ctx->initiate ? ctx->here : ctx->there,
&initiator);
if (code) {
*minor_status = code;
save_error_info(*minor_status, context);
return(GSS_S_FAILURE);
}
}
if (acceptor_name) {
code = kg_duplicate_name(context,
ctx->initiate ? ctx->there : ctx->here,
&acceptor);
if (code) {
if (initiator)
kg_release_name(context, &initiator);
*minor_status = code;
save_error_info(*minor_status, context);
return(GSS_S_FAILURE);
}
}
if (initiator_name)
*initiator_name = (gss_name_t) initiator;
if (acceptor_name)
*acceptor_name = (gss_name_t) acceptor;
if (lifetime_rec)
*lifetime_rec = lifetime;
} else {
lifetime = 0;
if (initiator_name)
*initiator_name = GSS_C_NO_NAME;
if (acceptor_name)
*acceptor_name = GSS_C_NO_NAME;
if (lifetime_rec)
*lifetime_rec = 0;
}
if (mech_type)
*mech_type = (gss_OID) ctx->mech_used;
if (ret_flags)
*ret_flags = ctx->gss_flags;
if (locally_initiated)
*locally_initiated = ctx->initiate;
if (opened)
*opened = ctx->established;
*minor_status = 0;
if (ctx->established)
return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
else
return GSS_S_COMPLETE;
}
static OM_uint32
inq_session_key_result(OM_uint32 *minor_status, krb5_key key,
gss_buffer_set_t *data_set)
{
gss_buffer_desc keyvalue, keyinfo;
OM_uint32 major, tmpmin;
unsigned char oid_buf[GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH + 6];
gss_OID_desc oid;
keyvalue.value = key->keyblock.contents;
keyvalue.length = key->keyblock.length;
major = generic_gss_add_buffer_set_member(minor_status, &keyvalue,
data_set);
if (GSS_ERROR(major))
goto cleanup;
oid.elements = oid_buf;
oid.length = sizeof(oid_buf);
major = generic_gss_oid_compose(minor_status,
GSS_KRB5_SESSION_KEY_ENCTYPE_OID,
GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
key->keyblock.enctype, &oid);
if (GSS_ERROR(major))
goto cleanup;
keyinfo.value = oid.elements;
keyinfo.length = oid.length;
major = generic_gss_add_buffer_set_member(minor_status, &keyinfo,
data_set);
if (GSS_ERROR(major))
goto cleanup;
return GSS_S_COMPLETE;
cleanup:
if (*data_set != GSS_C_NO_BUFFER_SET) {
if ((*data_set)->count != 0) {
zap((*data_set)->elements[0].value,
(*data_set)->elements[0].length);
}
gss_release_buffer_set(&tmpmin, data_set);
}
return major;
}
OM_uint32
gss_krb5int_inq_sspi_session_key(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle;
krb5_key key;
if (ctx->terminated || !ctx->established) {
*minor_status = KG_CTX_INCOMPLETE;
return GSS_S_NO_CONTEXT;
}
key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
return inq_session_key_result(minor_status, key, data_set);
}
OM_uint32
gss_krb5int_inq_odbc_session_key(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
OM_uint32 major;
krb5_error_code ret;
krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle;
krb5_key key;
if (ctx->terminated || !ctx->established) {
*minor_status = KG_CTX_INCOMPLETE;
return GSS_S_NO_CONTEXT;
}
ret = krb5_auth_con_getkey_k(ctx->k5_context, ctx->auth_context, &key);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
major = inq_session_key_result(minor_status, key, data_set);
krb5_k_free_key(ctx->k5_context, key);
return major;
}
OM_uint32
gss_krb5int_extract_authz_data_from_sec_context(
OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
OM_uint32 major_status;
krb5_gss_ctx_id_rec *ctx;
int ad_type = 0;
size_t i;
*data_set = GSS_C_NO_BUFFER_SET;
ctx = (krb5_gss_ctx_id_rec *) context_handle;
major_status = generic_gss_oid_decompose(minor_status,
GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
desired_object,
&ad_type);
if (major_status != GSS_S_COMPLETE || ad_type == 0) {
*minor_status = ENOENT;
return GSS_S_FAILURE;
}
if (ctx->authdata != NULL) {
for (i = 0; ctx->authdata[i] != NULL; i++) {
if (ctx->authdata[i]->ad_type == ad_type) {
gss_buffer_desc ad_data;
ad_data.length = ctx->authdata[i]->length;
ad_data.value = ctx->authdata[i]->contents;
major_status = generic_gss_add_buffer_set_member(minor_status,
&ad_data, data_set);
if (GSS_ERROR(major_status))
break;
}
}
}
if (GSS_ERROR(major_status)) {
OM_uint32 tmp;
generic_gss_release_buffer_set(&tmp, data_set);
}
return major_status;
}
OM_uint32
gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_OID desired_oid,
gss_buffer_set_t *data_set)
{
krb5_gss_ctx_id_rec *ctx;
gss_buffer_desc rep;
ctx = (krb5_gss_ctx_id_rec *) context_handle;
rep.value = &ctx->krb_times.authtime;
rep.length = sizeof(ctx->krb_times.authtime);
return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
}
OM_uint32
gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status,
const gss_ctx_id_t context_handle,
const gss_OID desired_object,
gss_buffer_set_t *data_set)
{
krb5_gss_ctx_id_rec *ctx;
krb5_key key;
krb5_error_code code;
gss_buffer_desc ssfbuf;
unsigned int ssf;
uint8_t buf[4];
ctx = (krb5_gss_ctx_id_rec *)context_handle;
key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf);
if (code)
return GSS_S_FAILURE;
store_32_be(ssf, buf);
ssfbuf.value = buf;
ssfbuf.length = sizeof(buf);
return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set);
}