X-Git-Url: https://git.distorted.org.uk/~mdw/udpkey/blobdiff_plain/4efa50917644cae61b131185efe245a19526d629..0057c20e40fd5e747d64b50fe96ca3d996916146:/udpkey.c diff --git a/udpkey.c b/udpkey.c index 9c23ee0..2715c65 100644 --- 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) {