udpkey.c: Secret handling machinery.
[udpkey] / udpkey.c
index 9c23ee0..2715c65 100644 (file)
--- a/udpkey.c
+++ b/udpkey.c
@@ -497,6 +497,71 @@ static void debug_ge(const char *what, group *g, ge *X)
 
 static time_t now;
 
+/* Secrets table.
+ *
+ * The server doesn't want to maintain state for each client.  Instead, we
+ * generate a global secret, and derive per-client secrets from it.  A secret
+ * needs to have an expiry time (at which point we won't use it for new
+ * requests) and a deletion time (at which point we just forget that it ever
+ * existed).  This lets us roll over to a new secret without leaving existing
+ * clients completely in the lurch.
+ *
+ * Secrets are kept in a linked list, ordered by expiry time.  At any given
+ * time there is at most one unexpired secret (because we only make a new one
+ * when the old one expires).
+ */
+
+struct secret {
+  struct secret *next;
+  uint32 seq;
+  time_t t_exp, t_del;
+  octet x[32];
+};
+static struct secret *secrets = 0, *live_secret = 0;
+static uint32 next_secret_seq = 0;
+#define T_SECEXP 30
+#define T_SECDEL 45
+
+static void kill_dead_secrets(void)
+{
+  struct secret *s = secrets, *ss;
+
+  for (s = secrets; s && s->t_del <= now; s = ss) {
+    ss = s->next;
+    DESTROY(s);
+  }
+  secrets = 0;
+  if (!s) live_secret = 0;
+}
+
+static struct secret *find_secret(uint32 seq)
+{
+  struct secret *s;
+
+  kill_dead_secrets();
+  for (s = secrets; s; s = s->next)
+    if (s->seq == seq) return (s);
+  return (0);
+}
+
+static struct secret *fresh_secret(void)
+{
+  struct secret *s;
+
+  if (live_secret && live_secret->t_exp > now) return (live_secret);
+  kill_dead_secrets();
+
+  s = CREATE(struct secret);
+  s->seq = next_secret_seq++;
+  s->next = 0;
+  rand_get(RAND_GLOBAL, s->x, sizeof(s->x));
+  s->t_exp = now + T_SECEXP; s->t_del = now + T_SECDEL;
+  if (live_secret) live_secret->next = s;
+  else secrets = s;
+  live_secret = s;
+  return (s);
+}
+
 static int fetch_key(const char *tag, struct sockaddr_in *sin,
                     key **ky, struct kinfo *k)
 {