ratatoskr-messenger/lib/ZDumpSession.c

139 lines
3.4 KiB
C

/* This file is part of the Project Athena Zephyr Notification System.
* It contains source for the session dump and restore function.
*
* Created by: David Benjamin
*
* $Id$
*
* Copyright (c) 2013 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#ifndef lint
static const char rcsid_ZDumpSession_c[] = "$Id$";
#endif
#include <internal.h>
#define SESSION_VERSION 1
Code_t
ZDumpSession(char **buffer,
int *ret_len)
{
#ifdef HAVE_KRB5
struct _Z_SessionKey *key;
uint32_t num_keys = 0;
#endif
char *ptr;
int len;
/*
* We serialize the port number and all keys. All numbers are
* stored in big-endian. Byte strings are prefixed with a 32-bit
* length. First field is 16-bit version number. Keys are stored
* in reverse.
*/
len = 2 + 2; /* version, port number */
#ifdef HAVE_KRB5
len += 4; /* num_keys */
for (key = Z_keys_head; key != NULL; key = key->next) {
num_keys++;
len += 4 + 4; /* enctype, length */
len += key->keyblock->length; /* contents */
}
#endif
*ret_len = len;
if (!(*buffer = (char *) malloc((unsigned)*ret_len)))
return (ENOMEM);
ptr = *buffer;
*((uint16_t*) ptr) = htons(SESSION_VERSION); ptr += 2;
*((uint16_t*) ptr) = htons(__Zephyr_port); ptr += 2;
#ifdef HAVE_KRB5
*((uint32_t *)ptr) = htonl(num_keys); ptr += 4;
for (key = Z_keys_tail; key != NULL; key = key->prev) {
*((uint32_t*) ptr) = htonl(key->keyblock->enctype); ptr += 4;
*((uint32_t*) ptr) = htonl(key->keyblock->length); ptr += 4;
memcpy(ptr, key->keyblock->contents, key->keyblock->length);
ptr += key->keyblock->length;
}
#endif
return (ZERR_NONE);
}
Code_t
ZLoadSession(char *buffer, int len)
{
#ifdef HAVE_KRB5
struct _Z_SessionKey *key;
uint32_t num_keys, keylength;
krb5_enctype enctype;
int i;
#endif
Code_t ret;
uint16_t version, port;
if (len < 2) return (EINVAL);
version = ntohs(*((uint16_t *) buffer)); buffer += 2; len -= 2;
if (version != SESSION_VERSION)
return (EINVAL);
if (len < 2) return (EINVAL);
port = ntohs(*((uint16_t *) buffer)); buffer += 2; len -= 2;
if ((ret = ZOpenPort(&port)) != ZERR_NONE)
return ret;
#ifdef HAVE_KRB5
if (len < 4) return (EINVAL);
num_keys = ntohl(*((uint32_t *) buffer)); buffer += 4; len -= 4;
for (i = 0; i < num_keys; i++) {
key = (struct _Z_SessionKey *)malloc(sizeof(struct _Z_SessionKey));
if (!key)
return (ENOMEM);
if (len < 4) {
free(key);
return (EINVAL);
}
enctype = ntohl(*((uint32_t *) buffer)); buffer += 4; len -= 4;
if (len < 4) {
free(key);
return (EINVAL);
}
keylength = ntohl(*((uint32_t *) buffer)); buffer += 4; len -= 4;
if (len < keylength) {
free(key);
return (EINVAL);
}
ret = krb5_init_keyblock(Z_krb5_ctx, enctype, keylength, &key->keyblock);
if (ret) {
free(key);
return ret;
}
memcpy((char *)key->keyblock->contents, buffer, keylength);
buffer += keylength; len -= keylength;
/* Just set recent times. It means we might not be able to
retire the keys, but that's fine. */
key->send_time = time(NULL);
key->first_use = time(NULL);
/* Prepend to the key list. */
key->prev = NULL;
key->next = Z_keys_head;
if (Z_keys_head)
Z_keys_head->prev = key;
Z_keys_head = key;
if (!Z_keys_tail)
Z_keys_tail = key;
}
#endif
if (len)
return (EINVAL);
return (ZERR_NONE);
}