[723] in Kerberos-V5-bugs
Followup on: KDC lookaside buffer can return incorrect results
daemon@ATHENA.MIT.EDU (Jonathan I. Kamens)
Thu Sep 8 15:31:46 1994
Date: Thu, 8 Sep 1994 15:32:54 -0400
From: "Jonathan I. Kamens" <jik@cam.ov.com>
To: krb5-bugs@MIT.EDU
On August 12, I sent a message to krb5-bugs explaining how in certain
circumstances, the lookaside buffer can return incorrect results, and
suggesting that it be disabled until a better fix for the problem can
be devised.
We disabled the lookaside buffer in the KDC we're running here, and as
a result, we discovered that disabling it causes other problems. In
particular, it causes the KDC to more frequently log "Request is a
replay while processing request" and send error packets back to
clients making TGS requests.
This seems to occur when krb5_sendto_kdc sends a message to the
server, which receives the message and sends a response, which gets
lost between the server and the client. The client then resends the
same message, which the server decides is a replay and rejects.
Before, when the lookaside buffer was enabled, the rejection occurred
less frequently, because the repeat request often came in less than a
second (server time) after the initial request, which means that it
was accepted by the lookaside buffer as a reply and retransmitted.
The fix is to actually implement the long-term fix I proposed in my
last message -- instead of disabling the lookaside buffer, fix it to
notice DB changes and not accept replays whose original requests came
in before the database was modified. The diff below (against beta 2)
accomplishes this.
Please let me know if you have any comments about this.
Jonathan Kamens | OpenVision Technologies, Inc. | jik@cam.ov.com
--- replay.c 1993/09/20 20:27:38 1.1
+++ replay.c 1994/09/08 19:25:41
@@ -41,6 +41,7 @@
struct _krb5_kdc_replay_ent *next;
int num_hits;
krb5_int32 timein;
+ time_t db_age;
krb5_data *req_packet;
krb5_data *reply_packet;
} krb5_kdc_replay_ent;
@@ -53,10 +54,12 @@
static int num_entries = 0;
#define STALE_TIME 2*60 /* two minutes */
-#define STALE(ptr) (abs((ptr)->timein - timenow) >= STALE_TIME)
+#define STALE(ptr) ((abs((ptr)->timein - timenow) >= STALE_TIME) || \
+ ((ptr)->db_age != db_age))
#define MATCH(ptr) (((ptr)->req_packet->length == inpkt->length) && \
- !memcmp((ptr)->req_packet->data, inpkt->data, inpkt->length))
+ !memcmp((ptr)->req_packet->data, inpkt->data, inpkt->length) && \
+ ((ptr)->db_age == db_age))
/* XXX
Todo: quench the size of the queue...
@@ -72,10 +75,18 @@
{
krb5_int32 timenow;
register krb5_kdc_replay_ent *eptr, *last, *hold;
+ time_t db_age;
- if (krb5_timeofday(&timenow))
+ /*
+ * We could modify the MATCH and STALE macros above to only call
+ * krb5_db_get_age when it's actually needed, but it's going to be
+ * needed in most calls to this function, so it's not worth the
+ * effort, especially since it would make the code more
+ * complicated.
+ */
+ if (krb5_timeofday(&timenow) || krb5_db_get_age(0, &db_age))
return FALSE;
-
+
calls++;
/* search for a replay entry in the queue, possibly removing
@@ -124,8 +135,9 @@
{
register krb5_kdc_replay_ent *eptr;
krb5_int32 timenow;
+ time_t db_age;
- if (krb5_timeofday(&timenow))
+ if (krb5_timeofday(&timenow) || krb5_db_get_age(0, &db_age))
return;
/* this is a new entry */
@@ -133,6 +145,7 @@
if (!eptr)
return;
eptr->timein = timenow;
+ eptr->db_age = db_age;
if (krb5_copy_data(inpkt, &eptr->req_packet)) {
xfree(eptr);
return;