17c478bd9Sstevel@tonic-gate /*
25e01956fSGlenn Barry * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate */
47c478bd9Sstevel@tonic-gate
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate * lib/krb5/rcache/rc_io.c
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * This file of the Kerberos V5 software is derived from public-domain code
107c478bd9Sstevel@tonic-gate * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate */
137c478bd9Sstevel@tonic-gate
14159d09a2SMark Phalan
157c478bd9Sstevel@tonic-gate /*
167c478bd9Sstevel@tonic-gate * I/O functions for the replay cache default implementation.
177c478bd9Sstevel@tonic-gate */
187c478bd9Sstevel@tonic-gate
19505d05c7Sgtb #if defined(_WIN32)
207c478bd9Sstevel@tonic-gate # define PATH_SEPARATOR "\\"
217c478bd9Sstevel@tonic-gate #else
227c478bd9Sstevel@tonic-gate # define PATH_SEPARATOR "/"
237c478bd9Sstevel@tonic-gate #endif
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate #define KRB5_RC_VNO 0x0501 /* krb5, rcache v 1 */
267c478bd9Sstevel@tonic-gate
27159d09a2SMark Phalan #include "k5-int.h"
28159d09a2SMark Phalan #include <stdio.h> /* for P_tmpdir */
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <syslog.h> /* SUNW */
325e01956fSGlenn Barry #include <locale.h> /* Solaris Kerberos */
337c478bd9Sstevel@tonic-gate #include "rc_base.h"
347c478bd9Sstevel@tonic-gate #include "rc_file.h"
357c478bd9Sstevel@tonic-gate #include "rc_io.h"
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #ifndef O_BINARY
387c478bd9Sstevel@tonic-gate #define O_BINARY 0
397c478bd9Sstevel@tonic-gate #endif
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #ifdef HAVE_NETINET_IN_H
42505d05c7Sgtb #if !defined(_WINSOCKAPI_)
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate #else
46505d05c7Sgtb #error find some way to use net-byte-order file version numbers.
477c478bd9Sstevel@tonic-gate #endif
487c478bd9Sstevel@tonic-gate
49159d09a2SMark Phalan /* Solaris Kerberos */
50159d09a2SMark Phalan #define FREE_RC(x) ((void) free((char *) (x)))
517c478bd9Sstevel@tonic-gate #define UNIQUE getpid() /* hopefully unique number */
527c478bd9Sstevel@tonic-gate
53505d05c7Sgtb #define GETDIR (dir = getdir(), dirlen = strlen(dir) + sizeof(PATH_SEPARATOR) - 1)
547c478bd9Sstevel@tonic-gate
55505d05c7Sgtb static char *
getdir(void)567c478bd9Sstevel@tonic-gate getdir(void)
577c478bd9Sstevel@tonic-gate {
58159d09a2SMark Phalan char *dir;
59505d05c7Sgtb
60505d05c7Sgtb #if defined(_WIN32)
61159d09a2SMark Phalan if (!(dir = getenv("TEMP")))
62159d09a2SMark Phalan if (!(dir = getenv("TMP")))
63159d09a2SMark Phalan dir = "C:";
647c478bd9Sstevel@tonic-gate #else
65159d09a2SMark Phalan /* Solaris Kerberos */
667c478bd9Sstevel@tonic-gate if (geteuid() == 0)
677c478bd9Sstevel@tonic-gate dir = "/var/krb5/rcache/root";
687c478bd9Sstevel@tonic-gate else
697c478bd9Sstevel@tonic-gate dir = "/var/krb5/rcache";
707c478bd9Sstevel@tonic-gate #endif
71505d05c7Sgtb return dir;
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate
74505d05c7Sgtb krb5_error_code
krb5_rc_io_creat(krb5_context context,krb5_rc_iostuff * d,char ** fn)75505d05c7Sgtb krb5_rc_io_creat(krb5_context context, krb5_rc_iostuff *d, char **fn)
767c478bd9Sstevel@tonic-gate {
77159d09a2SMark Phalan char *c;
78159d09a2SMark Phalan krb5_int16 rc_vno = htons(KRB5_RC_VNO);
79159d09a2SMark Phalan krb5_error_code retval = 0;
80159d09a2SMark Phalan int do_not_unlink = 0;
81159d09a2SMark Phalan char *dir;
82159d09a2SMark Phalan size_t dirlen;
83159d09a2SMark Phalan
84159d09a2SMark Phalan GETDIR;
85159d09a2SMark Phalan if (fn && *fn)
86159d09a2SMark Phalan {
87159d09a2SMark Phalan /* Solaris Kerberos */
887c478bd9Sstevel@tonic-gate if (*fn[0] == '/') {
897c478bd9Sstevel@tonic-gate d->fn = strdup(*fn);
907c478bd9Sstevel@tonic-gate if (d->fn == NULL)
917c478bd9Sstevel@tonic-gate return (KRB5_RC_IO_MALLOC);
927c478bd9Sstevel@tonic-gate } else {
937c478bd9Sstevel@tonic-gate if (!(d->fn = malloc(strlen(*fn) + dirlen + 1)))
94159d09a2SMark Phalan return KRB5_RC_IO_MALLOC;
957c478bd9Sstevel@tonic-gate (void) strcpy(d->fn, dir);
967c478bd9Sstevel@tonic-gate (void) strcat(d->fn, PATH_SEPARATOR);
97505d05c7Sgtb (void) strcat(d->fn, *fn);
987c478bd9Sstevel@tonic-gate }
99159d09a2SMark Phalan d->fd = THREEPARAMOPEN(d->fn, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL |
100159d09a2SMark Phalan O_BINARY, 0600);
101159d09a2SMark Phalan }
102159d09a2SMark Phalan else
1037c478bd9Sstevel@tonic-gate {
104159d09a2SMark Phalan /* %d is max 11 digits (-, 10 digits of 32-bit number)
105159d09a2SMark Phalan * 11 + /krb5_RC + aaa = 24, +6 for slop */
106159d09a2SMark Phalan if (!(d->fn = malloc(30 + dirlen)))
107159d09a2SMark Phalan return KRB5_RC_IO_MALLOC;
108159d09a2SMark Phalan if (fn)
109159d09a2SMark Phalan if (!(*fn = malloc(35))) {
110159d09a2SMark Phalan FREE_RC(d->fn);
111159d09a2SMark Phalan return KRB5_RC_IO_MALLOC;
112159d09a2SMark Phalan }
113159d09a2SMark Phalan (void) sprintf(d->fn, "%s%skrb5_RC%d", dir, PATH_SEPARATOR,
114159d09a2SMark Phalan (int) UNIQUE);
115159d09a2SMark Phalan c = d->fn + strlen(d->fn);
116159d09a2SMark Phalan (void) strcpy(c, "aaa");
117159d09a2SMark Phalan while ((d->fd = THREEPARAMOPEN(d->fn, O_WRONLY | O_CREAT | O_TRUNC |
118159d09a2SMark Phalan O_EXCL | O_BINARY, 0600)) == -1)
1197c478bd9Sstevel@tonic-gate {
120159d09a2SMark Phalan if ((c[2]++) == 'z')
121159d09a2SMark Phalan {
122159d09a2SMark Phalan c[2] = 'a';
123159d09a2SMark Phalan if ((c[1]++) == 'z')
124159d09a2SMark Phalan {
125159d09a2SMark Phalan c[1] = 'a';
126159d09a2SMark Phalan if ((c[0]++) == 'z')
127159d09a2SMark Phalan break; /* sigh */
128159d09a2SMark Phalan }
129159d09a2SMark Phalan }
130159d09a2SMark Phalan }
131159d09a2SMark Phalan if (fn)
132159d09a2SMark Phalan (void) strcpy(*fn, d->fn + dirlen);
1337c478bd9Sstevel@tonic-gate }
134159d09a2SMark Phalan if (d->fd == -1)
1357c478bd9Sstevel@tonic-gate {
136159d09a2SMark Phalan switch(errno)
137159d09a2SMark Phalan {
1387c478bd9Sstevel@tonic-gate case EFBIG:
1397c478bd9Sstevel@tonic-gate #ifdef EDQUOT
1407c478bd9Sstevel@tonic-gate case EDQUOT:
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate case ENOSPC:
1437c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_SPACE;
144505d05c7Sgtb goto cleanup;
145159d09a2SMark Phalan
1467c478bd9Sstevel@tonic-gate case EIO:
147505d05c7Sgtb retval = KRB5_RC_IO_IO;
148505d05c7Sgtb goto cleanup;
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate case EPERM:
1517c478bd9Sstevel@tonic-gate case EACCES:
1527c478bd9Sstevel@tonic-gate case EROFS:
1537c478bd9Sstevel@tonic-gate case EEXIST:
154505d05c7Sgtb retval = KRB5_RC_IO_PERM;
155159d09a2SMark Phalan krb5_set_error_message(context, retval,
1565e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
1575e01956fSGlenn Barry "Cannot create replay cache %s: %s"),
1585e01956fSGlenn Barry d->fn ? d->fn : "<null>",
1595e01956fSGlenn Barry strerror(errno));
160505d05c7Sgtb do_not_unlink = 1;
161505d05c7Sgtb goto cleanup;
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate default:
164505d05c7Sgtb retval = KRB5_RC_IO_UNKNOWN;
165159d09a2SMark Phalan krb5_set_error_message(context, retval,
1665e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
1675e01956fSGlenn Barry "Cannot create replay cache %s: %s"),
1685e01956fSGlenn Barry d->fn ? d->fn : "<null>",
1695e01956fSGlenn Barry strerror(errno));
170505d05c7Sgtb goto cleanup;
171159d09a2SMark Phalan }
1727c478bd9Sstevel@tonic-gate }
173505d05c7Sgtb retval = krb5_rc_io_write(context, d, (krb5_pointer)&rc_vno,
174505d05c7Sgtb sizeof(rc_vno));
175505d05c7Sgtb if (retval)
176505d05c7Sgtb goto cleanup;
177505d05c7Sgtb
178505d05c7Sgtb retval = krb5_rc_io_sync(context, d);
179505d05c7Sgtb
180505d05c7Sgtb cleanup:
181505d05c7Sgtb if (retval) {
182505d05c7Sgtb if (d->fn) {
183505d05c7Sgtb if (!do_not_unlink)
184505d05c7Sgtb (void) unlink(d->fn);
185159d09a2SMark Phalan FREE_RC(d->fn);
186505d05c7Sgtb d->fn = NULL;
187505d05c7Sgtb }
188159d09a2SMark Phalan if (d->fd != -1) {
189159d09a2SMark Phalan (void) close(d->fd);
190159d09a2SMark Phalan }
1917c478bd9Sstevel@tonic-gate }
192505d05c7Sgtb return retval;
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate
195505d05c7Sgtb static krb5_error_code
krb5_rc_io_open_internal(krb5_context context,krb5_rc_iostuff * d,char * fn,char * full_pathname)196505d05c7Sgtb krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
197159d09a2SMark Phalan char* full_pathname)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate krb5_int16 rc_vno;
2007c478bd9Sstevel@tonic-gate krb5_error_code retval = 0;
2017c478bd9Sstevel@tonic-gate int do_not_unlink = 1;
2027c478bd9Sstevel@tonic-gate struct stat lstatb, fstatb;
2037c478bd9Sstevel@tonic-gate int use_errno = 0;
204505d05c7Sgtb char *dir;
205505d05c7Sgtb size_t dirlen;
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate GETDIR;
2087c478bd9Sstevel@tonic-gate if (fn[0] == '/') {
2097c478bd9Sstevel@tonic-gate d->fn = strdup(fn);
2107c478bd9Sstevel@tonic-gate if (d->fn == NULL)
2117c478bd9Sstevel@tonic-gate return (KRB5_RC_IO_MALLOC);
2127c478bd9Sstevel@tonic-gate } else {
2137c478bd9Sstevel@tonic-gate if (!(d->fn = malloc(strlen(fn) + dirlen + 1)))
214159d09a2SMark Phalan return KRB5_RC_IO_MALLOC;
215505d05c7Sgtb (void) strcpy(d->fn, dir);
216505d05c7Sgtb (void) strcat(d->fn, PATH_SEPARATOR);
217505d05c7Sgtb (void) strcat(d->fn, fn);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /* Solaris: BEGIN made changes to be safer and better code structure */
2217c478bd9Sstevel@tonic-gate if ((d->fd = THREEPARAMOPEN(d->fn, O_RDWR|O_BINARY, 0600)) == -1) {
2227c478bd9Sstevel@tonic-gate use_errno = 1;
2237c478bd9Sstevel@tonic-gate goto cleanup;
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate do_not_unlink = 0;
2277c478bd9Sstevel@tonic-gate if (fstat(d->fd, &fstatb) == 0) {
2287c478bd9Sstevel@tonic-gate #ifndef NO_USERID
2297c478bd9Sstevel@tonic-gate uid_t me;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate me = geteuid();
2327c478bd9Sstevel@tonic-gate /* must be owned by this user, to prevent some security problems with
2337c478bd9Sstevel@tonic-gate * other users modifying replay cache stuff and must be a regular file
2347c478bd9Sstevel@tonic-gate */
2357c478bd9Sstevel@tonic-gate if ((fstatb.st_uid != me) || ((fstatb.st_mode & S_IFMT) != S_IFREG)) {
2367c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_PERM;
2377c478bd9Sstevel@tonic-gate goto cleanup;
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate #else
2407c478bd9Sstevel@tonic-gate /* make sure the rcache is a regular file */
2417c478bd9Sstevel@tonic-gate if (((fstatb.st_mode & S_IFMT) != S_IFREG)) {
2427c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_PERM;
243159d09a2SMark Phalan
2447c478bd9Sstevel@tonic-gate goto cleanup;
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate #endif
2477c478bd9Sstevel@tonic-gate if (lstat(d->fn, &lstatb) == 0) {
2487c478bd9Sstevel@tonic-gate /* Make sure fstat() and lstat() have accessed the same file */
249*55fea89dSDan Cross if ((lstatb.st_ino != fstatb.st_ino) ||
2507c478bd9Sstevel@tonic-gate (lstatb.st_dev != fstatb.st_dev)) {
2517c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_PERM;
2527c478bd9Sstevel@tonic-gate goto cleanup;
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate if ((lstatb.st_mode & S_IFMT) == S_IFLNK) {
2567c478bd9Sstevel@tonic-gate /* if we accessed the rcache via a symlink, bail out */
2577c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error, krb replay cache %s is a symlink "
2587c478bd9Sstevel@tonic-gate "and should be removed.\n", d->fn);
2597c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_PERM;
2607c478bd9Sstevel@tonic-gate goto cleanup;
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate else {
2647c478bd9Sstevel@tonic-gate use_errno = 1;
2657c478bd9Sstevel@tonic-gate goto cleanup;
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate else {
2697c478bd9Sstevel@tonic-gate use_errno = 1;
2707c478bd9Sstevel@tonic-gate goto cleanup;
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate
273505d05c7Sgtb do_not_unlink = 0;
2747c478bd9Sstevel@tonic-gate retval = krb5_rc_io_read(context, d, (krb5_pointer) &rc_vno,
275159d09a2SMark Phalan sizeof(rc_vno));
2767c478bd9Sstevel@tonic-gate if (retval)
2777c478bd9Sstevel@tonic-gate goto cleanup;
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate if (ntohs(rc_vno) != KRB5_RC_VNO)
2807c478bd9Sstevel@tonic-gate retval = KRB5_RCACHE_BADVNO;
2817c478bd9Sstevel@tonic-gate
282159d09a2SMark Phalan cleanup:
2837c478bd9Sstevel@tonic-gate if (use_errno) {
2847c478bd9Sstevel@tonic-gate switch(errno)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate case EFBIG:
2877c478bd9Sstevel@tonic-gate #ifdef EDQUOT
2887c478bd9Sstevel@tonic-gate case EDQUOT:
2897c478bd9Sstevel@tonic-gate #endif
2907c478bd9Sstevel@tonic-gate case ENOSPC:
2917c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_SPACE;
2927c478bd9Sstevel@tonic-gate break;
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate case EIO:
2957c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_IO;
2967c478bd9Sstevel@tonic-gate break;
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate case EPERM:
2997c478bd9Sstevel@tonic-gate case EACCES:
3007c478bd9Sstevel@tonic-gate case EROFS:
3017c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_PERM;
302159d09a2SMark Phalan krb5_set_error_message (context, retval,
3035e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
3045e01956fSGlenn Barry "Cannot open replay cache %s: %s"),
305159d09a2SMark Phalan d->fn, strerror(errno));
3067c478bd9Sstevel@tonic-gate break;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate default:
3097c478bd9Sstevel@tonic-gate retval = KRB5_RC_IO_UNKNOWN;
310159d09a2SMark Phalan krb5_set_error_message (context, retval,
3115e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
3125e01956fSGlenn Barry "Cannot open replay cache %s: %s"),
313159d09a2SMark Phalan d->fn, strerror(errno));
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate /* Solaris: END made changes to be safer and better code structure */
3177c478bd9Sstevel@tonic-gate if (retval) {
3187c478bd9Sstevel@tonic-gate if (d->fn) {
319159d09a2SMark Phalan if (!do_not_unlink)
3207c478bd9Sstevel@tonic-gate (void) unlink(d->fn);
321159d09a2SMark Phalan FREE_RC(d->fn);
3227c478bd9Sstevel@tonic-gate d->fn = NULL;
3237c478bd9Sstevel@tonic-gate }
324*55fea89dSDan Cross if (d->fd >= 0)
325159d09a2SMark Phalan (void) close(d->fd);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate return retval;
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
330505d05c7Sgtb krb5_error_code
krb5_rc_io_open(krb5_context context,krb5_rc_iostuff * d,char * fn)331505d05c7Sgtb krb5_rc_io_open(krb5_context context, krb5_rc_iostuff *d, char *fn)
332505d05c7Sgtb {
333505d05c7Sgtb return krb5_rc_io_open_internal(context, d, fn, NULL);
334505d05c7Sgtb }
335505d05c7Sgtb
3367c478bd9Sstevel@tonic-gate krb5_error_code
krb5_rc_io_move(krb5_context context,krb5_rc_iostuff * new1,krb5_rc_iostuff * old)3377c478bd9Sstevel@tonic-gate krb5_rc_io_move(krb5_context context, krb5_rc_iostuff *new1,
3387c478bd9Sstevel@tonic-gate krb5_rc_iostuff *old)
3397c478bd9Sstevel@tonic-gate {
340159d09a2SMark Phalan #if defined(_WIN32) || defined(__CYGWIN__)
341505d05c7Sgtb char *new_fn = NULL;
342505d05c7Sgtb char *old_fn = NULL;
343505d05c7Sgtb off_t offset = 0;
344505d05c7Sgtb krb5_error_code retval = 0;
3457c478bd9Sstevel@tonic-gate /*
346505d05c7Sgtb * Initial work around provided by Tom Sanfilippo to work around
347505d05c7Sgtb * poor Windows emulation of POSIX functions. Rename and dup has
3487c478bd9Sstevel@tonic-gate * different semantics!
349505d05c7Sgtb *
350505d05c7Sgtb * Additional fixes and explanation provided by dalmeida@mit.edu:
351505d05c7Sgtb *
352505d05c7Sgtb * First, we save the offset of "old". Then, we close and remove
353505d05c7Sgtb * the "new" file so we can do the rename. We also close "old" to
354505d05c7Sgtb * make sure the rename succeeds (though that might not be
355505d05c7Sgtb * necessary on some systems).
356505d05c7Sgtb *
357505d05c7Sgtb * Next, we do the rename. If all goes well, we seek the "new"
358505d05c7Sgtb * file to the position "old" was at.
359505d05c7Sgtb *
360505d05c7Sgtb * --- WARNING!!! ---
361505d05c7Sgtb *
362505d05c7Sgtb * Since "old" is now gone, we mourn its disappearance, but we
363505d05c7Sgtb * cannot emulate that Unix behavior... THIS BEHAVIOR IS
364505d05c7Sgtb * DIFFERENT FROM UNIX. However, it is ok because this function
365505d05c7Sgtb * gets called such that "old" gets closed right afterwards.
3667c478bd9Sstevel@tonic-gate */
367505d05c7Sgtb offset = lseek(old->fd, 0, SEEK_CUR);
368505d05c7Sgtb
369505d05c7Sgtb new_fn = new1->fn;
370505d05c7Sgtb new1->fn = NULL;
371505d05c7Sgtb close(new1->fd);
372505d05c7Sgtb new1->fd = -1;
373505d05c7Sgtb
374505d05c7Sgtb unlink(new_fn);
375505d05c7Sgtb
376505d05c7Sgtb old_fn = old->fn;
377505d05c7Sgtb old->fn = NULL;
3787c478bd9Sstevel@tonic-gate close(old->fd);
379505d05c7Sgtb old->fd = -1;
380505d05c7Sgtb
381505d05c7Sgtb if (rename(old_fn, new_fn) == -1) { /* MUST be atomic! */
382505d05c7Sgtb retval = KRB5_RC_IO_UNKNOWN;
383505d05c7Sgtb goto cleanup;
384505d05c7Sgtb }
385505d05c7Sgtb
386505d05c7Sgtb retval = krb5_rc_io_open_internal(context, new1, 0, new_fn);
387505d05c7Sgtb if (retval)
388505d05c7Sgtb goto cleanup;
389505d05c7Sgtb
390505d05c7Sgtb if (lseek(new1->fd, offset, SEEK_SET) == -1) {
391505d05c7Sgtb retval = KRB5_RC_IO_UNKNOWN;
392505d05c7Sgtb goto cleanup;
393505d05c7Sgtb }
394505d05c7Sgtb
395505d05c7Sgtb cleanup:
396505d05c7Sgtb free(new_fn);
397505d05c7Sgtb free(old_fn);
398505d05c7Sgtb return retval;
3997c478bd9Sstevel@tonic-gate #else
400505d05c7Sgtb char *fn = NULL;
4017c478bd9Sstevel@tonic-gate if (rename(old->fn, new1->fn) == -1) /* MUST be atomic! */
4027c478bd9Sstevel@tonic-gate return KRB5_RC_IO_UNKNOWN;
4037c478bd9Sstevel@tonic-gate fn = new1->fn;
4047c478bd9Sstevel@tonic-gate new1->fn = NULL; /* avoid clobbering */
4057c478bd9Sstevel@tonic-gate (void) krb5_rc_io_close(context, new1);
4067c478bd9Sstevel@tonic-gate new1->fn = fn;
4077c478bd9Sstevel@tonic-gate new1->fd = dup(old->fd);
4087c478bd9Sstevel@tonic-gate return 0;
409505d05c7Sgtb #endif
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
412505d05c7Sgtb krb5_error_code
krb5_rc_io_write(krb5_context context,krb5_rc_iostuff * d,krb5_pointer buf,unsigned int num)413505d05c7Sgtb krb5_rc_io_write(krb5_context context, krb5_rc_iostuff *d, krb5_pointer buf,
414505d05c7Sgtb unsigned int num)
4157c478bd9Sstevel@tonic-gate {
416505d05c7Sgtb if (write(d->fd, (char *) buf, num) == -1)
417505d05c7Sgtb switch(errno)
418505d05c7Sgtb {
4197c478bd9Sstevel@tonic-gate #ifdef EDQUOT
420159d09a2SMark Phalan case EDQUOT:
4217c478bd9Sstevel@tonic-gate #endif
422159d09a2SMark Phalan case EFBIG:
423159d09a2SMark Phalan case ENOSPC:
424159d09a2SMark Phalan krb5_set_error_message (context, KRB5_RC_IO_SPACE,
4255e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
4265e01956fSGlenn Barry "Can't write to replay cache %s: %s"),
4275e01956fSGlenn Barry d->fn, strerror(errno));
428159d09a2SMark Phalan return KRB5_RC_IO_SPACE;
429159d09a2SMark Phalan case EIO:
430159d09a2SMark Phalan krb5_set_error_message (context, KRB5_RC_IO_IO,
4315e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
4325e01956fSGlenn Barry "Can't write to replay cache %s: %s"),
4335e01956fSGlenn Barry d->fn, strerror(errno));
434159d09a2SMark Phalan return KRB5_RC_IO_IO;
435159d09a2SMark Phalan case EBADF:
436159d09a2SMark Phalan default:
437159d09a2SMark Phalan krb5_set_error_message (context, KRB5_RC_IO_UNKNOWN,
4385e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
4395e01956fSGlenn Barry "Can't write to replay cache %s: %s"),
4405e01956fSGlenn Barry d->fn, strerror(errno));
441159d09a2SMark Phalan return KRB5_RC_IO_UNKNOWN;
442505d05c7Sgtb }
443505d05c7Sgtb return 0;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate
446505d05c7Sgtb krb5_error_code
krb5_rc_io_sync(krb5_context context,krb5_rc_iostuff * d)447505d05c7Sgtb krb5_rc_io_sync(krb5_context context, krb5_rc_iostuff *d)
4487c478bd9Sstevel@tonic-gate {
449505d05c7Sgtb #if defined(_WIN32)
450505d05c7Sgtb #ifndef fsync
451505d05c7Sgtb #define fsync _commit
452505d05c7Sgtb #endif
453505d05c7Sgtb #endif
4547c478bd9Sstevel@tonic-gate if (fsync(d->fd) == -1) {
455505d05c7Sgtb switch(errno)
456505d05c7Sgtb {
457505d05c7Sgtb case EBADF: return KRB5_RC_IO_UNKNOWN;
458505d05c7Sgtb case EIO: return KRB5_RC_IO_IO;
459159d09a2SMark Phalan default:
460159d09a2SMark Phalan krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
4615e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
4625e01956fSGlenn Barry "Cannot sync replay cache file %s: %s"),
4635e01956fSGlenn Barry d->fn, strerror(errno));
464159d09a2SMark Phalan return KRB5_RC_IO_UNKNOWN;
465505d05c7Sgtb }
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate return 0;
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
471505d05c7Sgtb krb5_error_code
krb5_rc_io_read(krb5_context context,krb5_rc_iostuff * d,krb5_pointer buf,unsigned int num)472505d05c7Sgtb krb5_rc_io_read(krb5_context context, krb5_rc_iostuff *d, krb5_pointer buf,
473505d05c7Sgtb unsigned int num)
4747c478bd9Sstevel@tonic-gate {
475505d05c7Sgtb int count;
476505d05c7Sgtb if ((count = read(d->fd, (char *) buf, num)) == -1)
477505d05c7Sgtb switch(errno)
478505d05c7Sgtb {
479505d05c7Sgtb case EIO: return KRB5_RC_IO_IO;
480159d09a2SMark Phalan case EBADF:
481159d09a2SMark Phalan default:
482159d09a2SMark Phalan krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
4835e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
4845e01956fSGlenn Barry "Can't read from replay cache %s: %s"),
4855e01956fSGlenn Barry d->fn, strerror(errno));
486159d09a2SMark Phalan return KRB5_RC_IO_UNKNOWN;
487505d05c7Sgtb }
488505d05c7Sgtb if (count == 0)
489505d05c7Sgtb return KRB5_RC_IO_EOF;
490505d05c7Sgtb return 0;
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate /*ARGSUSED*/
494505d05c7Sgtb krb5_error_code
krb5_rc_io_close(krb5_context context,krb5_rc_iostuff * d)495505d05c7Sgtb krb5_rc_io_close(krb5_context context, krb5_rc_iostuff *d)
4967c478bd9Sstevel@tonic-gate {
497505d05c7Sgtb if (d->fn != NULL) {
498159d09a2SMark Phalan FREE_RC(d->fn);
499505d05c7Sgtb d->fn = NULL;
500505d05c7Sgtb }
501505d05c7Sgtb if (d->fd != -1) {
502505d05c7Sgtb if (close(d->fd) == -1) /* can't happen */
503505d05c7Sgtb return KRB5_RC_IO_UNKNOWN;
504505d05c7Sgtb d->fd = -1;
505505d05c7Sgtb }
506505d05c7Sgtb return 0;
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
510505d05c7Sgtb krb5_error_code
krb5_rc_io_destroy(krb5_context context,krb5_rc_iostuff * d)511505d05c7Sgtb krb5_rc_io_destroy(krb5_context context, krb5_rc_iostuff *d)
5127c478bd9Sstevel@tonic-gate {
513159d09a2SMark Phalan if (unlink(d->fn) == -1)
514159d09a2SMark Phalan switch(errno)
515159d09a2SMark Phalan {
516159d09a2SMark Phalan case EIO:
517159d09a2SMark Phalan krb5_set_error_message(context, KRB5_RC_IO_IO,
5185e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
5195e01956fSGlenn Barry "Can't destroy replay cache %s: %s"),
5205e01956fSGlenn Barry d->fn, strerror(errno));
521159d09a2SMark Phalan return KRB5_RC_IO_IO;
522159d09a2SMark Phalan case EPERM:
523159d09a2SMark Phalan case EBUSY:
524159d09a2SMark Phalan case EROFS:
525159d09a2SMark Phalan krb5_set_error_message(context, KRB5_RC_IO_PERM,
5265e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
5275e01956fSGlenn Barry "Can't destroy replay cache %s: %s"),
5285e01956fSGlenn Barry d->fn, strerror(errno));
529159d09a2SMark Phalan return KRB5_RC_IO_PERM;
530159d09a2SMark Phalan case EBADF:
531159d09a2SMark Phalan default:
532159d09a2SMark Phalan krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
5335e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
5345e01956fSGlenn Barry "Can't destroy replay cache %s: %s"),
5355e01956fSGlenn Barry d->fn, strerror(errno));
536159d09a2SMark Phalan return KRB5_RC_IO_UNKNOWN;
537159d09a2SMark Phalan }
538159d09a2SMark Phalan return 0;
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate /*ARGSUSED*/
542505d05c7Sgtb krb5_error_code
krb5_rc_io_mark(krb5_context context,krb5_rc_iostuff * d)543505d05c7Sgtb krb5_rc_io_mark(krb5_context context, krb5_rc_iostuff *d)
5447c478bd9Sstevel@tonic-gate {
545505d05c7Sgtb d->mark = lseek(d->fd, (off_t) 0, SEEK_CUR); /* can't fail */
546505d05c7Sgtb return 0;
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate /*ARGSUSED*/
550505d05c7Sgtb krb5_error_code
krb5_rc_io_unmark(krb5_context context,krb5_rc_iostuff * d)551505d05c7Sgtb krb5_rc_io_unmark(krb5_context context, krb5_rc_iostuff *d)
5527c478bd9Sstevel@tonic-gate {
553505d05c7Sgtb (void) lseek(d->fd, d->mark, SEEK_SET); /* if it fails, tough luck */
554505d05c7Sgtb return 0;
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5587c478bd9Sstevel@tonic-gate long
krb5_rc_io_size(krb5_context context,krb5_rc_iostuff * d)559505d05c7Sgtb krb5_rc_io_size(krb5_context context, krb5_rc_iostuff *d)
5607c478bd9Sstevel@tonic-gate {
5617c478bd9Sstevel@tonic-gate struct stat statb;
5627c478bd9Sstevel@tonic-gate
563505d05c7Sgtb if (fstat(d->fd, &statb) == 0)
5647c478bd9Sstevel@tonic-gate return statb.st_size;
5657c478bd9Sstevel@tonic-gate else
5667c478bd9Sstevel@tonic-gate return 0;
5677c478bd9Sstevel@tonic-gate }
568