krb5 commit: Use file2 replay cache by default

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/e8a35f6962ce2d048616fb7457bff2d90398ca48
commit e8a35f6962ce2d048616fb7457bff2d90398ca48
Author: Greg Hudson <[email protected]>
Date:   Wed May 15 01:01:34 2019 -0400

    Use file2 replay cache by default
    
    Remove the existing default replay cache implementation and replace it
    with a wrapper around the file2 replay cache code.  Change the
    filename to krb5_EUID.rcache2, ignoring the residual (and therefore
    the server principal name).  On Windows, use the local appdata
    directory if KRB5RCACHEDIR is not set in the environment.
    
    ticket: 8786

 doc/basic/rcache_def.rst        |   27 +-
 src/kadmin/testing/Makefile.in  |    2 +-
 src/lib/krb5/libkrb5.exports    |   23 -
 src/lib/krb5/rcache/Makefile.in |    6 -
 src/lib/krb5/rcache/README      |   82 ----
 src/lib/krb5/rcache/deps        |   40 +-
 src/lib/krb5/rcache/rc_dfl.c    |  927 ++++++---------------------------------
 src/lib/krb5/rcache/rc_dfl.h    |   48 --
 src/lib/krb5/rcache/rc_io.c     |  518 ----------------------
 src/lib/krb5/rcache/rc_io.h     |   60 ---
 src/lib/krb5/rcache/rcdef.c     |   45 --
 11 files changed, 179 insertions(+), 1599 deletions(-)

diff --git a/doc/basic/rcache_def.rst b/doc/basic/rcache_def.rst
index 56d369d..5e550fc 100644
--- a/doc/basic/rcache_def.rst
+++ b/doc/basic/rcache_def.rst
@@ -71,21 +71,30 @@ are in lowercase.  The following types are defined:
 
 #. **dfl** is the default type if no environment variable or
    configuration specifies a different type.  It stores replay data in
-   a file, occasionally rewriting it to purge old, expired entries.
+   a file2 replay cache with a filename based on the effective uid.
+   The residual value is ignored.
 
 The default type can be overridden by the **KRB5RCACHETYPE**
 environment variable.
 
-For the dfl type, the placement of the replay cache file is determined
-by the following:
+For the dfl type, the location of the replay cache file is determined
+as follows:
 
-#. The **KRB5RCACHEDIR** environment variable;
+#. The directory is taken from the **KRB5RCACHEDIR** environment
+   variable, or the **TMPDIR** environment variable, or a temporary
+   directory determined at configuration time such as ``/var/tmp``, in
+   descending order of preference.
 
-#. If KRB5RCACHEDIR is unspecified, on UNIX, the library
-   will fall back to the environment variable **TMPDIR**, and then to
-   a temporary directory determined at configuration time such as
-   */tmp* or */var/tmp*; on Windows, it will check the environment
-   variables *TEMP* and *TMP*, and fall back to the directory C:\\.
+#. The filename is ``krb5_EUID.rcache2`` where EUID is the effective
+   uid of the process.
+
+#. The file is opened without following symbolic links, and ownership
+   of the file is verified to match the effective uid.
+
+On Windows, the directory for the dfl type is the local appdata
+directory, unless overridden by the **KRB5RCACHEDIR** environment
+variable.  The filename on Windows is ``krb5.rcache2``, and the file
+is opened normally.
 
 Performance issues
 ------------------
diff --git a/src/kadmin/testing/Makefile.in b/src/kadmin/testing/Makefile.in
index e5bcc74..5b803cb 100644
--- a/src/kadmin/testing/Makefile.in
+++ b/src/kadmin/testing/Makefile.in
@@ -5,4 +5,4 @@ SUBDIRS = scripts util
 all:
 
 clean:
-	-$(RM) -r krb5-test-root admin_* init-* kadmin_* kdc_rcache.* ovsec-*
+	-$(RM) -r krb5-test-root admin_* init-* *.rcache2 ovsec-*
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 038e4de..1f22498 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -503,35 +503,12 @@ krb5_rc_default
 krb5_rc_default_name
 krb5_rc_default_type
 krb5_rc_destroy
-krb5_rc_dfl_close
-krb5_rc_dfl_close_no_free
-krb5_rc_dfl_destroy
-krb5_rc_dfl_expunge
-krb5_rc_dfl_get_name
-krb5_rc_dfl_get_span
-krb5_rc_dfl_init
-krb5_rc_dfl_ops
-krb5_rc_dfl_recover
-krb5_rc_dfl_resolve
-krb5_rc_dfl_store
 krb5_rc_expunge
-krb5_rc_free_entry
 krb5_rc_get_lifespan
 krb5_rc_get_name
 krb5_rc_get_type
 krb5_rc_hash_message
 krb5_rc_initialize
-krb5_rc_io_close
-krb5_rc_io_creat
-krb5_rc_io_destroy
-krb5_rc_io_mark
-krb5_rc_io_move
-krb5_rc_io_open
-krb5_rc_io_read
-krb5_rc_io_size
-krb5_rc_io_sync
-krb5_rc_io_unmark
-krb5_rc_io_write
 krb5_rc_recover
 krb5_rc_recover_or_initialize
 krb5_rc_register_type
diff --git a/src/lib/krb5/rcache/Makefile.in b/src/lib/krb5/rcache/Makefile.in
index 0513937..441a6ca 100644
--- a/src/lib/krb5/rcache/Makefile.in
+++ b/src/lib/krb5/rcache/Makefile.in
@@ -10,8 +10,6 @@ STLIBOBJS = \
 	rc_base.o	\
 	rc_dfl.o 	\
 	rc_file2.o	\
-	rc_io.o		\
-	rcdef.o		\
 	rc_none.o	\
 	rc_conv.o	\
 	ser_rc.o	\
@@ -22,8 +20,6 @@ OBJS=	\
 	$(OUTPRE)rc_base.$(OBJEXT)	\
 	$(OUTPRE)rc_dfl.$(OBJEXT) 	\
 	$(OUTPRE)rc_file2.$(OBJEXT) 	\
-	$(OUTPRE)rc_io.$(OBJEXT)	\
-	$(OUTPRE)rcdef.$(OBJEXT)	\
 	$(OUTPRE)rc_none.$(OBJEXT)	\
 	$(OUTPRE)rc_conv.$(OBJEXT)	\
 	$(OUTPRE)ser_rc.$(OBJEXT)	\
@@ -34,8 +30,6 @@ SRCS=	\
 	$(srcdir)/rc_base.c	\
 	$(srcdir)/rc_dfl.c 	\
 	$(srcdir)/rc_file2.c 	\
-	$(srcdir)/rc_io.c	\
-	$(srcdir)/rcdef.c	\
 	$(srcdir)/rc_none.c	\
 	$(srcdir)/rc_conv.c	\
 	$(srcdir)/ser_rc.c	\
diff --git a/src/lib/krb5/rcache/README b/src/lib/krb5/rcache/README
deleted file mode 100644
index 13a45a1..0000000
--- a/src/lib/krb5/rcache/README
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 1990, Daniel J. Bernstein. All rights reserved.
-
-Please address any questions or comments to the author at [email protected].
-*/
-
-The #include's should be rewritten.
-
-All functions return 0 on success.
-
-Environment variables: KRB5RCACHETYPE, KRB5RCACHENAME, KRB5RCACHEDIR,
-and TMPDIR. Obsolete: KRB5RCACHE.
-
-All header files are both ANSI-compatible and K&R-compatible. The .c files
-are only ANSI compatible. Everything passes gcc -Wall -ansi -pedantic.
-
-Strings are freed using FREE(), which is defined in terms of free(). 
-
-The error header files should be redone.
-
-The header files don't use __ because that's reserved.
-
-Each .c file assumes <malloc.h>. rc_io.c assumes fsync() and a gaggle of
-error codes. These assumptions are not as portable as the code itself.
-
-
-rcache.c:
-
-The rcache.c compatibility interface's type registration is a no-op; it
-simply passes the type name on to rc_base.h. rcache.h is obsolete; use
-rc_base.h if possible.
-
-There are some slight differences between rcache.c and the prototypes I
-saw in krb/func-proto.h. Don't look at me, it's your interface.
-
-rcache.c's get_name doesn't fill with zeros unless strncpy does.
-
-
-rc_base.c:
-
-It doesn't take linker magic to preregister types. Just change the
-typehead initialization in rc_base.c, with an appropriate include file
-setting the ops.
-
-
-rc_dfl.c:
-
-If NOIOSTUFF is defined when rc_dfl.c is compiled, all dfl rcaches will
-be per-process. This is untested.
-
-Provided that separate threads use separate rcaches, rc_dfl.c is safe
-for multithreading.
-
-Getting the name of a cache is only valid after it is created and before
-it is closed. Recovering a cache is only valid after it has been created.
-
-krb5_unparse_name had better produce a zero-terminated string.
-
-rc_dfl.c isn't smart enough to try expunge/retry upon a malloc error.
-Then again, such an error indicates that the whole system's about to die;
-without real memory management there's no good solution.
-
-HASHSIZE can be defined at compile time. It defaults to 997 in rc_dfl.c.
-EXCESSREPS can be defined at compile time. It defaults to 30 in rc_dfl.c.
-
-Hopefully adding a deltat to a time to compare to another time cannot
-overflow.
-
-In rc_dfl's struct dfl_data, the name field is never freed, even though
-it may be malloced by io_creat on a generate-name call. This should not
-be a problem: a single process should not be opening and closing many
-rcaches. One fix would be another field to indicate whether the string
-was malloced or not; normally this is an unstated characteristic of a
-char pointer, but here it would have to be explicit.
-
-
-rc_io.c:
-
-rc_io.c assumes that siginterrupt() is not set. If siginterrupt() is set
-and a signal occurs during, say, close(), then the close will fail.
-
-On a machine without fsync() you might as well not use the disk at all.
diff --git a/src/lib/krb5/rcache/deps b/src/lib/krb5/rcache/deps
index 445439a..a9ac7fd 100644
--- a/src/lib/krb5/rcache/deps
+++ b/src/lib/krb5/rcache/deps
@@ -26,37 +26,27 @@ rc_base.so rc_base.po $(OUTPRE)rc_base.$(OBJEXT): $(BUILDTOP)/include/autoconf.h
   rc_base.h
 rc_dfl.so rc_dfl.po $(OUTPRE)rc_dfl.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
   $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h rc-int.h rc_base.h \
-  rc_dfl.c rc_dfl.h rc_io.h
-rc_io.so rc_io.po $(OUTPRE)rc_io.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../os/os-proto.h \
+  $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
   $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h rc_base.h rc_dfl.h \
-  rc_io.c rc_io.h
-rcdef.so rcdef.po $(OUTPRE)rcdef.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+  $(top_srcdir)/include/socket-utils.h memrcache.h rc-int.h \
+  rc_dfl.c
+rc_file2.so rc_file2.po $(OUTPRE)rc_file2.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-hashtab.h \
   $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
   $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
   $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
   $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
   $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h rc-int.h rc_dfl.h \
-  rcdef.c
+  $(top_srcdir)/include/socket-utils.h rc-int.h rc_file2.c
 rc_none.so rc_none.po $(OUTPRE)rc_none.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
   $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
   $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
index 1e0cb22..d7ea476 100644
--- a/src/lib/krb5/rcache/rc_dfl.c
+++ b/src/lib/krb5/rcache/rc_dfl.c
@@ -1,850 +1,213 @@
 /* -*- 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, <[email protected]>.
+ * 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
+#ifdef _WIN32
+#include "../os/os-proto.h"
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
 #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.
- */
+#ifdef _WIN32
 
-static unsigned int
-hash(krb5_donot_replay *rep, unsigned int hsize)
+static krb5_error_code
+open_file(krb5_context context, int *fd_out)
 {
-    unsigned int h = rep->cusec + rep->ctime;
-    h += *rep->server;
-    h += *rep->client;
-    return h % hsize;
-}
+    krb5_error_code ret;
+    char *fname;
+    const char *dir;
 
-#define CMP_MALLOC -3
-#define CMP_EXPIRED -2
-#define CMP_REPLAY -1
-#define CMP_HOHUM 0
+    *fd_out = -1;
 
-/*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;
+    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;
     }
-    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;
+    *fd_out = open(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);
+    }
+    free(fname);
+    return ret;
 }
 
-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;
-#endif
-    char recovering;
-};
-
-struct authlist
-{
-    krb5_donot_replay rep;
-    struct authlist *na;
-    struct authlist *nh;
-};
+#else /* _WIN32 */
 
-/* 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)
+static krb5_error_code
+open_file(krb5_context context, int *fd_out)
 {
-    struct dfl_data *t = (struct dfl_data *)id->data;
-    unsigned int rephash;
-    struct authlist *ta;
-
-    rephash = hash(rep, t->hsize);
+    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;
+    }
 
-    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? */
-        }
+    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;
     }
 
-    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;
-}
+    *fd_out = fd;
+    fd = -1;
+    ret = 0;
 
-char * KRB5_CALLCONV
-krb5_rc_dfl_get_name(krb5_context context, krb5_rcache id)
-{
-    return ((struct dfl_data *) (id->data))->name;
+cleanup:
+    if (fd != -1)
+        close(fd);
+    free(fname);
+    return ret;
 }
 
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_get_span(krb5_context context, krb5_rcache id,
-                     krb5_deltat *lifespan)
-{
-    struct dfl_data *t;
+#endif /* not _WIN32 */
 
-    k5_mutex_lock(&id->lock);
-    t = (struct dfl_data *) id->data;
-    *lifespan = t->lifespan;
-    k5_mutex_unlock(&id->lock);
-    return 0;
+static char * KRB5_CALLCONV
+dfl_get_name(krb5_context context, krb5_rcache rc)
+{
+    return "";
 }
 
 static krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_init_locked(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
+dfl_get_span(krb5_context context, krb5_rcache rc, krb5_deltat *lifespan)
 {
-    struct dfl_data *t = (struct dfl_data *)id->data;
-    krb5_error_code retval;
-
-    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;
-    }
-#endif
+    *lifespan = context->clockskew;
     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)
+static krb5_error_code KRB5_CALLCONV
+dfl_init(krb5_context context, krb5_rcache rc, krb5_deltat lifespan)
 {
-    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);
-    }
-#ifndef NOIOSTUFF
-    (void) krb5_rc_io_close(context, &t->d);
-#endif
-    free(t);
     return 0;
 }
 
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_close(krb5_context context, krb5_rcache id)
+static krb5_error_code KRB5_CALLCONV
+dfl_close(krb5_context context, krb5_rcache rc)
 {
-    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);
+    k5_mutex_destroy(&rc->lock);
+    free(rc);
     return 0;
 }
 
-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);
-}
+#define dfl_destroy dfl_close
 
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_resolve(krb5_context context, krb5_rcache id, char *name)
+static krb5_error_code KRB5_CALLCONV
+dfl_resolve(krb5_context context, krb5_rcache rc, char *name)
 {
-    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;
-        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);
-    }
 }
 
-/*
- * 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)
+static krb5_error_code KRB5_CALLCONV
+dfl_recover(krb5_context context, krb5_rcache rc)
 {
-    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;
-
-    /* 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;
 }
 
-/*
- * 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)
+static krb5_error_code KRB5_CALLCONV
+dfl_recover_or_init(krb5_context context, krb5_rcache rc, krb5_deltat lifespan)
 {
-    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;
 }
 
-static krb5_error_code
-krb5_rc_io_fetch(krb5_context context, struct dfl_data *t,
-                 krb5_donot_replay *rep, int maxlen)
-{
-    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;
-
-    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)
-{
-    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)
+static krb5_error_code KRB5_CALLCONV
+dfl_store(krb5_context context, krb5_rcache rc, krb5_donot_replay *rep)
 {
     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;
+    ret = k5_rcfile2_store(context, fd, rep);
+    close(fd);
+    return ret;
 }
 
-static krb5_error_code
-krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
+static krb5_error_code KRB5_CALLCONV
+dfl_expunge(krb5_context context, krb5_rcache rc)
 {
-    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
 }
 
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_expunge(krb5_context context, krb5_rcache id)
-{
-    krb5_error_code ret;
-
-    k5_mutex_lock(&id->lock);
-    ret = krb5_rc_dfl_expunge_locked(context, id);
-    k5_mutex_unlock(&id->lock);
-    return ret;
-}
+const krb5_rc_ops krb5_rc_dfl_ops =
+{
+    0,
+    "dfl",
+    dfl_init,
+    dfl_recover,
+    dfl_recover_or_init,
+    dfl_destroy,
+    dfl_close,
+    dfl_store,
+    dfl_expunge,
+    dfl_get_span,
+    dfl_get_name,
+    dfl_resolve
+};
diff --git a/src/lib/krb5/rcache/rc_dfl.h b/src/lib/krb5/rcache/rc_dfl.h
deleted file mode 100644
index ad036a2..0000000
--- a/src/lib/krb5/rcache/rc_dfl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/rcache/rc_dfl.h */
-/*
- * This file of the Kerberos V5 software is derived from public-domain code
- * contributed by Daniel J. Bernstein, <[email protected]>.
- *
- */
-
-/*
- * Declarations for the default replay cache implementation.
- */
-
-#ifndef KRB5_RC_DFL_H
-#define KRB5_RC_DFL_H
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_init(krb5_context, krb5_rcache, krb5_deltat);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_recover(krb5_context, krb5_rcache);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_recover_or_init(krb5_context, krb5_rcache, krb5_deltat);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_destroy(krb5_context, krb5_rcache);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_close(krb5_context, krb5_rcache);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_store(krb5_context, krb5_rcache, krb5_donot_replay *);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_expunge(krb5_context, krb5_rcache);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_get_span(krb5_context, krb5_rcache, krb5_deltat *);
-
-char * KRB5_CALLCONV
-krb5_rc_dfl_get_name(krb5_context, krb5_rcache);
-
-krb5_error_code KRB5_CALLCONV
-krb5_rc_dfl_resolve(krb5_context, krb5_rcache, char *);
-
-krb5_error_code krb5_rc_dfl_close_no_free(krb5_context, krb5_rcache);
-void krb5_rc_free_entry(krb5_context, krb5_donot_replay **);
-#endif
diff --git a/src/lib/krb5/rcache/rc_io.c b/src/lib/krb5/rcache/rc_io.c
deleted file mode 100644
index 1800460..0000000
--- a/src/lib/krb5/rcache/rc_io.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/rcache/rc_io.c */
-/*
- * This file of the Kerberos V5 software is derived from public-domain code
- * contributed by Daniel J. Bernstein, <[email protected]>.
- *
- */
-
-/*
- * I/O functions for the replay cache default implementation.
- */
-
-#if defined(_WIN32)
-#  define PATH_SEPARATOR "\\"
-#else
-#  define PATH_SEPARATOR "/"
-#endif
-
-#define KRB5_RC_VNO     0x0501          /* krb5, rcache v 1 */
-
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#include "k5-int.h"
-#include <stdio.h> /* for P_tmpdir */
-#include "rc_base.h"
-#include "rc_dfl.h"
-#include "rc_io.h"
-
-#ifndef O_BINARY
-#define O_BINARY    0
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-#if !defined(_WINSOCKAPI_)
-#include <netinet/in.h>
-#endif
-#else
-#error find some way to use net-byte-order file version numbers.
-#endif
-
-#define UNIQUE getpid() /* hopefully unique number */
-
-#define GETDIR (dir = getdir(), dirlen = strlen(dir) + sizeof(PATH_SEPARATOR) - 1)
-
-static char *
-getdir(void)
-{
-    char *dir;
-
-    if (!(dir = secure_getenv("KRB5RCACHEDIR"))) {
-#if defined(_WIN32)
-        if (!(dir = getenv("TEMP")))
-            if (!(dir = getenv("TMP")))
-                dir = "C:";
-#else
-        if (!(dir = secure_getenv("TMPDIR"))) {
-#ifdef RCTMPDIR
-            dir = RCTMPDIR;
-#else
-            dir = "/tmp";
-#endif
-        }
-#endif
-    }
-    return dir;
-}
-
-/*
- * Called from krb5_rc_io_creat(); calls mkstemp() and does some
- * sanity checking on the file modes in case some broken mkstemp()
- * implementation creates the file with overly permissive modes.  To
- * avoid race conditions, do not fchmod() a file for which mkstemp set
- * incorrect modes.
- */
-static krb5_error_code
-krb5_rc_io_mkstemp(krb5_context context, krb5_rc_iostuff *d, char *dir)
-{
-    krb5_error_code retval = 0;
-#if HAVE_SYS_STAT_H
-    struct stat stbuf;
-
-    memset(&stbuf, 0, sizeof(stbuf));
-#endif
-    if (asprintf(&d->fn, "%s%skrb5_RCXXXXXX",
-                 dir, PATH_SEPARATOR) < 0) {
-        d->fn = NULL;
-        return KRB5_RC_IO_MALLOC;
-    }
-    d->fd = mkstemp(d->fn);
-    if (d->fd == -1) {
-        /*
-         * This return value is deliberate because d->fd == -1 causes
-         * caller to go into errno interpretation code.
-         */
-        return 0;
-    }
-#if HAVE_SYS_STAT_H
-    /*
-     * Be paranoid and check that mkstemp made the file accessible
-     * only to the user.
-     */
-    retval = fstat(d->fd, &stbuf);
-    if (retval) {
-        k5_setmsg(context, retval,
-                  _("Cannot fstat replay cache file %s: %s"),
-                  d->fn, strerror(errno));
-        return KRB5_RC_IO_UNKNOWN;
-    }
-    if (stbuf.st_mode & 077) {
-        k5_setmsg(context, retval,
-                  _("Insecure mkstemp() file mode for replay cache file %s; "
-                    "try running this program with umask 077"), d->fn);
-        return KRB5_RC_IO_UNKNOWN;
-    }
-#endif
-    return 0;
-}
-
-static krb5_error_code
-rc_map_errno (krb5_context context, int e, const char *fn,
-              const char *operation)
-{
-    switch (e) {
-    case EFBIG:
-#ifdef EDQUOT
-    case EDQUOT:
-#endif
-    case ENOSPC:
-        return KRB5_RC_IO_SPACE;
-
-    case EIO:
-        return KRB5_RC_IO_IO;
-
-    case EPERM:
-    case EACCES:
-    case EROFS:
-    case EEXIST:
-        k5_setmsg(context, KRB5_RC_IO_PERM,
-                  _("Cannot %s replay cache file %s: %s"),
-                  operation, fn, strerror(e));
-        return KRB5_RC_IO_PERM;
-
-    default:
-        k5_setmsg(context, KRB5_RC_IO_UNKNOWN, _("Cannot %s replay cache: %s"),
-                  operation, strerror(e));
-        return KRB5_RC_IO_UNKNOWN;
-    }
-}
-
-
-krb5_error_code
-krb5_rc_io_creat(krb5_context context, krb5_rc_iostuff *d, char **fn)
-{
-    krb5_int16 rc_vno = htons(KRB5_RC_VNO);
-    krb5_error_code retval = 0;
-    int flags, do_not_unlink = 0;
-    char *dir;
-    size_t dirlen;
-
-    GETDIR;
-    if (fn && *fn) {
-        if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, *fn) < 0)
-            return KRB5_RC_IO_MALLOC;
-        d->fd = -1;
-        do {
-            if (unlink(d->fn) == -1 && errno != ENOENT)
-                break;
-            flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY;
-            d->fd = THREEPARAMOPEN(d->fn, flags, 0600);
-        } while (d->fd == -1 && errno == EEXIST);
-    } else {
-        retval = krb5_rc_io_mkstemp(context, d, dir);
-        if (retval)
-            goto cleanup;
-        if (d->fd != -1 && fn) {
-            *fn = strdup(d->fn + dirlen);
-            if (*fn == NULL) {
-                free(d->fn);
-                return KRB5_RC_IO_MALLOC;
-            }
-        }
-    }
-    if (d->fd == -1) {
-        retval = rc_map_errno(context, errno, d->fn, "create");
-        if (retval == KRB5_RC_IO_PERM)
-            do_not_unlink = 1;
-        goto cleanup;
-    }
-    set_cloexec_fd(d->fd);
-    retval = krb5_rc_io_write(context, d, (krb5_pointer)&rc_vno,
-                              sizeof(rc_vno));
-    if (retval)
-        goto cleanup;
-
-    retval = krb5_rc_io_sync(context, d);
-
-cleanup:
-    if (retval) {
-        if (d->fn) {
-            if (!do_not_unlink)
-                (void) unlink(d->fn);
-            free(d->fn);
-            d->fn = NULL;
-        }
-        if (d->fd != -1) {
-            (void) close(d->fd);
-        }
-    }
-    return retval;
-}
-
-static krb5_error_code
-krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
-                         char* full_pathname)
-{
-    krb5_int16 rc_vno;
-    krb5_error_code retval = 0;
-    int do_not_unlink = 1;
-#ifndef NO_USERID
-    struct stat sb1, sb2;
-#endif
-    char *dir;
-
-    dir = getdir();
-    if (full_pathname) {
-        if (!(d->fn = strdup(full_pathname)))
-            return KRB5_RC_IO_MALLOC;
-    } else {
-        if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, fn) < 0)
-            return KRB5_RC_IO_MALLOC;
-    }
-
-#ifdef NO_USERID
-    d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
-    if (d->fd == -1) {
-        retval = rc_map_errno(context, errno, d->fn, "open");
-        goto cleanup;
-    }
-#else
-    d->fd = -1;
-    retval = lstat(d->fn, &sb1);
-    if (retval != 0) {
-        retval = rc_map_errno(context, errno, d->fn, "lstat");
-        goto cleanup;
-    }
-    d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
-    if (d->fd < 0) {
-        retval = rc_map_errno(context, errno, d->fn, "open");
-        goto cleanup;
-    }
-    retval = fstat(d->fd, &sb2);
-    if (retval < 0) {
-        retval = rc_map_errno(context, errno, d->fn, "fstat");
-        goto cleanup;
-    }
-    /* check if someone was playing with symlinks */
-    if ((sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino)
-        || (sb1.st_mode & S_IFMT) != S_IFREG)
-    {
-        retval = KRB5_RC_IO_PERM;
-        k5_setmsg(context, retval, "rcache not a file %s", d->fn);
-        goto cleanup;
-    }
-    /* check that non other can read/write/execute the file */
-    if (sb1.st_mode & 077) {
-        k5_setmsg(context, retval,
-                  _("Insecure file mode for replay cache file %s"), d->fn);
-        return KRB5_RC_IO_UNKNOWN;
-    }
-    /* owned by me */
-    if (sb1.st_uid != geteuid()) {
-        retval = KRB5_RC_IO_PERM;
-        k5_setmsg(context, retval, _("rcache not owned by %d"),
-                  (int)geteuid());
-        goto cleanup;
-    }
-#endif
-    set_cloexec_fd(d->fd);
-
-    do_not_unlink = 0;
-    retval = krb5_rc_io_read(context, d, (krb5_pointer) &rc_vno,
-                             sizeof(rc_vno));
-    if (retval)
-        goto cleanup;
-
-    if (ntohs(rc_vno) != KRB5_RC_VNO)
-        retval = KRB5_RCACHE_BADVNO;
-
-cleanup:
-    if (retval) {
-        if (!do_not_unlink)
-            (void) unlink(d->fn);
-        free(d->fn);
-        d->fn = NULL;
-        if (d->fd >= 0)
-            (void) close(d->fd);
-    }
-    return retval;
-}
-
-krb5_error_code
-krb5_rc_io_open(krb5_context context, krb5_rc_iostuff *d, char *fn)
-{
-    return krb5_rc_io_open_internal(context, d, fn, NULL);
-}
-
-krb5_error_code
-krb5_rc_io_move(krb5_context context, krb5_rc_iostuff *new1,
-                krb5_rc_iostuff *old)
-{
-#if defined(_WIN32) || defined(__CYGWIN__)
-    char *new_fn = NULL;
-    char *old_fn = NULL;
-    off_t offset = 0;
-    krb5_error_code retval = 0;
-    /*
-     * Initial work around provided by Tom Sanfilippo to work around
-     * poor Windows emulation of POSIX functions.  Rename and dup has
-     * different semantics!
-     *
-     * Additional fixes and explanation provided by [email protected]:
-     *
-     * First, we save the offset of "old".  Then, we close and remove
-     * the "new" file so we can do the rename.  We also close "old" to
-     * make sure the rename succeeds (though that might not be
-     * necessary on some systems).
-     *
-     * Next, we do the rename.  If all goes well, we seek the "new"
-     * file to the position "old" was at.
-     *
-     * --- WARNING!!! ---
-     *
-     * Since "old" is now gone, we mourn its disappearance, but we
-     * cannot emulate that Unix behavior...  THIS BEHAVIOR IS
-     * DIFFERENT FROM UNIX.  However, it is ok because this function
-     * gets called such that "old" gets closed right afterwards.
-     */
-    offset = lseek(old->fd, 0, SEEK_CUR);
-
-    new_fn = new1->fn;
-    new1->fn = NULL;
-    close(new1->fd);
-    new1->fd = -1;
-
-    unlink(new_fn);
-
-    old_fn = old->fn;
-    old->fn = NULL;
-    close(old->fd);
-    old->fd = -1;
-
-    if (rename(old_fn, new_fn) == -1) { /* MUST be atomic! */
-        retval = KRB5_RC_IO_UNKNOWN;
-        goto cleanup;
-    }
-
-    retval = krb5_rc_io_open_internal(context, new1, 0, new_fn);
-    if (retval)
-        goto cleanup;
-
-    if (lseek(new1->fd, offset, SEEK_SET) == -1) {
-        retval = KRB5_RC_IO_UNKNOWN;
-        goto cleanup;
-    }
-
-cleanup:
-    free(new_fn);
-    free(old_fn);
-    return retval;
-#else
-    char *fn = NULL;
-    if (rename(old->fn, new1->fn) == -1) /* MUST be atomic! */
-        return KRB5_RC_IO_UNKNOWN;
-    fn = new1->fn;
-    new1->fn = NULL;            /* avoid clobbering */
-    (void) krb5_rc_io_close(context, new1);
-    new1->fn = fn;
-    new1->fd = dup(old->fd);
-    set_cloexec_fd(new1->fd);
-    return 0;
-#endif
-}
-
-krb5_error_code
-krb5_rc_io_write(krb5_context context, krb5_rc_iostuff *d, krb5_pointer buf,
-                 unsigned int num)
-{
-    if (write(d->fd, (char *) buf, num) == -1)
-        switch(errno)
-        {
-#ifdef EDQUOT
-        case EDQUOT:
-#endif
-        case EFBIG:
-        case ENOSPC:
-            k5_setmsg(context, KRB5_RC_IO_SPACE,
-                      _("Can't write to replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_SPACE;
-        case EIO:
-            k5_setmsg(context, KRB5_RC_IO_IO,
-                      _("Can't write to replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_IO;
-        case EBADF:
-        default:
-            k5_setmsg(context, KRB5_RC_IO_UNKNOWN,
-                      _("Can't write to replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_UNKNOWN;
-        }
-    return 0;
-}
-
-krb5_error_code
-krb5_rc_io_sync(krb5_context context, krb5_rc_iostuff *d)
-{
-#if defined(_WIN32)
-#ifndef fsync
-#define fsync _commit
-#endif
-#endif
-    if (fsync(d->fd) == -1) {
-        switch(errno)
-        {
-        case EBADF: return KRB5_RC_IO_UNKNOWN;
-        case EIO: return KRB5_RC_IO_IO;
-        default:
-            k5_setmsg(context, KRB5_RC_IO_UNKNOWN,
-                      _("Cannot sync replay cache file: %s"), strerror(errno));
-            return KRB5_RC_IO_UNKNOWN;
-        }
-    }
-    return 0;
-}
-
-krb5_error_code
-krb5_rc_io_read(krb5_context context, krb5_rc_iostuff *d, krb5_pointer buf,
-                unsigned int num)
-{
-    int count;
-    if ((count = read(d->fd, (char *) buf, num)) == -1)
-        switch(errno)
-        {
-        case EIO: return KRB5_RC_IO_IO;
-        case EBADF:
-        default:
-            k5_setmsg(context, KRB5_RC_IO_UNKNOWN,
-                      _("Can't read from replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_UNKNOWN;
-        }
-    if (count < 0 || (unsigned int)count != num)
-        return KRB5_RC_IO_EOF;
-    return 0;
-}
-
-krb5_error_code
-krb5_rc_io_close(krb5_context context, krb5_rc_iostuff *d)
-{
-    if (d->fn != NULL) {
-        free(d->fn);
-        d->fn = NULL;
-    }
-    if (d->fd != -1) {
-        if (close(d->fd) == -1) /* can't happen */
-            return KRB5_RC_IO_UNKNOWN;
-        d->fd = -1;
-    }
-    return 0;
-}
-
-krb5_error_code
-krb5_rc_io_destroy(krb5_context context, krb5_rc_iostuff *d)
-{
-    if (unlink(d->fn) == -1)
-        switch(errno)
-        {
-        case EIO:
-            k5_setmsg(context, KRB5_RC_IO_IO,
-                      _("Can't destroy replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_IO;
-        case EPERM:
-        case EBUSY:
-        case EROFS:
-            k5_setmsg(context, KRB5_RC_IO_PERM,
-                      _("Can't destroy replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_PERM;
-        case EBADF:
-        default:
-            k5_setmsg(context, KRB5_RC_IO_UNKNOWN,
-                      _("Can't destroy replay cache: %s"), strerror(errno));
-            return KRB5_RC_IO_UNKNOWN;
-        }
-    return 0;
-}
-
-krb5_error_code
-krb5_rc_io_mark(krb5_context context, krb5_rc_iostuff *d)
-{
-    d->mark = lseek(d->fd, (off_t) 0, SEEK_CUR); /* can't fail */
-    return 0;
-}
-
-krb5_error_code
-krb5_rc_io_unmark(krb5_context context, krb5_rc_iostuff *d)
-{
-    (void) lseek(d->fd, d->mark, SEEK_SET); /* if it fails, tough luck */
-    return 0;
-}
-
-long
-krb5_rc_io_size(krb5_context context, krb5_rc_iostuff *d)
-{
-    struct stat statb;
-
-    if (fstat(d->fd, &statb) == 0)
-        return statb.st_size;
-    else
-        return 0;
-}
diff --git a/src/lib/krb5/rcache/rc_io.h b/src/lib/krb5/rcache/rc_io.h
deleted file mode 100644
index f5ab239..0000000
--- a/src/lib/krb5/rcache/rc_io.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/rcache/rc_io.h */
-/*
- * This file of the Kerberos V5 software is derived from public-domain code
- * contributed by Daniel J. Bernstein, <[email protected]>.
- *
- */
-
-/*
- * Declarations for the I/O sub-package of the replay cache
- */
-
-#ifndef KRB5_RC_IO_H
-#define KRB5_RC_IO_H
-
-typedef struct krb5_rc_iostuff {
-    int fd;
-#ifdef MSDOS_FILESYSTEM
-    long mark;
-#else
-    off_t mark; /* on newer systems, should be pos_t */
-#endif
-    char *fn;
-} krb5_rc_iostuff;
-
-/* first argument is always iostuff for result file */
-
-krb5_error_code
-krb5_rc_io_creat(krb5_context, krb5_rc_iostuff *, char **);
-
-krb5_error_code
-krb5_rc_io_open(krb5_context, krb5_rc_iostuff *, char *);
-
-krb5_error_code
-krb5_rc_io_move(krb5_context, krb5_rc_iostuff *, krb5_rc_iostuff *);
-
-krb5_error_code
-krb5_rc_io_write(krb5_context, krb5_rc_iostuff *, krb5_pointer, unsigned int);
-
-krb5_error_code
-krb5_rc_io_read(krb5_context, krb5_rc_iostuff *, krb5_pointer, unsigned int);
-
-krb5_error_code
-krb5_rc_io_close(krb5_context, krb5_rc_iostuff *);
-
-krb5_error_code
-krb5_rc_io_destroy(krb5_context, krb5_rc_iostuff *);
-
-krb5_error_code
-krb5_rc_io_mark(krb5_context, krb5_rc_iostuff *);
-
-krb5_error_code
-krb5_rc_io_unmark(krb5_context, krb5_rc_iostuff *);
-
-krb5_error_code
-krb5_rc_io_sync(krb5_context, krb5_rc_iostuff *);
-
-long
-krb5_rc_io_size(krb5_context, krb5_rc_iostuff *);
-#endif
diff --git a/src/lib/krb5/rcache/rcdef.c b/src/lib/krb5/rcache/rcdef.c
deleted file mode 100644
index 01d166b..0000000
--- a/src/lib/krb5/rcache/rcdef.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/rcache/rcdef.c - Default replay cache operations vector */
-/*
- * Copyright 1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-int.h"
-#include "rc-int.h"
-#include "rc_dfl.h"
-
-const krb5_rc_ops krb5_rc_dfl_ops =
-{
-    0,
-    "dfl",
-    krb5_rc_dfl_init,
-    krb5_rc_dfl_recover,
-    krb5_rc_dfl_recover_or_init,
-    krb5_rc_dfl_destroy,
-    krb5_rc_dfl_close,
-    krb5_rc_dfl_store,
-    krb5_rc_dfl_expunge,
-    krb5_rc_dfl_get_span,
-    krb5_rc_dfl_get_name,
-    krb5_rc_dfl_resolve
-};
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.