1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
/* 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: 01c4444c7593a09e6568a3b2849858571c822bc5 $
*
* 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: 01c4444c7593a09e6568a3b2849858571c822bc5 $";
#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);
}
|