summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar David Benjamin <davidben@mit.edu>2013-08-20 13:40:19 -0400
committerGravatar Karl Ramm <kcr@1ts.org>2013-09-28 14:20:40 -0400
commitf269734ef50e1a9aa22eb9f18125967ca772744b (patch)
treef8ec0ecea416fac1698484b16d73d55b0378ed46
parent50d60c3dc739be77574cbf80bc24d7fbd2ff41be (diff)
Create an alternate Z_AuthProc that saves keys
The start of proper session key management in libzephyr. A new Z_AuthProc is added which appends the key into a queue. ZSubscribeTo and ZSubscribeToSansDefaults are modified to use it. For now, it's extremely simple and makes no attempt to expire old keys.
-rw-r--r--h/internal.h14
-rw-r--r--lib/ZMkAuth.c67
-rw-r--r--lib/ZSubs.c15
-rw-r--r--lib/Zinternal.c2
4 files changed, 95 insertions, 3 deletions
diff --git a/h/internal.h b/h/internal.h
index f87c8a2..54c595c 100644
--- a/h/internal.h
+++ b/h/internal.h
@@ -32,6 +32,8 @@
#define HM_SVC_FALLBACK htons((unsigned short) 2104)
#define HM_SRV_SVC_FALLBACK htons((unsigned short) 2105)
+#define ZSUBAUTH (Z_MakeAuthenticationSaveKey)
+
#define ZAUTH_UNSET (-3) /* Internal to client library. */
#define Z_MAXFRAGS 500 /* Max number of packet fragments */
#define Z_MAXNOTICESIZE 400000 /* Max size of incoming notice */
@@ -81,6 +83,16 @@ extern int __Zephyr_server; /* 0 if normal client, 1 if server or zhm */
#ifdef HAVE_KRB5
extern krb5_context Z_krb5_ctx;
Code_t Z_krb5_lookup_cksumtype(krb5_enctype, krb5_cksumtype *);
+
+struct _Z_SessionKey {
+ struct _Z_SessionKey *next;
+ struct _Z_SessionKey *prev;
+ krb5_keyblock *keyblock;
+ time_t send_time;
+ time_t first_use;
+};
+
+extern struct _Z_SessionKey *Z_keys_head, *Z_keys_tail;
#endif
extern ZLocations_t *__locate_list;
@@ -133,6 +145,8 @@ Code_t Z_AsciiFormatRawHeader (ZNotice_t *, char *, int, int *, char **,
void Z_gettimeofday(struct _ZTimeval *ztv, struct timezone *tz);
+Code_t Z_MakeAuthenticationSaveKey(ZNotice_t*, char *,int, int*);
+
#ifdef HAVE_KRB5
int ZGetCreds(krb5_creds **creds_out);
int ZGetCredsRealm(krb5_creds **creds_out, char *realm);
diff --git a/lib/ZMkAuth.c b/lib/ZMkAuth.c
index f837a1e..7ca4457 100644
--- a/lib/ZMkAuth.c
+++ b/lib/ZMkAuth.c
@@ -98,6 +98,73 @@ ZMakeAuthentication(register ZNotice_t *notice,
#endif
}
+Code_t
+Z_MakeAuthenticationSaveKey(register ZNotice_t *notice,
+ char *buffer,
+ int buffer_len,
+ int *len)
+{
+#ifdef HAVE_KRB4
+ /* Key management not implemented for krb4. */
+ return ZMakeAuthentication(notice, buffer, buffer_len, len);
+#else
+ Code_t result;
+ krb5_creds *creds = NULL;
+ krb5_keyblock *keyblock;
+ struct _Z_SessionKey *savedkey;
+
+ /* Look up creds and checksum the notice. */
+ if ((result = ZGetCreds(&creds)))
+ return result;
+ if ((result = Z_MakeZcodeAuthentication(notice, buffer, buffer_len, len,
+ creds))) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return result;
+ }
+
+ /* Save the key. */
+ keyblock = Z_credskey(creds);
+
+ if (Z_keys_head &&
+ Z_keys_head->keyblock->enctype == keyblock->enctype &&
+ Z_keys_head->keyblock->length == keyblock->length &&
+ memcmp(Z_keys_head->keyblock->contents, keyblock->contents,
+ keyblock->length) == 0) {
+ /*
+ * Optimization: if the key hasn't changed, replace the current entry,
+ * rather than make a new one.
+ */
+ Z_keys_head->send_time = time(NULL);
+ Z_keys_head->first_use = 0;
+ } else {
+ savedkey = (struct _Z_SessionKey *)malloc(sizeof(struct _Z_SessionKey));
+ if (!savedkey) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return ENOMEM;
+ }
+
+ if ((result = krb5_copy_keyblock(Z_krb5_ctx, keyblock, &savedkey->keyblock))) {
+ free(savedkey);
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return result;
+ }
+ savedkey->send_time = time(NULL);
+ savedkey->first_use = 0;
+
+ savedkey->prev = NULL;
+ savedkey->next = Z_keys_head;
+ if (Z_keys_head)
+ Z_keys_head->prev = savedkey;
+ Z_keys_head = savedkey;
+ if (!Z_keys_tail)
+ Z_keys_tail = savedkey;
+ }
+
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return result;
+#endif
+}
+
/* only used by server? */
Code_t
ZMakeZcodeAuthentication(register ZNotice_t *notice,
diff --git a/lib/ZSubs.c b/lib/ZSubs.c
index 7c7949b..535f3f9 100644
--- a/lib/ZSubs.c
+++ b/lib/ZSubs.c
@@ -91,6 +91,7 @@ ZSubscriptions(register ZSubscription_t *sublist,
0xFF, so some bytes are encoded as two bytes. */
int size_avail = Z_MAXPKTLEN-Z_FRAGFUDGE-Z_FRAGFUDGE;
int size, start, numok;
+ Z_AuthProc cert_routine;
/* nitems = 0 means cancel all subscriptions; still need to allocate a */
/* array for one item so we can cancel, however. */
@@ -117,6 +118,14 @@ ZSubscriptions(register ZSubscription_t *sublist,
return(retval);
}
+ /* if a subscription request, we save the key */
+ if (strcmp(opcode, CLIENT_SUBSCRIBE) == 0 ||
+ strcmp(opcode, CLIENT_SUBSCRIBE_NODEFS) == 0) {
+ cert_routine = ZSUBAUTH;
+ } else {
+ cert_routine = ZAUTH;
+ }
+
/* compute amount of room left */
size_avail -= hdrlen;
size = size_avail;
@@ -138,7 +147,7 @@ ZSubscriptions(register ZSubscription_t *sublist,
numok = 0;
if (!nitems) {
/* there aren't really any, but we need to xmit anyway */
- retval = ZSrvSendList(&notice, list, 0, ZAUTH, send_routine);
+ retval = ZSrvSendList(&notice, list, 0, cert_routine, send_routine);
free((char *)list);
return(retval);
}
@@ -163,7 +172,7 @@ ZSubscriptions(register ZSubscription_t *sublist,
return(ZERR_FIELDLEN);
}
retval = ZSrvSendList(&notice, &list[start*3], numok * 3,
- ZAUTH, send_routine);
+ cert_routine, send_routine);
if (retval) {
free((char *)list);
return(retval);
@@ -172,7 +181,7 @@ ZSubscriptions(register ZSubscription_t *sublist,
}
if (numok)
retval = ZSrvSendList(&notice, &list[start*3], numok * 3,
- ZAUTH, send_routine);
+ cert_routine, send_routine);
free((char *)list);
return(retval);
}
diff --git a/lib/Zinternal.c b/lib/Zinternal.c
index 07cd342..ecee122 100644
--- a/lib/Zinternal.c
+++ b/lib/Zinternal.c
@@ -44,6 +44,8 @@ int Z_discarded_packets = 0;
#ifdef HAVE_KRB5
/* This context is used throughout */
krb5_context Z_krb5_ctx;
+/* A queue of all the currently active session keys. */
+struct _Z_SessionKey *Z_keys_head, *Z_keys_tail;
static const struct cksum_map_s {
krb5_enctype e;