/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/rcache/rc_dfl.c */
+/* lib/krb5/rcache/rc_dfl.c - default replay cache type */
/*
- * This file of the Kerberos V5 software is derived from public-domain code
- * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ * Copyright (C) 2019 by the Massachusetts Institute of Technology.
+ * All rights reserved.
*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
- * An implementation for the default replay cache type.
+ * The dfl rcache type is a wrapper around the file2 rcache type, selecting a
+ * filename and (on Unix-like systems) applying open() safety appropriate for
+ * using a shared temporary directory.
*/
+
#include "k5-int.h"
-#include "rc_base.h"
-#include "rc_dfl.h"
-#include "rc_io.h"
#include "rc-int.h"
-
-/*
- * If NOIOSTUFF is defined at compile time, dfl rcaches will be per-process.
- */
-
-/*
- Local stuff:
-
- static int hash(krb5_donot_replay *rep, int hsize)
- returns hash value of *rep, between 0 and hsize - 1
- HASHSIZE
- size of hash table (constant), can be preset
- static int cmp(krb5_donot_replay *old, krb5_donot_replay *new, krb5_deltat t)
- compare old and new; return CMP_REPLAY or CMP_HOHUM
- static int alive(krb5_context, krb5_donot_replay *new, krb5_deltat t)
- see if new is still alive; return CMP_EXPIRED or CMP_HOHUM
- CMP_MALLOC, CMP_EXPIRED, CMP_REPLAY, CMP_HOHUM
- return codes from cmp(), alive(), and store()
- struct dfl_data
- data stored in this cache type, namely "dfl"
- struct authlist
- multilinked list of reps
- static int rc_store(context, krb5_rcache id, krb5_donot_replay *rep)
- store rep in cache id; return CMP_REPLAY if replay, else CMP_MALLOC/CMP_HOHUM
-
-*/
-
-#ifndef HASHSIZE
-#define HASHSIZE 997 /* a convenient prime */
-#endif
-
-#ifndef EXCESSREPS
-#define EXCESSREPS 30
-#endif
-
-/*
- * The rcache will be automatically expunged when the number of
- * expired krb5_donot_replays encountered incidentally in searching
- * exceeds the number of live krb5_donot_replays by EXCESSREPS. With
- * the defaults here, a typical cache might build up some 10K of
- * expired krb5_donot_replays before an automatic expunge, with the
- * waste basically independent of the number of stores per minute.
- *
- * The rcache will also automatically be expunged when it encounters
- * more than EXCESSREPS expired entries when recovering a cache in
- * dfl_recover.
- */
-
-static unsigned int
-hash(krb5_donot_replay *rep, unsigned int hsize)
-{
- unsigned int h = rep->cusec + rep->ctime;
- h += *rep->server;
- h += *rep->client;
- return h % hsize;
-}
-
-#define CMP_MALLOC -3
-#define CMP_EXPIRED -2
-#define CMP_REPLAY -1
-#define CMP_HOHUM 0
-
-/*ARGSUSED*/
-static int
-cmp(krb5_donot_replay *old, krb5_donot_replay *new1, krb5_deltat t)
-{
- if ((old->cusec == new1->cusec) && /* most likely to distinguish */
- (old->ctime == new1->ctime) &&
- (strcmp(old->client, new1->client) == 0) &&
- (strcmp(old->server, new1->server) == 0)) { /* always true */
- /* If both records include message hashes, compare them as well. */
- if (old->msghash == NULL || new1->msghash == NULL ||
- strcmp(old->msghash, new1->msghash) == 0)
- return CMP_REPLAY;
- }
- return CMP_HOHUM;
-}
-
-static int
-alive(krb5_timestamp mytime, krb5_donot_replay *new1, krb5_deltat t)
-{
- if (mytime == 0)
- return CMP_HOHUM; /* who cares? */
- if (ts_after(mytime, ts_incr(new1->ctime, t)))
- return CMP_EXPIRED;
- return CMP_HOHUM;
-}
-
-struct dfl_data
-{
- char *name;
- krb5_deltat lifespan;
- unsigned int hsize;
- int numhits;
- int nummisses;
- struct authlist **h;
- struct authlist *a;
-#ifndef NOIOSTUFF
- krb5_rc_iostuff d;
+#ifdef _WIN32
+#include "../os/os-proto.h"
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
#endif
- char recovering;
-};
-
-struct authlist
-{
- krb5_donot_replay rep;
- struct authlist *na;
- struct authlist *nh;
-};
-
-/* of course, list is backwards from file */
-/* hash could be forwards since we have to search on match, but naaaah */
-
-static int
-rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep,
- krb5_timestamp now, krb5_boolean fromfile)
-{
- struct dfl_data *t = (struct dfl_data *)id->data;
- unsigned int rephash;
- struct authlist *ta;
-
- rephash = hash(rep, t->hsize);
- for (ta = t->h[rephash]; ta; ta = ta->nh) {
- switch(cmp(&ta->rep, rep, t->lifespan))
- {
- case CMP_REPLAY:
- if (fromfile) {
- /*
- * This is an expected collision between a hash
- * extension record and a normal-format record. Make
- * sure the message hash is included in the stored
- * record and carry on.
- */
- if (!ta->rep.msghash && rep->msghash) {
- if (!(ta->rep.msghash = strdup(rep->msghash)))
- return CMP_MALLOC;
- }
- return CMP_HOHUM;
- } else
- return CMP_REPLAY;
- case CMP_HOHUM:
- if (alive(now, &ta->rep, t->lifespan) == CMP_EXPIRED)
- t->nummisses++;
- else
- t->numhits++;
- break;
- default:
- ; /* wtf? */
- }
- }
+#ifdef _WIN32
- if (!(ta = (struct authlist *) malloc(sizeof(struct authlist))))
- return CMP_MALLOC;
- ta->rep = *rep;
- ta->rep.client = ta->rep.server = ta->rep.msghash = NULL;
- if (!(ta->rep.client = strdup(rep->client)))
- goto error;
- if (!(ta->rep.server = strdup(rep->server)))
- goto error;
- if (rep->msghash && !(ta->rep.msghash = strdup(rep->msghash)))
- goto error;
- ta->na = t->a; t->a = ta;
- ta->nh = t->h[rephash]; t->h[rephash] = ta;
- return CMP_HOHUM;
-error:
- if (ta->rep.client)
- free(ta->rep.client);
- if (ta->rep.server)
- free(ta->rep.server);
- if (ta->rep.msghash)
- free(ta->rep.msghash);
- free(ta);
- return CMP_MALLOC;
-}
-
-char * KRB5_CALLCONV
-krb5_rc_dfl_get_name(krb5_context context, krb5_rcache id)
-{
- return ((struct dfl_data *) (id->data))->name;
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_get_span(krb5_context context, krb5_rcache id,
- krb5_deltat *lifespan)
+static krb5_error_code
+open_file(krb5_context context, int *fd_out)
{
- struct dfl_data *t;
-
- k5_mutex_lock(&id->lock);
- t = (struct dfl_data *) id->data;
- *lifespan = t->lifespan;
- k5_mutex_unlock(&id->lock);
- return 0;
-}
+ krb5_error_code ret;
+ char *fname;
+ const char *dir;
-static krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_init_locked(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
-{
- struct dfl_data *t = (struct dfl_data *)id->data;
- krb5_error_code retval;
+ *fd_out = -1;
- t->lifespan = lifespan ? lifespan : context->clockskew;
- /* default to clockskew from the context */
-#ifndef NOIOSTUFF
- if ((retval = krb5_rc_io_creat(context, &t->d, &t->name))) {
- return retval;
- }
- if ((krb5_rc_io_write(context, &t->d,
- (krb5_pointer) &t->lifespan, sizeof(t->lifespan))
- || krb5_rc_io_sync(context, &t->d))) {
- return KRB5_RC_IO;
+ dir = getenv("KRB5RCACHEDIR");
+ if (dir != NULL) {
+ if (asprintf(&fname, "%s\\krb5.rcache2") < 0)
+ return ENOMEM;
+ } else {
+ ret = k5_expand_path_tokens(context, "%{LOCAL_APPDATA}\\krb5.rcache2",
+ &fname);
+ if (ret)
+ return ret;
}
-#endif
- return 0;
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_init(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
-{
- krb5_error_code retval;
- k5_mutex_lock(&id->lock);
- retval = krb5_rc_dfl_init_locked(context, id, lifespan);
- k5_mutex_unlock(&id->lock);
- return retval;
-}
-
-/* Called with the mutex already locked. */
-krb5_error_code
-krb5_rc_dfl_close_no_free(krb5_context context, krb5_rcache id)
-{
- struct dfl_data *t = (struct dfl_data *)id->data;
- struct authlist *q;
-
- free(t->h);
- if (t->name)
- free(t->name);
- while ((q = t->a))
- {
- t->a = q->na;
- free(q->rep.client);
- free(q->rep.server);
- if (q->rep.msghash)
- free(q->rep.msghash);
- free(q);
+ *fd_out = open(fname, O_CREAT | O_RDWR | O_BINARY, 0600);
+ ret = (*fd_out < 0) ? errno : 0;
+ if (ret) {
+ k5_setmsg(context, ret, "%s (filename: %s)",
+ error_message(ret), fname);
}
-#ifndef NOIOSTUFF
- (void) krb5_rc_io_close(context, &t->d);
-#endif
- free(t);
- return 0;
+ free(fname);
+ return ret;
}
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_close(krb5_context context, krb5_rcache id)
-{
- k5_mutex_lock(&id->lock);
- krb5_rc_dfl_close_no_free(context, id);
- k5_mutex_unlock(&id->lock);
- k5_mutex_destroy(&id->lock);
- free(id);
- return 0;
-}
+#else /* _WIN32 */
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_destroy(krb5_context context, krb5_rcache id)
-{
-#ifndef NOIOSTUFF
- if (krb5_rc_io_destroy(context, &((struct dfl_data *) (id->data))->d))
- return KRB5_RC_IO;
-#endif
- return krb5_rc_dfl_close(context, id);
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_resolve(krb5_context context, krb5_rcache id, char *name)
+static krb5_error_code
+open_file(krb5_context context, int *fd_out)
{
- struct dfl_data *t = 0;
- krb5_error_code retval;
-
- /* allocate id? no */
- if (!(t = (struct dfl_data *) calloc(1, sizeof(struct dfl_data))))
- return KRB5_RC_MALLOC;
- id->data = (krb5_pointer) t;
- if (name) {
- t->name = strdup(name);
- if (!t->name) {
- retval = KRB5_RC_MALLOC;
- goto cleanup;
- }
- } else
- t->name = 0;
- t->numhits = t->nummisses = 0;
- t->hsize = HASHSIZE; /* no need to store---it's memory-only */
- t->h = (struct authlist **) malloc(t->hsize*sizeof(struct authlist *));
- if (!t->h) {
- retval = KRB5_RC_MALLOC;
+ krb5_error_code ret;
+ int fd = -1;
+ char *fname = NULL;
+ const char *dir;
+ struct stat statbuf;
+ uid_t euid = geteuid();
+
+ *fd_out = -1;
+
+ dir = secure_getenv("KRB5RCACHEDIR");
+ if (dir == NULL) {
+ dir = secure_getenv("TMPDIR");
+ if (dir == NULL)
+ dir = RCTMPDIR;
+ }
+ if (asprintf(&fname, "%s/krb5_%lu.rcache2", dir, (unsigned long)euid) < 0)
+ return ENOMEM;
+
+ fd = open(fname, O_CREAT | O_RDWR | O_NOFOLLOW, 0600);
+ if (fd < 0) {
+ ret = errno;
+ k5_setmsg(context, ret, "%s (filename: %s)",
+ error_message(ret), fname);
goto cleanup;
}
- memset(t->h, 0, t->hsize*sizeof(struct authlist *));
- t->a = (struct authlist *) 0;
-#ifndef NOIOSTUFF
- t->d.fd = -1;
-#endif
- t->recovering = 0;
- return 0;
-
-cleanup:
- if (t) {
- if (t->name)
- free(t->name);
- if (t->h)
- free(t->h);
- free(t);
- }
- return retval;
-}
-
-void
-krb5_rc_free_entry(krb5_context context, krb5_donot_replay **rep)
-{
- krb5_donot_replay *rp = *rep;
- *rep = NULL;
- if (rp)
- {
- if (rp->client)
- free(rp->client);
- if (rp->server)
- free(rp->server);
- if (rp->msghash)
- free(rp->msghash);
- rp->client = NULL;
- rp->server = NULL;
- rp->msghash = NULL;
- free(rp);
+ if (fstat(fd, &statbuf) < 0 || statbuf.st_uid != euid) {
+ ret = EIO;
+ k5_setmsg(context, ret, "Replay cache file %s is not owned by uid %lu",
+ fname, (unsigned long)euid);
+ goto cleanup;
}
-}
-
-/*
- * Parse a string in the format <len>:<data>, with the length
- * represented in ASCII decimal. On parse failure, return 0 but set
- * *result to NULL.
- */
-static krb5_error_code
-parse_counted_string(char **strptr, char **result)
-{
- char *str = *strptr, *end;
- unsigned long len;
-
- *result = NULL;
- /* Parse the length, expecting a ':' afterwards. */
- errno = 0;
- len = strtoul(str, &end, 10);
- if (errno != 0 || *end != ':' || len > strlen(end + 1))
- return 0;
+ *fd_out = fd;
+ fd = -1;
+ ret = 0;
- /* Allocate space for *result and copy the data. */
- *result = malloc(len + 1);
- if (!*result)
- return KRB5_RC_MALLOC;
- memcpy(*result, end + 1, len);
- (*result)[len] = '\0';
- *strptr = end + 1 + len;
- return 0;
+cleanup:
+ if (fd != -1)
+ close(fd);
+ free(fname);
+ return ret;
}
-/*
- * Hash extension records have the format:
- * client = <empty string>
- * server = SHA256:<msghash> <clientlen>:<client> <serverlen>:<server>
- * Spaces in the client and server string are represented with
- * with backslashes. Client and server lengths are represented in
- * ASCII decimal (which is different from the 32-bit binary we use
- * elsewhere in the replay cache).
- *
- * On parse failure, we leave the record unmodified.
- */
-static krb5_error_code
-check_hash_extension(krb5_donot_replay *rep)
-{
- char *msghash = NULL, *client = NULL, *server = NULL, *str, *end;
- krb5_error_code retval = 0;
-
- /* Check if this appears to match the hash extension format. */
- if (*rep->client)
- return 0;
- if (strncmp(rep->server, "SHA256:", 7) != 0)
- return 0;
-
- /* Parse out the message hash. */
- str = rep->server + 7;
- end = strchr(str, ' ');
- if (!end)
- return 0;
- msghash = k5memdup0(str, end - str, &retval);
- if (!msghash)
- return KRB5_RC_MALLOC;
- str = end + 1;
-
- /* Parse out the client and server. */
- retval = parse_counted_string(&str, &client);
- if (retval != 0 || client == NULL)
- goto error;
- if (*str != ' ')
- goto error;
- str++;
- retval = parse_counted_string(&str, &server);
- if (retval != 0 || server == NULL)
- goto error;
- if (*str)
- goto error;
-
- free(rep->client);
- free(rep->server);
- rep->client = client;
- rep->server = server;
- rep->msghash = msghash;
- return 0;
-
-error:
- if (msghash)
- free(msghash);
- if (client)
- free(client);
- if (server)
- free(server);
- return retval;
-}
+#endif /* not _WIN32 */
static krb5_error_code
-krb5_rc_io_fetch(krb5_context context, struct dfl_data *t,
- krb5_donot_replay *rep, int maxlen)
+dfl_resolve(krb5_context context, const char *residual, void **rcdata_out)
{
- int len2;
- unsigned int len;
- krb5_error_code retval;
-
- rep->client = rep->server = rep->msghash = NULL;
-
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len2,
- sizeof(len2));
- if (retval)
- return retval;
-
- if ((len2 <= 0) || (len2 >= maxlen))
- return KRB5_RC_IO_EOF;
-
- len = len2;
- rep->client = malloc (len);
- if (!rep->client)
- return KRB5_RC_MALLOC;
-
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) rep->client, len);
- if (retval)
- goto errout;
-
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len2,
- sizeof(len2));
- if (retval)
- goto errout;
-
- if ((len2 <= 0) || (len2 >= maxlen)) {
- retval = KRB5_RC_IO_EOF;
- goto errout;
- }
- len = len2;
-
- rep->server = malloc (len);
- if (!rep->server) {
- retval = KRB5_RC_MALLOC;
- goto errout;
- }
-
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) rep->server, len);
- if (retval)
- goto errout;
-
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &rep->cusec,
- sizeof(rep->cusec));
- if (retval)
- goto errout;
-
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &rep->ctime,
- sizeof(rep->ctime));
- if (retval)
- goto errout;
-
- retval = check_hash_extension(rep);
- if (retval)
- goto errout;
-
+ *rcdata_out = NULL;
return 0;
-
-errout:
- if (rep->client)
- free(rep->client);
- if (rep->server)
- free(rep->server);
- if (rep->msghash)
- free(rep->msghash);
- rep->client = rep->server = rep->msghash = NULL;
- return retval;
-}
-
-
-static krb5_error_code
-krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id);
-
-static krb5_error_code
-krb5_rc_dfl_recover_locked(krb5_context context, krb5_rcache id)
-{
-#ifdef NOIOSTUFF
- return KRB5_RC_NOIO;
-#else
-
- struct dfl_data *t = (struct dfl_data *)id->data;
- krb5_donot_replay *rep = 0;
- krb5_error_code retval;
- long max_size;
- int expired_entries = 0;
- krb5_timestamp now;
-
- if ((retval = krb5_rc_io_open(context, &t->d, t->name))) {
- return retval;
- }
-
- t->recovering = 1;
-
- max_size = krb5_rc_io_size(context, &t->d);
-
- rep = NULL;
- if (krb5_rc_io_read(context, &t->d, (krb5_pointer) &t->lifespan,
- sizeof(t->lifespan))) {
- retval = KRB5_RC_IO;
- goto io_fail;
- }
-
- if (!(rep = (krb5_donot_replay *) malloc(sizeof(krb5_donot_replay)))) {
- retval = KRB5_RC_MALLOC;
- goto io_fail;
- }
- rep->client = rep->server = rep->msghash = NULL;
-
- if (krb5_timeofday(context, &now))
- now = 0;
-
- /* now read in each auth_replay and insert into table */
- for (;;) {
- if (krb5_rc_io_mark(context, &t->d)) {
- retval = KRB5_RC_IO;
- goto io_fail;
- }
-
- retval = krb5_rc_io_fetch(context, t, rep, (int) max_size);
-
- if (retval == KRB5_RC_IO_EOF)
- break;
- else if (retval != 0)
- goto io_fail;
-
- if (alive(now, rep, t->lifespan) != CMP_EXPIRED) {
- if (rc_store(context, id, rep, now, TRUE) == CMP_MALLOC) {
- retval = KRB5_RC_MALLOC; goto io_fail;
- }
- } else {
- expired_entries++;
- }
-
- /*
- * free fields allocated by rc_io_fetch
- */
- free(rep->server);
- free(rep->client);
- if (rep->msghash)
- free(rep->msghash);
- rep->client = rep->server = rep->msghash = NULL;
- }
- retval = 0;
- krb5_rc_io_unmark(context, &t->d);
- /*
- * An automatic expunge here could remove the need for
- * mark/unmark but that would be inefficient.
- */
-io_fail:
- krb5_rc_free_entry(context, &rep);
- if (retval)
- krb5_rc_io_close(context, &t->d);
- else if (expired_entries > EXCESSREPS)
- retval = krb5_rc_dfl_expunge_locked(context, id);
- t->recovering = 0;
- return retval;
-
-#endif
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_recover(krb5_context context, krb5_rcache id)
-{
- krb5_error_code ret;
-
- k5_mutex_lock(&id->lock);
- ret = krb5_rc_dfl_recover_locked(context, id);
- k5_mutex_unlock(&id->lock);
- return ret;
}
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_recover_or_init(krb5_context context, krb5_rcache id,
- krb5_deltat lifespan)
+static void
+dfl_close(krb5_context context, void *rcdata)
{
- krb5_error_code retval;
-
- k5_mutex_lock(&id->lock);
- retval = krb5_rc_dfl_recover_locked(context, id);
- if (retval)
- retval = krb5_rc_dfl_init_locked(context, id, lifespan);
- k5_mutex_unlock(&id->lock);
- return retval;
}
static krb5_error_code
-krb5_rc_io_store(krb5_context context, struct dfl_data *t,
- krb5_donot_replay *rep)
-{
- size_t clientlen, serverlen;
- unsigned int len;
- krb5_error_code ret;
- struct k5buf buf, extbuf;
- char *extstr;
-
- clientlen = strlen(rep->client);
- serverlen = strlen(rep->server);
-
- if (rep->msghash) {
- /*
- * Write a hash extension record, to be followed by a record
- * in regular format (without the message hash) for the
- * benefit of old implementations.
- */
-
- /* Format the extension value so we know its length. */
- k5_buf_init_dynamic(&extbuf);
- k5_buf_add_fmt(&extbuf, "SHA256:%s %lu:%s %lu:%s", rep->msghash,
- (unsigned long)clientlen, rep->client,
- (unsigned long)serverlen, rep->server);
- if (k5_buf_status(&extbuf) != 0)
- return KRB5_RC_MALLOC;
- extstr = extbuf.data;
-
- /*
- * Put the extension value into the server field of a
- * regular-format record, with an empty client field.
- */
- k5_buf_init_dynamic(&buf);
- len = 1;
- k5_buf_add_len(&buf, (char *)&len, sizeof(len));
- k5_buf_add_len(&buf, "", 1);
- len = strlen(extstr) + 1;
- k5_buf_add_len(&buf, (char *)&len, sizeof(len));
- k5_buf_add_len(&buf, extstr, len);
- k5_buf_add_len(&buf, (char *)&rep->cusec, sizeof(rep->cusec));
- k5_buf_add_len(&buf, (char *)&rep->ctime, sizeof(rep->ctime));
- free(extstr);
- } else /* No extension record needed. */
- k5_buf_init_dynamic(&buf);
-
- len = clientlen + 1;
- k5_buf_add_len(&buf, (char *)&len, sizeof(len));
- k5_buf_add_len(&buf, rep->client, len);
- len = serverlen + 1;
- k5_buf_add_len(&buf, (char *)&len, sizeof(len));
- k5_buf_add_len(&buf, rep->server, len);
- k5_buf_add_len(&buf, (char *)&rep->cusec, sizeof(rep->cusec));
- k5_buf_add_len(&buf, (char *)&rep->ctime, sizeof(rep->ctime));
-
- if (k5_buf_status(&buf) != 0)
- return KRB5_RC_MALLOC;
-
- ret = krb5_rc_io_write(context, &t->d, buf.data, buf.len);
- k5_buf_free(&buf);
- return ret;
-}
-
-static krb5_error_code krb5_rc_dfl_expunge_locked(krb5_context, krb5_rcache);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep)
+dfl_store(krb5_context context, void *rcdata, const krb5_data *tag)
{
krb5_error_code ret;
- struct dfl_data *t;
- krb5_timestamp now;
+ int fd;
- ret = krb5_timeofday(context, &now);
+ ret = open_file(context, &fd);
if (ret)
return ret;
- k5_mutex_lock(&id->lock);
-
- switch(rc_store(context, id, rep, now, FALSE)) {
- case CMP_MALLOC:
- k5_mutex_unlock(&id->lock);
- return KRB5_RC_MALLOC;
- case CMP_REPLAY:
- k5_mutex_unlock(&id->lock);
- return KRB5KRB_AP_ERR_REPEAT;
- case 0: break;
- default: /* wtf? */ ;
- }
- t = (struct dfl_data *)id->data;
-#ifndef NOIOSTUFF
- ret = krb5_rc_io_store(context, t, rep);
- if (ret) {
- k5_mutex_unlock(&id->lock);
- return ret;
- }
-#endif
- /* Shall we automatically expunge? */
- if (t->nummisses > t->numhits + EXCESSREPS)
- {
- ret = krb5_rc_dfl_expunge_locked(context, id);
- k5_mutex_unlock(&id->lock);
- return ret;
- }
-#ifndef NOIOSTUFF
- else
- {
- if (krb5_rc_io_sync(context, &t->d)) {
- k5_mutex_unlock(&id->lock);
- return KRB5_RC_IO;
- }
- }
-#endif
- k5_mutex_unlock(&id->lock);
- return 0;
-}
-
-static krb5_error_code
-krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
-{
- struct dfl_data *t = (struct dfl_data *)id->data;
-#ifdef NOIOSTUFF
- unsigned int i;
- struct authlist **q;
- struct authlist **qt;
- struct authlist *r;
- struct authlist *rt;
- krb5_timestamp now;
-
- if (krb5_timestamp(context, &now))
- now = 0;
-
- for (q = &t->a; *q; q = qt) {
- qt = &(*q)->na;
- if (alive(now, &(*q)->rep, t->lifespan) == CMP_EXPIRED) {
- free((*q)->rep.client);
- free((*q)->rep.server);
- if ((*q)->rep.msghash)
- free((*q)->rep.msghash);
- free(*q);
- *q = *qt; /* why doesn't this feel right? */
- }
- }
- for (i = 0; i < t->hsize; i++)
- t->h[i] = (struct authlist *) 0;
- for (r = t->a; r; r = r->na) {
- i = hash(&r->rep, t->hsize);
- rt = t->h[i];
- t->h[i] = r;
- r->nh = rt;
- }
- return 0;
-#else
- struct authlist *q;
- char *name;
- krb5_error_code retval = 0;
- krb5_rcache tmp;
- krb5_deltat lifespan = t->lifespan; /* save original lifespan */
-
- if (! t->recovering) {
- name = t->name;
- t->name = 0; /* Clear name so it isn't freed */
- (void) krb5_rc_dfl_close_no_free(context, id);
- retval = krb5_rc_dfl_resolve(context, id, name);
- free(name);
- if (retval)
- return retval;
- retval = krb5_rc_dfl_recover_locked(context, id);
- if (retval)
- return retval;
- t = (struct dfl_data *)id->data; /* point to recovered cache */
- }
-
- retval = krb5_rc_resolve_type(context, &tmp, "dfl");
- if (retval)
- return retval;
- retval = krb5_rc_resolve(context, tmp, 0);
- if (retval)
- goto cleanup;
- retval = krb5_rc_initialize(context, tmp, lifespan);
- if (retval)
- goto cleanup;
- for (q = t->a; q; q = q->na) {
- if (krb5_rc_io_store(context, (struct dfl_data *)tmp->data, &q->rep)) {
- retval = KRB5_RC_IO;
- goto cleanup;
- }
- }
- /* NOTE: We set retval in case we have an error */
- retval = KRB5_RC_IO;
- if (krb5_rc_io_sync(context, &((struct dfl_data *)tmp->data)->d))
- goto cleanup;
- if (krb5_rc_io_sync(context, &t->d))
- goto cleanup;
- if (krb5_rc_io_move(context, &t->d, &((struct dfl_data *)tmp->data)->d))
- goto cleanup;
- retval = 0;
-cleanup:
- (void) krb5_rc_dfl_close(context, tmp);
- return retval;
-#endif
+ ret = k5_rcfile2_store(context, fd, tag);
+ close(fd);
+ return ret;
}
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_expunge(krb5_context context, krb5_rcache id)
+const krb5_rc_ops k5_rc_dfl_ops =
{
- krb5_error_code ret;
-
- k5_mutex_lock(&id->lock);
- ret = krb5_rc_dfl_expunge_locked(context, id);
- k5_mutex_unlock(&id->lock);
- return ret;
-}
+ "dfl",
+ dfl_resolve,
+ dfl_close,
+ dfl_store
+};