#include "k5-int.h"
#include "gssapiP_krb5.h"
static krb5_error_code
kg_oid_externalize(gss_OID oid, krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code err;
err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
if (err)
return err;
err = krb5_ser_pack_int32((krb5_int32) oid->length,
buffer, lenremain);
if (err)
return err;
err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
oid->length, buffer, lenremain);
if (err)
return err;
err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
return err;
}
static krb5_error_code
kg_oid_internalize(gss_OID *argp, krb5_octet **buffer, size_t *lenremain)
{
gss_OID oid;
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
bp = *buffer;
remain = *lenremain;
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
return (EINVAL);
if (ibuf != KV5M_GSS_OID)
return (EINVAL);
oid = (gss_OID) malloc(sizeof(gss_OID_desc));
if (oid == NULL)
return ENOMEM;
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
free(oid);
return EINVAL;
}
oid->length = ibuf;
oid->elements = malloc((size_t)ibuf);
if (oid->elements == 0) {
free(oid);
return ENOMEM;
}
if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
oid->length, &bp, &remain)) {
free(oid->elements);
free(oid);
return EINVAL;
}
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
free(oid->elements);
free(oid);
return (EINVAL);
}
if (ibuf != KV5M_GSS_OID) {
free(oid->elements);
free(oid);
return (EINVAL);
}
*buffer = bp;
*lenremain = remain;
*argp = oid;
return 0;
}
static krb5_error_code
kg_oid_size(gss_OID oid, size_t *sizep)
{
krb5_error_code kret;
size_t required;
kret = EINVAL;
if (oid != NULL) {
required = 2*sizeof(krb5_int32);
required += sizeof(krb5_int32);
required += oid->length;
kret = 0;
*sizep += required;
}
return(kret);
}
static krb5_error_code
kg_seqstate_externalize(g_seqnum_state arg, krb5_octet **buffer,
size_t *lenremain)
{
krb5_error_code err;
err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
if (err == 0)
err = g_seqstate_externalize(arg, buffer, lenremain);
if (err == 0)
err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
return err;
}
static krb5_error_code
kg_seqstate_internalize(g_seqnum_state *argp, krb5_octet **buffer,
size_t *lenremain)
{
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
krb5_error_code err;
bp = *buffer;
remain = *lenremain;
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
return (EINVAL);
if (ibuf != KV5M_GSS_QUEUE)
return (EINVAL);
err = g_seqstate_internalize(argp, &bp, &remain);
if (err)
return err;
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
g_seqstate_free(*argp);
return (EINVAL);
}
if (ibuf != KV5M_GSS_QUEUE) {
g_seqstate_free(*argp);
return (EINVAL);
}
*buffer = bp;
*lenremain = remain;
return 0;
}
static krb5_error_code
kg_seqstate_size(g_seqnum_state arg, size_t *sizep)
{
krb5_error_code kret;
size_t required;
kret = EINVAL;
if (arg) {
required = 2*sizeof(krb5_int32);
g_seqstate_size(arg, &required);
kret = 0;
*sizep += required;
}
return(kret);
}
krb5_error_code
kg_ctx_size(krb5_context kcontext, krb5_gss_ctx_id_t ctx, size_t *sizep)
{
krb5_error_code kret;
size_t required;
kret = EINVAL;
if (ctx != NULL) {
required = 21*sizeof(krb5_int32);
required += 2*sizeof(int64_t);
required += sizeof(ctx->seed);
kret = 0;
if (!kret && ctx->here)
kret = k5_size_principal(ctx->here->princ, &required);
if (!kret && ctx->there)
kret = k5_size_principal(ctx->there->princ, &required);
if (!kret && ctx->subkey)
kret = k5_size_keyblock(&ctx->subkey->keyblock, &required);
if (!kret && ctx->enc)
kret = k5_size_keyblock(&ctx->enc->keyblock, &required);
if (!kret && ctx->seq)
kret = k5_size_keyblock(&ctx->seq->keyblock, &required);
if (!kret)
kret = kg_oid_size(ctx->mech_used, &required);
if (!kret && ctx->seqstate)
kret = kg_seqstate_size(ctx->seqstate, &required);
if (!kret)
kret = k5_size_context(ctx->k5_context, &required);
if (!kret)
kret = k5_size_auth_context(ctx->auth_context, &required);
if (!kret && ctx->acceptor_subkey)
kret = k5_size_keyblock(&ctx->acceptor_subkey->keyblock,
&required);
if (!kret && ctx->authdata) {
krb5_int32 i;
for (i = 0; !kret && ctx->authdata[i]; i++)
kret = k5_size_authdata(ctx->authdata[i], &required);
}
if (!kret) {
krb5_gss_name_t initiator_name;
initiator_name = ctx->initiate ? ctx->here : ctx->there;
if (initiator_name && initiator_name->ad_context) {
kret = k5_size_authdata_context(kcontext,
initiator_name->ad_context,
&required);
}
}
*sizep += required;
}
return(kret);
}
krb5_error_code
kg_ctx_externalize(krb5_context kcontext, krb5_gss_ctx_id_t ctx,
krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code kret;
size_t required;
krb5_octet *bp;
size_t remain;
krb5int_access kaccess;
kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
if (kret)
return(kret);
required = 0;
bp = *buffer;
remain = *lenremain;
kret = EINVAL;
if (ctx != NULL) {
kret = ENOMEM;
if (!kg_ctx_size(kcontext, ctx, &required) &&
(required <= remain)) {
(void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->established,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
&bp, &remain);
(void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
sizeof(ctx->seed),
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.authtime,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.starttime,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.endtime,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.renew_till,
&bp, &remain);
(void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
&bp, &remain);
(void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_send,
&bp, &remain);
(void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_recv,
&bp, &remain);
kret = 0;
if (!kret && ctx->mech_used)
kret = kg_oid_externalize(ctx->mech_used, &bp, &remain);
if (!kret && ctx->here)
kret = k5_externalize_principal(ctx->here->princ,
&bp, &remain);
if (!kret && ctx->there)
kret = k5_externalize_principal(ctx->there->princ,
&bp, &remain);
if (!kret && ctx->subkey)
kret = k5_externalize_keyblock(&ctx->subkey->keyblock,
&bp, &remain);
if (!kret && ctx->enc)
kret = k5_externalize_keyblock(&ctx->enc->keyblock,
&bp, &remain);
if (!kret && ctx->seq)
kret = k5_externalize_keyblock(&ctx->seq->keyblock,
&bp, &remain);
if (!kret && ctx->seqstate)
kret = kg_seqstate_externalize(ctx->seqstate, &bp, &remain);
if (!kret)
kret = k5_externalize_context(ctx->k5_context, &bp, &remain);
if (!kret)
kret = k5_externalize_auth_context(ctx->auth_context,
&bp, &remain);
if (!kret)
kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
&bp, &remain);
if (!kret)
kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
&bp, &remain);
if (!kret && ctx->acceptor_subkey)
kret = k5_externalize_keyblock(&ctx->acceptor_subkey->keyblock,
&bp, &remain);
if (!kret)
kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
&bp, &remain);
if (!kret)
kret = krb5_ser_pack_int32((krb5_int32) ctx->cred_rcache,
&bp, &remain);
if (!kret) {
krb5_int32 i = 0;
if (ctx->authdata) {
for (; ctx->authdata[i]; i++)
;
}
kret = krb5_ser_pack_int32(i, &bp, &remain);
if (!kret && ctx->authdata) {
for (i = 0; !kret && ctx->authdata[i]; i++)
kret = k5_externalize_authdata(ctx->authdata[i],
&bp, &remain);
}
}
if (!kret) {
krb5_gss_name_t initiator_name;
initiator_name = ctx->initiate ? ctx->here : ctx->there;
if (initiator_name && initiator_name->ad_context) {
kret = k5_externalize_authdata_context(kcontext,
initiator_name->
ad_context,
&bp, &remain);
}
}
if (!kret)
kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
if (!kret) {
*buffer = bp;
*lenremain = remain;
}
}
}
return(kret);
}
static krb5_error_code
intern_key(krb5_key *key, krb5_octet **bp, size_t *sp)
{
krb5_keyblock *keyblock;
krb5_error_code ret;
ret = k5_internalize_keyblock(&keyblock, bp, sp);
if (ret != 0)
return ret;
ret = krb5_k_create_key(NULL, keyblock, key);
krb5_free_keyblock(NULL, keyblock);
return ret;
}
krb5_error_code
kg_ctx_internalize(krb5_context kcontext, krb5_gss_ctx_id_t *argp,
krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code kret;
krb5_gss_ctx_id_rec *ctx;
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
krb5int_access kaccess;
krb5_principal princ;
kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
if (kret)
return(kret);
bp = *buffer;
remain = *lenremain;
kret = EINVAL;
princ = NULL;
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
ibuf = 0;
if (ibuf == KG_CONTEXT) {
kret = ENOMEM;
if ((remain >= (17*sizeof(krb5_int32)
+ 2*sizeof(int64_t)
+ sizeof(ctx->seed))) &&
(ctx = (krb5_gss_ctx_id_rec *)
xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
ctx->magic = ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->initiate = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->established = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->have_acceptor_subkey = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->seed_init = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->gss_flags = (int) ibuf;
(void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
sizeof(ctx->seed),
&bp, &remain);
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->signalg = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->cksum_size = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->sealalg = (int) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->krb_times.authtime = (krb5_timestamp) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->krb_times.starttime = (krb5_timestamp) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->krb_times.endtime = (krb5_timestamp) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->krb_times.renew_till = (krb5_timestamp) ibuf;
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->krb_flags = (krb5_flags) ibuf;
(void) (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_send,
&bp, &remain);
kret = (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_recv,
&bp, &remain);
if (kret) {
free(ctx);
return kret;
}
{
gss_OID tmp;
kret = kg_oid_internalize(&tmp, &bp, &remain);
if (kret == 0)
ctx->mech_used = tmp;
else if (kret == EINVAL)
kret = 0;
}
kret = k5_internalize_principal(&princ, &bp, &remain);
if (kret == 0) {
kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
KG_INIT_NAME_NO_COPY, &ctx->here);
if (kret)
krb5_free_principal(kcontext, princ);
} else if (kret == EINVAL)
kret = 0;
if (!kret) {
kret = k5_internalize_principal(&princ, &bp, &remain);
if (kret == 0) {
kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
KG_INIT_NAME_NO_COPY, &ctx->there);
if (kret)
krb5_free_principal(kcontext, princ);
} else if (kret == EINVAL)
kret = 0;
}
if (!kret &&
(kret = intern_key(&ctx->subkey, &bp, &remain))) {
if (kret == EINVAL)
kret = 0;
}
if (!kret &&
(kret = intern_key(&ctx->enc, &bp, &remain))) {
if (kret == EINVAL)
kret = 0;
}
if (!kret &&
(kret = intern_key(&ctx->seq, &bp, &remain))) {
if (kret == EINVAL)
kret = 0;
}
if (!kret) {
kret = kg_seqstate_internalize(&ctx->seqstate, &bp, &remain);
if (kret == EINVAL)
kret = 0;
}
if (!kret)
kret = k5_internalize_context(&ctx->k5_context, &bp, &remain);
if (!kret)
kret = k5_internalize_auth_context(&ctx->auth_context,
&bp, &remain);
if (!kret)
kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->proto = ibuf;
if (!kret)
kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->cksumtype = ibuf;
if (!kret &&
(kret = intern_key(&ctx->acceptor_subkey, &bp, &remain))) {
if (kret == EINVAL)
kret = 0;
}
if (!kret)
kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->acceptor_subkey_cksumtype = ibuf;
if (!kret)
kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
ctx->cred_rcache = ibuf;
if (!kret)
kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
if (!kret) {
krb5_int32 nadata = ibuf, i;
if (nadata > 0) {
ctx->authdata = (krb5_authdata **)calloc((size_t)nadata + 1,
sizeof(krb5_authdata *));
if (ctx->authdata == NULL) {
kret = ENOMEM;
} else {
for (i = 0; !kret && i < nadata; i++)
kret = k5_internalize_authdata(&ctx->authdata[i],
&bp, &remain);
}
}
}
if (!kret) {
krb5_gss_name_t initiator_name;
initiator_name = ctx->initiate ? ctx->here : ctx->there;
if (initiator_name == NULL) {
kret = EINVAL;
} else {
kret = k5_internalize_authdata_context(kcontext,
&initiator_name->
ad_context,
&bp, &remain);
if (kret == EINVAL)
kret = 0;
}
}
if (!kret)
kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
if (!kret && ibuf != KG_CONTEXT)
kret = EINVAL;
if (!kret) {
*buffer = bp;
*lenremain = remain;
*argp = ctx;
} else {
if (ctx->seq)
krb5_k_free_key(kcontext, ctx->seq);
if (ctx->enc)
krb5_k_free_key(kcontext, ctx->enc);
if (ctx->subkey)
krb5_k_free_key(kcontext, ctx->subkey);
if (ctx->there)
kg_release_name(kcontext, &ctx->there);
if (ctx->here)
kg_release_name(kcontext, &ctx->here);
xfree(ctx);
}
}
}
return(kret);
}