#include "k5-int.h"
#include "int-proto.h"
errcode_t profile_ser_size(profile_t, size_t *);
errcode_t profile_ser_externalize(profile_t, krb5_octet **, size_t *);
errcode_t profile_ser_internalize(profile_t *, krb5_octet **, size_t *);
static krb5_error_code size_oscontext(krb5_os_context os_ctx, size_t *sizep);
static krb5_error_code externalize_oscontext(krb5_os_context os_ctx,
krb5_octet **buffer,
size_t *lenremain);
static krb5_error_code internalize_oscontext(krb5_os_context *argp,
krb5_octet **buffer,
size_t *lenremain);
static inline unsigned int
etypes_len(krb5_enctype *list)
{
return (list == NULL) ? 0 : k5_count_etypes(list);
}
krb5_error_code
k5_size_context(krb5_context context, size_t *sizep)
{
krb5_error_code kret;
size_t required;
kret = EINVAL;
if (context != NULL) {
required = (9 * sizeof(krb5_int32) +
(etypes_len(context->tgs_etypes) * sizeof(krb5_int32)));
if (context->default_realm)
required += strlen(context->default_realm);
kret = size_oscontext(&context->os_context, &required);
if (!kret && context->profile)
kret = profile_ser_size(context->profile, &required);
}
if (!kret)
*sizep += required;
return(kret);
}
krb5_error_code
k5_externalize_context(krb5_context context,
krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code kret;
size_t required;
krb5_octet *bp;
size_t remain;
unsigned int i;
required = 0;
bp = *buffer;
remain = *lenremain;
if (!context)
return (EINVAL);
if (context->magic != KV5M_CONTEXT)
return (KV5M_CONTEXT);
if ((kret = k5_size_context(context, &required)))
return (kret);
if (required > remain)
return (ENOMEM);
kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
if (kret)
return (kret);
kret = krb5_ser_pack_int32((context->default_realm) ?
(krb5_int32) strlen(context->default_realm) : 0,
&bp, &remain);
if (kret)
return (kret);
if (context->default_realm) {
kret = krb5_ser_pack_bytes((krb5_octet *) context->default_realm,
strlen(context->default_realm),
&bp, &remain);
if (kret)
return (kret);
}
kret = krb5_ser_pack_int32(etypes_len(context->tgs_etypes), &bp, &remain);
if (kret)
return (kret);
if (context->tgs_etypes) {
for (i = 0; context->tgs_etypes[i]; i++) {
kret = krb5_ser_pack_int32(context->tgs_etypes[i], &bp, &remain);
if (kret)
return (kret);
}
}
kret = krb5_ser_pack_int32((krb5_int32) context->clockskew,
&bp, &remain);
if (kret)
return (kret);
kret = krb5_ser_pack_int32((krb5_int32) context->kdc_default_options,
&bp, &remain);
if (kret)
return (kret);
kret = krb5_ser_pack_int32((krb5_int32) context->library_options,
&bp, &remain);
if (kret)
return (kret);
kret = krb5_ser_pack_int32((krb5_int32) context->profile_secure,
&bp, &remain);
if (kret)
return (kret);
kret = krb5_ser_pack_int32((krb5_int32) context->fcc_default_format,
&bp, &remain);
if (kret)
return (kret);
kret = externalize_oscontext(&context->os_context, &bp, &remain);
if (kret)
return (kret);
if (context->profile != NULL) {
kret = profile_ser_externalize(context->profile, &bp, &remain);
if (kret)
return (kret);
}
kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
if (kret)
return (kret);
*buffer = bp;
*lenremain = remain;
return (0);
}
krb5_error_code
k5_internalize_context(krb5_context *argp,
krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code kret;
krb5_context context;
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
unsigned int i, count;
bp = *buffer;
remain = *lenremain;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
return (EINVAL);
if (ibuf != KV5M_CONTEXT)
return (EINVAL);
context = (krb5_context) calloc(1, sizeof(struct _krb5_context));
if (!context)
return (ENOMEM);
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
if (ibuf) {
context->default_realm = (char *) malloc((size_t) ibuf+1);
if (!context->default_realm) {
kret = ENOMEM;
goto cleanup;
}
kret = krb5_ser_unpack_bytes((krb5_octet *) context->default_realm,
(size_t) ibuf, &bp, &remain);
if (kret)
goto cleanup;
context->default_realm[ibuf] = '\0';
}
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
count = ibuf;
if (count > 0) {
context->tgs_etypes = calloc(count + 1, sizeof(krb5_enctype));
if (!context->tgs_etypes) {
kret = ENOMEM;
goto cleanup;
}
for (i = 0; i < count; i++) {
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->tgs_etypes[i] = ibuf;
}
context->tgs_etypes[count] = 0;
} else
context->tgs_etypes = NULL;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->clockskew = (krb5_deltat) ibuf;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->kdc_default_options = (krb5_flags) ibuf;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->library_options = (krb5_flags) ibuf;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->profile_secure = (krb5_boolean) ibuf;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->fcc_default_format = (int) ibuf;
{
krb5_os_context osp = 0;
kret = internalize_oscontext(&osp, &bp, &remain);
if (kret && (kret != EINVAL) && (kret != ENOENT))
goto cleanup;
if (osp)
context->os_context = *osp;
free(osp);
}
kret = profile_ser_internalize(&context->profile, &bp, &remain);
if (kret && (kret != EINVAL) && (kret != ENOENT))
goto cleanup;
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
if (ibuf != KV5M_CONTEXT) {
kret = EINVAL;
goto cleanup;
}
context->magic = KV5M_CONTEXT;
*buffer = bp;
*lenremain = remain;
*argp = context;
return 0;
cleanup:
if (context)
krb5_free_context(context);
return(kret);
}
krb5_error_code
size_oscontext(krb5_os_context os_ctx, size_t *sizep)
{
*sizep += (5*sizeof(krb5_int32));
return(0);
}
krb5_error_code
externalize_oscontext(krb5_os_context os_ctx,
krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code kret;
size_t required;
krb5_octet *bp;
size_t remain;
required = 0;
bp = *buffer;
remain = *lenremain;
kret = EINVAL;
if (os_ctx != NULL) {
kret = ENOMEM;
if (!size_oscontext(os_ctx, &required) && required <= remain) {
(void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
(void) krb5_ser_pack_int32(os_ctx->time_offset, &bp, &remain);
(void) krb5_ser_pack_int32(os_ctx->usec_offset, &bp, &remain);
(void) krb5_ser_pack_int32(os_ctx->os_flags, &bp, &remain);
(void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
kret = 0;
if (!kret) {
*buffer = bp;
*lenremain = remain;
}
}
}
return(kret);
}
static krb5_error_code
internalize_oscontext(krb5_os_context *argp,
krb5_octet **buffer, size_t *lenremain)
{
krb5_error_code kret;
krb5_os_context os_ctx;
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
bp = *buffer;
remain = *lenremain;
kret = EINVAL;
os_ctx = (krb5_os_context) NULL;
if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
ibuf = 0;
if (ibuf == KV5M_OS_CONTEXT) {
kret = ENOMEM;
if ((os_ctx = (krb5_os_context)
calloc(1, sizeof(struct _krb5_os_context))) &&
(remain >= 4*sizeof(krb5_int32))) {
os_ctx->magic = KV5M_OS_CONTEXT;
(void) krb5_ser_unpack_int32(&os_ctx->time_offset, &bp, &remain);
(void) krb5_ser_unpack_int32(&os_ctx->usec_offset, &bp, &remain);
(void) krb5_ser_unpack_int32(&os_ctx->os_flags, &bp, &remain);
(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
if (ibuf == KV5M_OS_CONTEXT) {
os_ctx->magic = KV5M_OS_CONTEXT;
kret = 0;
*buffer = bp;
*lenremain = remain;
} else
kret = EINVAL;
}
}
if (!kret) {
*argp = os_ctx;
}
else {
if (os_ctx)
free(os_ctx);
}
return(kret);
}