From f269734ef50e1a9aa22eb9f18125967ca772744b Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 20 Aug 2013 13:40:19 -0400 Subject: 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. --- h/internal.h | 14 ++++++++++++ lib/ZMkAuth.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/ZSubs.c | 15 ++++++++++--- lib/Zinternal.c | 2 ++ 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(¬ice, list, 0, ZAUTH, send_routine); + retval = ZSrvSendList(¬ice, 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(¬ice, &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(¬ice, &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; -- cgit v1.2.3