From: Greg Hudson Date: Wed, 15 May 2019 05:01:34 +0000 (-0400) Subject: Use file2 replay cache by default X-Git-Tag: krb5-1.18-beta1~115 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e8a35f6962ce2d048616fb7457bff2d90398ca48;p=thirdparty%2Fkrb5.git 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 --- diff --git a/doc/basic/rcache_def.rst b/doc/basic/rcache_def.rst index 56d369d836..5e550fcc32 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 e5bcc74341..5b803cb239 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 038e4de4bb..1f2249841f 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 0513937b23..441a6cae99 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 13a45a1d86..0000000000 --- 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 brnstnd@acf10.nyu.edu. -*/ - -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 . 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 445439a797..a9ac7fdb31 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 1e0cb22c94..d7ea476061 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, . + * 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 +#include #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 :, 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 = - * server = SHA256: : : - * 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 ad036a207e..0000000000 --- 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, . - * - */ - -/* - * 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 1800460b2a..0000000000 --- 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, . - * - */ - -/* - * 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 -#endif -#include "k5-int.h" -#include /* 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 -#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 dalmeida@mit.edu: - * - * 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 f5ab239038..0000000000 --- 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, . - * - */ - -/* - * 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 01d166bec2..0000000000 --- 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 -};