45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk/*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * lib/krb5/rcache/rc_io.c
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * This file of the Kerberos V5 software is derived from public-domain code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk/*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * I/O functions for the replay cache default implementation.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk/*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if defined(_WIN32)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk# define PATH_SEPARATOR "\\"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#else
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk# define PATH_SEPARATOR "/"
ebb7ba5d39a1fc27566910c47e9749493f961e3fTony Nguyen#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#define KRB5_RC_VNO 0x0501 /* krb5, rcache v 1 */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if HAVE_SYS_STAT_H
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include <sys/stat.h>
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include "k5-int.h"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include <stdio.h> /* for P_tmpdir */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
ebb7ba5d39a1fc27566910c47e9749493f961e3fTony Nguyen /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include <locale.h>
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include <syslog.h>
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include "rc_base.h"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include "rc_dfl.h"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include "rc_io.h"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#ifndef O_BINARY
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#define O_BINARY 0
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#ifdef HAVE_NETINET_IN_H
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if !defined(_WINSOCKAPI_)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#include <netinet/in.h>
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#else
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#error find some way to use net-byte-order file version numbers.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#define UNIQUE getpid() /* hopefully unique number */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#define GETDIR (dir = getdir(), dirlen = strlen(dir) + sizeof(PATH_SEPARATOR) - 1)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkstatic char *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkgetdir(void)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk char *dir;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk/* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if 0
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!(dir = getenv("KRB5RCACHEDIR"))) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if defined(_WIN32)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!(dir = getenv("TEMP")))
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!(dir = getenv("TMP")))
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dir = "C:";
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#else
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!(dir = getenv("TMPDIR"))) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#ifdef RCTMPDIR
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dir = RCTMPDIR;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#else
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dir = "/tmp";
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
ebb7ba5d39a1fc27566910c47e9749493f961e3fTony Nguyen#endif
ebb7ba5d39a1fc27566910c47e9749493f961e3fTony Nguyen }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
ebb7ba5d39a1fc27566910c47e9749493f961e3fTony Nguyen if (geteuid() == 0)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dir = "/var/krb5/rcache/root";
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk else
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dir = "/var/krb5/rcache";
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return dir;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk}
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk/*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Called from krb5_rc_io_creat(); calls mkstemp() and does some
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * sanity checking on the file modes in case some broken mkstemp()
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * implementation creates the file with overly permissive modes. To
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * avoid race conditions, do not fchmod() a file for which mkstemp set
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * incorrect modes.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkstatic krb5_error_code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_rc_io_mkstemp(krb5_context context, krb5_rc_iostuff *d, char *dir)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_error_code retval = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if HAVE_SYS_STAT_H
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk struct stat stbuf;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk memset(&stbuf, 0, sizeof(stbuf));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (asprintf(&d->fn, "%s%skrb5_RCXXXXXX",
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dir, PATH_SEPARATOR) < 0) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fd = mkstemp(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fd == -1) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * This return value is deliberate because d->fd == -1 causes
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * caller to go into errno interpretation code.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if HAVE_SYS_STAT_H
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Be paranoid and check that mkstemp made the file accessible
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * only to the user.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = fstat(d->fd, &stbuf);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, retval,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "Cannot fstat replay cache file %s: %s"),
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fn, strerror(errno));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_UNKNOWN;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (stbuf.st_mode & 077) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, retval,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "Insecure mkstemp() file mode "
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "for replay cache file %s; "
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "try running this program "
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "with umask 077 "), d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_UNKNOWN;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk}
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if 0
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkstatic krb5_error_code rc_map_errno (int) __attribute__((cold));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkstatic krb5_error_code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkrc_map_errno (krb5_context context, int e, const char *fn,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk const char *operation)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk switch (e) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EFBIG:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#ifdef EDQUOT
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EDQUOT:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case ENOSPC:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_SPACE;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EIO:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_IO;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EPERM:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EACCES:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EROFS:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk case EEXIST:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, KRB5_RC_IO_PERM,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "Cannot %s replay cache file %s: %s"),
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk operation, fn, strerror(e));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_PERM;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk default:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "Cannot %s replay cache: %s"),
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk operation, strerror(e));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_UNKNOWN;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk}
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_error_code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_rc_io_creat(krb5_context context, krb5_rc_iostuff *d, char **fn)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_int16 rc_vno = htons(KRB5_RC_VNO);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_error_code retval = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk int do_not_unlink = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk char *dir;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk size_t dirlen;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk GETDIR;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (fn && *fn) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (*fn[0] == '/') {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if ((d->fn = strdup(*fn)) == NULL)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk } else {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, *fn) < 0)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk unlink(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fd = THREEPARAMOPEN(d->fn, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL |
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk O_BINARY, 0600);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk } else {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = krb5_rc_io_mkstemp(context, d, dir);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fd != -1 && fn) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *fn = strdup(d->fn + dirlen);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (*fn == NULL) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk free(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fd == -1) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = rc_map_errno(context, errno, d->fn, "create");
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval == KRB5_RC_IO_PERM)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk do_not_unlink = 1;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk set_cloexec_fd(d->fd);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = krb5_rc_io_write(context, d, (krb5_pointer)&rc_vno,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk sizeof(rc_vno));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = krb5_rc_io_sync(context, d);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkcleanup:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fn) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!do_not_unlink)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk (void) unlink(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk free(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
ebb7ba5d39a1fc27566910c47e9749493f961e3fTony Nguyen if (d->fd != -1) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk (void) close(d->fd);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return retval;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk}
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkstatic krb5_error_code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk char* full_pathname)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_int16 rc_vno;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_error_code retval = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk int do_not_unlink = 1;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#ifndef NO_USERID
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk struct stat sb1, sb2;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk char *dir;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk size_t dirlen;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk GETDIR;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (full_pathname) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!(d->fn = strdup(full_pathname)))
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk } else {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (fn[0] == '/') {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if ((d->fn = strdup(fn)) == NULL)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk } else {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, fn) < 0)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_MALLOC;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#ifdef NO_USERID
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fd == -1) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = rc_map_errno(context, errno, d->fn, "open");
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#else
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fd = -1;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = lstat(d->fn, &sb1);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval != 0) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = rc_map_errno(context, errno, d->fn, "lstat");
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fd < 0) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = rc_map_errno(context, errno, d->fn, "open");
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = fstat(d->fd, &sb2);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval < 0) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = rc_map_errno(context, errno, d->fn, "fstat");
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* check if someone was playing with symlinks */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if ((sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk || (sb1.st_mode & S_IFMT) != S_IFREG)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = KRB5_RC_IO_PERM;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk syslog(LOG_ERR, "Error, rcache %s is a not a file"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "and should be removed.", d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, retval,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "rcache not a file %s"), d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* check that non other can read/write/execute the file */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (sb1.st_mode & 077) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, retval, dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "Insecure file mode "
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "for replay cache file %s"), d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return KRB5_RC_IO_UNKNOWN;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* owned by me */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (sb1.st_uid != geteuid()) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = KRB5_RC_IO_PERM;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /* Solaris Kerberos */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_set_error_message(context, retval, dgettext(TEXT_DOMAIN,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk "rcache not owned by %d"),
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk (int)geteuid());
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#endif
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk set_cloexec_fd(d->fd);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk do_not_unlink = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = krb5_rc_io_read(context, d, (krb5_pointer) &rc_vno,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk sizeof(rc_vno));
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk goto cleanup;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (ntohs(rc_vno) != KRB5_RC_VNO)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk retval = KRB5_RCACHE_BADVNO;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkcleanup:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (retval) {
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (!do_not_unlink)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk (void) unlink(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk free(d->fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk d->fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk if (d->fd >= 0)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk (void) close(d->fd);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk }
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return retval;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk}
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_error_code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_rc_io_open(krb5_context context, krb5_rc_iostuff *d, char *fn)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk return krb5_rc_io_open_internal(context, d, fn, NULL);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk}
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_error_code
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpkkrb5_rc_io_move(krb5_context context, krb5_rc_iostuff *new1,
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_rc_iostuff *old)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk{
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk#if defined(_WIN32) || defined(__CYGWIN__)
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk char *new_fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk char *old_fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk off_t offset = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk krb5_error_code retval = 0;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk /*
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Initial work around provided by Tom Sanfilippo to work around
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * poor Windows emulation of POSIX functions. Rename and dup has
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * different semantics!
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Additional fixes and explanation provided by dalmeida@mit.edu:
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * First, we save the offset of "old". Then, we close and remove
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * the "new" file so we can do the rename. We also close "old" to
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * make sure the rename succeeds (though that might not be
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * necessary on some systems).
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Next, we do the rename. If all goes well, we seek the "new"
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * file to the position "old" was at.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * --- WARNING!!! ---
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk *
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * Since "old" is now gone, we mourn its disappearance, but we
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * cannot emulate that Unix behavior... THIS BEHAVIOR IS
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * DIFFERENT FROM UNIX. However, it is ok because this function
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk * gets called such that "old" gets closed right afterwards.
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk */
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk offset = lseek(old->fd, 0, SEEK_CUR);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk new_fn = new1->fn;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk new1->fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk close(new1->fd);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk new1->fd = -1;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk unlink(new_fn);
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk old_fn = old->fn;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk old->fn = NULL;
45916cd2fec6e79bca5dee0421bd39e3c2910d1ejpk 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:
/* Solaris Kerberos */
krb5_set_error_message (context, KRB5_RC_IO_SPACE,
dgettext(TEXT_DOMAIN,
"Can't write to replay cache %s: %s"),
d->fn, strerror(errno));
return KRB5_RC_IO_SPACE;
case EIO:
/* Solaris Kerberos */
krb5_set_error_message (context, KRB5_RC_IO_IO,
dgettext(TEXT_DOMAIN,
"Can't write to replay cache %s: %s"),
d->fn, strerror(errno));
return KRB5_RC_IO_IO;
case EBADF:
default:
/* Solaris Kerberos */
krb5_set_error_message (context, KRB5_RC_IO_UNKNOWN,
dgettext(TEXT_DOMAIN,
"Can't write to replay cache %s: %s"),
d->fn, 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:
/* Solaris Kerberos */
krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
dgettext(TEXT_DOMAIN,
"Cannot sync replay cache file %s: %s"),
d->fn, 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:
/* Solaris Kerberos */
krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
dgettext(TEXT_DOMAIN,
"Can't read from replay cache %s: %s"),
d->fn, 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:
/* Solaris Kerberos */
krb5_set_error_message(context, KRB5_RC_IO_IO,
dgettext(TEXT_DOMAIN,
"Can't destroy replay cache %s: %s"),
d->fn, strerror(errno));
return KRB5_RC_IO_IO;
case EPERM:
case EBUSY:
case EROFS:
/* Solaris Kerberos */
krb5_set_error_message(context, KRB5_RC_IO_PERM,
dgettext(TEXT_DOMAIN,
"Can't destroy replay cache %s: %s"),
d->fn, strerror(errno));
return KRB5_RC_IO_PERM;
case EBADF:
default:
/* Solaris Kerberos */
krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
dgettext(TEXT_DOMAIN,
"Can't destroy replay cache %s: %s"),
d->fn, 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;
}