summaryrefslogtreecommitdiff
path: root/lib/ZDumpSession.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ZDumpSession.c')
-rw-r--r--lib/ZDumpSession.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/ZDumpSession.c b/lib/ZDumpSession.c
new file mode 100644
index 0000000..f4dfc76
--- /dev/null
+++ b/lib/ZDumpSession.c
@@ -0,0 +1,139 @@
+/* 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;
+ int i;
+#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;
+#endif
+ int i;
+ 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);
+}