xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/fcache.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: fcache.c,v 1.1.1.2 2014/04/24 12:45:49 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc  * All rights reserved.
7ebfedea0SLionel Sambuc  *
8ebfedea0SLionel Sambuc  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9ebfedea0SLionel Sambuc  *
10ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
12ebfedea0SLionel Sambuc  * are met:
13ebfedea0SLionel Sambuc  *
14ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
15ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
16ebfedea0SLionel Sambuc  *
17ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
18ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
19ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
20ebfedea0SLionel Sambuc  *
21ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
22ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
23ebfedea0SLionel Sambuc  *    without specific prior written permission.
24ebfedea0SLionel Sambuc  *
25ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ebfedea0SLionel Sambuc  * SUCH DAMAGE.
36ebfedea0SLionel Sambuc  */
37ebfedea0SLionel Sambuc 
38ebfedea0SLionel Sambuc #include "krb5_locl.h"
39ebfedea0SLionel Sambuc 
40ebfedea0SLionel Sambuc typedef struct krb5_fcache{
41ebfedea0SLionel Sambuc     char *filename;
42ebfedea0SLionel Sambuc     int version;
43ebfedea0SLionel Sambuc }krb5_fcache;
44ebfedea0SLionel Sambuc 
45ebfedea0SLionel Sambuc struct fcc_cursor {
46ebfedea0SLionel Sambuc     int fd;
47ebfedea0SLionel Sambuc     krb5_storage *sp;
48ebfedea0SLionel Sambuc };
49ebfedea0SLionel Sambuc 
50ebfedea0SLionel Sambuc #define KRB5_FCC_FVNO_1 1
51ebfedea0SLionel Sambuc #define KRB5_FCC_FVNO_2 2
52ebfedea0SLionel Sambuc #define KRB5_FCC_FVNO_3 3
53ebfedea0SLionel Sambuc #define KRB5_FCC_FVNO_4 4
54ebfedea0SLionel Sambuc 
55ebfedea0SLionel Sambuc #define FCC_TAG_DELTATIME 1
56ebfedea0SLionel Sambuc 
57ebfedea0SLionel Sambuc #define FCACHE(X) ((krb5_fcache*)(X)->data.data)
58ebfedea0SLionel Sambuc 
59ebfedea0SLionel Sambuc #define FILENAME(X) (FCACHE(X)->filename)
60ebfedea0SLionel Sambuc 
61ebfedea0SLionel Sambuc #define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
62ebfedea0SLionel Sambuc 
63ebfedea0SLionel Sambuc static const char* KRB5_CALLCONV
fcc_get_name(krb5_context context,krb5_ccache id)64ebfedea0SLionel Sambuc fcc_get_name(krb5_context context,
65ebfedea0SLionel Sambuc 	     krb5_ccache id)
66ebfedea0SLionel Sambuc {
67*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
68*0a6a1f1dSLionel Sambuc         return NULL;
69*0a6a1f1dSLionel Sambuc 
70ebfedea0SLionel Sambuc     return FILENAME(id);
71ebfedea0SLionel Sambuc }
72ebfedea0SLionel Sambuc 
73ebfedea0SLionel Sambuc int
_krb5_xlock(krb5_context context,int fd,krb5_boolean exclusive,const char * filename)74ebfedea0SLionel Sambuc _krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive,
75ebfedea0SLionel Sambuc 	    const char *filename)
76ebfedea0SLionel Sambuc {
77ebfedea0SLionel Sambuc     int ret;
78ebfedea0SLionel Sambuc #ifdef HAVE_FCNTL
79ebfedea0SLionel Sambuc     struct flock l;
80ebfedea0SLionel Sambuc 
81ebfedea0SLionel Sambuc     l.l_start = 0;
82ebfedea0SLionel Sambuc     l.l_len = 0;
83ebfedea0SLionel Sambuc     l.l_type = exclusive ? F_WRLCK : F_RDLCK;
84ebfedea0SLionel Sambuc     l.l_whence = SEEK_SET;
85ebfedea0SLionel Sambuc     ret = fcntl(fd, F_SETLKW, &l);
86ebfedea0SLionel Sambuc #else
87ebfedea0SLionel Sambuc     ret = flock(fd, exclusive ? LOCK_EX : LOCK_SH);
88ebfedea0SLionel Sambuc #endif
89ebfedea0SLionel Sambuc     if(ret < 0)
90ebfedea0SLionel Sambuc 	ret = errno;
91ebfedea0SLionel Sambuc     if(ret == EACCES) /* fcntl can return EACCES instead of EAGAIN */
92ebfedea0SLionel Sambuc 	ret = EAGAIN;
93ebfedea0SLionel Sambuc 
94ebfedea0SLionel Sambuc     switch (ret) {
95ebfedea0SLionel Sambuc     case 0:
96ebfedea0SLionel Sambuc 	break;
97ebfedea0SLionel Sambuc     case EINVAL: /* filesystem doesn't support locking, let the user have it */
98ebfedea0SLionel Sambuc 	ret = 0;
99ebfedea0SLionel Sambuc 	break;
100ebfedea0SLionel Sambuc     case EAGAIN:
101ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
102ebfedea0SLionel Sambuc 			       N_("timed out locking cache file %s", "file"),
103ebfedea0SLionel Sambuc 			       filename);
104ebfedea0SLionel Sambuc 	break;
105ebfedea0SLionel Sambuc     default: {
106ebfedea0SLionel Sambuc 	char buf[128];
107ebfedea0SLionel Sambuc 	rk_strerror_r(ret, buf, sizeof(buf));
108ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
109ebfedea0SLionel Sambuc 			       N_("error locking cache file %s: %s",
110ebfedea0SLionel Sambuc 				  "file, error"), filename, buf);
111ebfedea0SLionel Sambuc 	break;
112ebfedea0SLionel Sambuc     }
113ebfedea0SLionel Sambuc     }
114ebfedea0SLionel Sambuc     return ret;
115ebfedea0SLionel Sambuc }
116ebfedea0SLionel Sambuc 
117ebfedea0SLionel Sambuc int
_krb5_xunlock(krb5_context context,int fd)118ebfedea0SLionel Sambuc _krb5_xunlock(krb5_context context, int fd)
119ebfedea0SLionel Sambuc {
120ebfedea0SLionel Sambuc     int ret;
121ebfedea0SLionel Sambuc #ifdef HAVE_FCNTL
122ebfedea0SLionel Sambuc     struct flock l;
123ebfedea0SLionel Sambuc     l.l_start = 0;
124ebfedea0SLionel Sambuc     l.l_len = 0;
125ebfedea0SLionel Sambuc     l.l_type = F_UNLCK;
126ebfedea0SLionel Sambuc     l.l_whence = SEEK_SET;
127ebfedea0SLionel Sambuc     ret = fcntl(fd, F_SETLKW, &l);
128ebfedea0SLionel Sambuc #else
129ebfedea0SLionel Sambuc     ret = flock(fd, LOCK_UN);
130ebfedea0SLionel Sambuc #endif
131ebfedea0SLionel Sambuc     if (ret < 0)
132ebfedea0SLionel Sambuc 	ret = errno;
133ebfedea0SLionel Sambuc     switch (ret) {
134ebfedea0SLionel Sambuc     case 0:
135ebfedea0SLionel Sambuc 	break;
136ebfedea0SLionel Sambuc     case EINVAL: /* filesystem doesn't support locking, let the user have it */
137ebfedea0SLionel Sambuc 	ret = 0;
138ebfedea0SLionel Sambuc 	break;
139ebfedea0SLionel Sambuc     default: {
140ebfedea0SLionel Sambuc 	char buf[128];
141ebfedea0SLionel Sambuc 	rk_strerror_r(ret, buf, sizeof(buf));
142ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
143ebfedea0SLionel Sambuc 			       N_("Failed to unlock file: %s", ""), buf);
144ebfedea0SLionel Sambuc 	break;
145ebfedea0SLionel Sambuc     }
146ebfedea0SLionel Sambuc     }
147ebfedea0SLionel Sambuc     return ret;
148ebfedea0SLionel Sambuc }
149ebfedea0SLionel Sambuc 
150ebfedea0SLionel Sambuc static krb5_error_code
write_storage(krb5_context context,krb5_storage * sp,int fd)151ebfedea0SLionel Sambuc write_storage(krb5_context context, krb5_storage *sp, int fd)
152ebfedea0SLionel Sambuc {
153ebfedea0SLionel Sambuc     krb5_error_code ret;
154ebfedea0SLionel Sambuc     krb5_data data;
155ebfedea0SLionel Sambuc     ssize_t sret;
156ebfedea0SLionel Sambuc 
157ebfedea0SLionel Sambuc     ret = krb5_storage_to_data(sp, &data);
158ebfedea0SLionel Sambuc     if (ret) {
159ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
160ebfedea0SLionel Sambuc 	return ret;
161ebfedea0SLionel Sambuc     }
162ebfedea0SLionel Sambuc     sret = write(fd, data.data, data.length);
163*0a6a1f1dSLionel Sambuc     ret = (sret != (ssize_t)data.length);
164ebfedea0SLionel Sambuc     krb5_data_free(&data);
165ebfedea0SLionel Sambuc     if (ret) {
166ebfedea0SLionel Sambuc 	ret = errno;
167ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
168ebfedea0SLionel Sambuc 			       N_("Failed to write FILE credential data", ""));
169ebfedea0SLionel Sambuc 	return ret;
170ebfedea0SLionel Sambuc     }
171ebfedea0SLionel Sambuc     return 0;
172ebfedea0SLionel Sambuc }
173ebfedea0SLionel Sambuc 
174ebfedea0SLionel Sambuc 
175ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_lock(krb5_context context,krb5_ccache id,int fd,krb5_boolean exclusive)176ebfedea0SLionel Sambuc fcc_lock(krb5_context context, krb5_ccache id,
177ebfedea0SLionel Sambuc 	 int fd, krb5_boolean exclusive)
178ebfedea0SLionel Sambuc {
179ebfedea0SLionel Sambuc     return _krb5_xlock(context, fd, exclusive, fcc_get_name(context, id));
180ebfedea0SLionel Sambuc }
181ebfedea0SLionel Sambuc 
182ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_unlock(krb5_context context,int fd)183ebfedea0SLionel Sambuc fcc_unlock(krb5_context context, int fd)
184ebfedea0SLionel Sambuc {
185ebfedea0SLionel Sambuc     return _krb5_xunlock(context, fd);
186ebfedea0SLionel Sambuc }
187ebfedea0SLionel Sambuc 
188ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_resolve(krb5_context context,krb5_ccache * id,const char * res)189ebfedea0SLionel Sambuc fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
190ebfedea0SLionel Sambuc {
191ebfedea0SLionel Sambuc     krb5_fcache *f;
192ebfedea0SLionel Sambuc     f = malloc(sizeof(*f));
193ebfedea0SLionel Sambuc     if(f == NULL) {
194ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_CC_NOMEM,
195ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
196ebfedea0SLionel Sambuc 	return KRB5_CC_NOMEM;
197ebfedea0SLionel Sambuc     }
198ebfedea0SLionel Sambuc     f->filename = strdup(res);
199ebfedea0SLionel Sambuc     if(f->filename == NULL){
200ebfedea0SLionel Sambuc 	free(f);
201ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_CC_NOMEM,
202ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
203ebfedea0SLionel Sambuc 	return KRB5_CC_NOMEM;
204ebfedea0SLionel Sambuc     }
205ebfedea0SLionel Sambuc     f->version = 0;
206ebfedea0SLionel Sambuc     (*id)->data.data = f;
207ebfedea0SLionel Sambuc     (*id)->data.length = sizeof(*f);
208ebfedea0SLionel Sambuc     return 0;
209ebfedea0SLionel Sambuc }
210ebfedea0SLionel Sambuc 
211ebfedea0SLionel Sambuc /*
212ebfedea0SLionel Sambuc  * Try to scrub the contents of `filename' safely.
213ebfedea0SLionel Sambuc  */
214ebfedea0SLionel Sambuc 
215ebfedea0SLionel Sambuc static int
scrub_file(int fd)216ebfedea0SLionel Sambuc scrub_file (int fd)
217ebfedea0SLionel Sambuc {
218ebfedea0SLionel Sambuc     off_t pos;
219ebfedea0SLionel Sambuc     char buf[128];
220ebfedea0SLionel Sambuc 
221ebfedea0SLionel Sambuc     pos = lseek(fd, 0, SEEK_END);
222ebfedea0SLionel Sambuc     if (pos < 0)
223ebfedea0SLionel Sambuc         return errno;
224ebfedea0SLionel Sambuc     if (lseek(fd, 0, SEEK_SET) < 0)
225ebfedea0SLionel Sambuc         return errno;
226ebfedea0SLionel Sambuc     memset(buf, 0, sizeof(buf));
227ebfedea0SLionel Sambuc     while(pos > 0) {
228*0a6a1f1dSLionel Sambuc         ssize_t tmp = write(fd, buf, min((off_t)sizeof(buf), pos));
229ebfedea0SLionel Sambuc 
230ebfedea0SLionel Sambuc 	if (tmp < 0)
231ebfedea0SLionel Sambuc 	    return errno;
232ebfedea0SLionel Sambuc 	pos -= tmp;
233ebfedea0SLionel Sambuc     }
234ebfedea0SLionel Sambuc #ifdef _MSC_VER
235ebfedea0SLionel Sambuc     _commit (fd);
236ebfedea0SLionel Sambuc #else
237ebfedea0SLionel Sambuc     fsync (fd);
238ebfedea0SLionel Sambuc #endif
239ebfedea0SLionel Sambuc     return 0;
240ebfedea0SLionel Sambuc }
241ebfedea0SLionel Sambuc 
242ebfedea0SLionel Sambuc /*
243ebfedea0SLionel Sambuc  * Erase `filename' if it exists, trying to remove the contents if
244ebfedea0SLionel Sambuc  * it's `safe'.  We always try to remove the file, it it exists.  It's
245ebfedea0SLionel Sambuc  * only overwritten if it's a regular file (not a symlink and not a
246ebfedea0SLionel Sambuc  * hardlink)
247ebfedea0SLionel Sambuc  */
248ebfedea0SLionel Sambuc 
249ebfedea0SLionel Sambuc krb5_error_code
_krb5_erase_file(krb5_context context,const char * filename)250ebfedea0SLionel Sambuc _krb5_erase_file(krb5_context context, const char *filename)
251ebfedea0SLionel Sambuc {
252ebfedea0SLionel Sambuc     int fd;
253ebfedea0SLionel Sambuc     struct stat sb1, sb2;
254ebfedea0SLionel Sambuc     int ret;
255ebfedea0SLionel Sambuc 
256ebfedea0SLionel Sambuc     ret = lstat (filename, &sb1);
257ebfedea0SLionel Sambuc     if (ret < 0)
258ebfedea0SLionel Sambuc 	return errno;
259ebfedea0SLionel Sambuc 
260ebfedea0SLionel Sambuc     fd = open(filename, O_RDWR | O_BINARY);
261ebfedea0SLionel Sambuc     if(fd < 0) {
262ebfedea0SLionel Sambuc 	if(errno == ENOENT)
263ebfedea0SLionel Sambuc 	    return 0;
264ebfedea0SLionel Sambuc 	else
265ebfedea0SLionel Sambuc 	    return errno;
266ebfedea0SLionel Sambuc     }
267ebfedea0SLionel Sambuc     rk_cloexec(fd);
268ebfedea0SLionel Sambuc     ret = _krb5_xlock(context, fd, 1, filename);
269ebfedea0SLionel Sambuc     if (ret) {
270ebfedea0SLionel Sambuc 	close(fd);
271ebfedea0SLionel Sambuc 	return ret;
272ebfedea0SLionel Sambuc     }
273ebfedea0SLionel Sambuc     if (unlink(filename) < 0) {
274ebfedea0SLionel Sambuc 	_krb5_xunlock(context, fd);
275ebfedea0SLionel Sambuc         close (fd);
276ebfedea0SLionel Sambuc         return errno;
277ebfedea0SLionel Sambuc     }
278ebfedea0SLionel Sambuc     ret = fstat (fd, &sb2);
279ebfedea0SLionel Sambuc     if (ret < 0) {
280ebfedea0SLionel Sambuc 	_krb5_xunlock(context, fd);
281ebfedea0SLionel Sambuc 	close (fd);
282ebfedea0SLionel Sambuc 	return errno;
283ebfedea0SLionel Sambuc     }
284ebfedea0SLionel Sambuc 
285ebfedea0SLionel Sambuc     /* check if someone was playing with symlinks */
286ebfedea0SLionel Sambuc 
287ebfedea0SLionel Sambuc     if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
288ebfedea0SLionel Sambuc 	_krb5_xunlock(context, fd);
289ebfedea0SLionel Sambuc 	close (fd);
290ebfedea0SLionel Sambuc 	return EPERM;
291ebfedea0SLionel Sambuc     }
292ebfedea0SLionel Sambuc 
293ebfedea0SLionel Sambuc     /* there are still hard links to this file */
294ebfedea0SLionel Sambuc 
295ebfedea0SLionel Sambuc     if (sb2.st_nlink != 0) {
296ebfedea0SLionel Sambuc 	_krb5_xunlock(context, fd);
297ebfedea0SLionel Sambuc         close (fd);
298ebfedea0SLionel Sambuc         return 0;
299ebfedea0SLionel Sambuc     }
300ebfedea0SLionel Sambuc 
301ebfedea0SLionel Sambuc     ret = scrub_file (fd);
302ebfedea0SLionel Sambuc     if (ret) {
303ebfedea0SLionel Sambuc 	_krb5_xunlock(context, fd);
304ebfedea0SLionel Sambuc 	close(fd);
305ebfedea0SLionel Sambuc 	return ret;
306ebfedea0SLionel Sambuc     }
307ebfedea0SLionel Sambuc     ret = _krb5_xunlock(context, fd);
308ebfedea0SLionel Sambuc     close (fd);
309ebfedea0SLionel Sambuc     return ret;
310ebfedea0SLionel Sambuc }
311ebfedea0SLionel Sambuc 
312ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_gen_new(krb5_context context,krb5_ccache * id)313ebfedea0SLionel Sambuc fcc_gen_new(krb5_context context, krb5_ccache *id)
314ebfedea0SLionel Sambuc {
315ebfedea0SLionel Sambuc     char *file = NULL, *exp_file = NULL;
316ebfedea0SLionel Sambuc     krb5_error_code ret;
317ebfedea0SLionel Sambuc     krb5_fcache *f;
318ebfedea0SLionel Sambuc     int fd;
319ebfedea0SLionel Sambuc 
320ebfedea0SLionel Sambuc     f = malloc(sizeof(*f));
321ebfedea0SLionel Sambuc     if(f == NULL) {
322ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_CC_NOMEM,
323ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
324ebfedea0SLionel Sambuc 	return KRB5_CC_NOMEM;
325ebfedea0SLionel Sambuc     }
326ebfedea0SLionel Sambuc     ret = asprintf (&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
327ebfedea0SLionel Sambuc     if(ret < 0 || file == NULL) {
328ebfedea0SLionel Sambuc 	free(f);
329ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_CC_NOMEM,
330ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
331ebfedea0SLionel Sambuc 	return KRB5_CC_NOMEM;
332ebfedea0SLionel Sambuc     }
333ebfedea0SLionel Sambuc     ret = _krb5_expand_path_tokens(context, file, &exp_file);
334ebfedea0SLionel Sambuc     free(file);
335ebfedea0SLionel Sambuc     if (ret)
336ebfedea0SLionel Sambuc 	return ret;
337ebfedea0SLionel Sambuc 
338ebfedea0SLionel Sambuc     file = exp_file;
339ebfedea0SLionel Sambuc 
340ebfedea0SLionel Sambuc     fd = mkstemp(exp_file);
341ebfedea0SLionel Sambuc     if(fd < 0) {
342*0a6a1f1dSLionel Sambuc 	int xret = errno;
343*0a6a1f1dSLionel Sambuc 	krb5_set_error_message(context, xret, N_("mkstemp %s failed", ""), exp_file);
344ebfedea0SLionel Sambuc 	free(f);
345ebfedea0SLionel Sambuc 	free(exp_file);
346*0a6a1f1dSLionel Sambuc 	return xret;
347ebfedea0SLionel Sambuc     }
348ebfedea0SLionel Sambuc     close(fd);
349ebfedea0SLionel Sambuc     f->filename = exp_file;
350ebfedea0SLionel Sambuc     f->version = 0;
351ebfedea0SLionel Sambuc     (*id)->data.data = f;
352ebfedea0SLionel Sambuc     (*id)->data.length = sizeof(*f);
353ebfedea0SLionel Sambuc     return 0;
354ebfedea0SLionel Sambuc }
355ebfedea0SLionel Sambuc 
356ebfedea0SLionel Sambuc static void
storage_set_flags(krb5_context context,krb5_storage * sp,int vno)357ebfedea0SLionel Sambuc storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
358ebfedea0SLionel Sambuc {
359ebfedea0SLionel Sambuc     int flags = 0;
360ebfedea0SLionel Sambuc     switch(vno) {
361ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_1:
362ebfedea0SLionel Sambuc 	flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
363ebfedea0SLionel Sambuc 	flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
364ebfedea0SLionel Sambuc 	flags |= KRB5_STORAGE_HOST_BYTEORDER;
365ebfedea0SLionel Sambuc 	break;
366ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_2:
367ebfedea0SLionel Sambuc 	flags |= KRB5_STORAGE_HOST_BYTEORDER;
368ebfedea0SLionel Sambuc 	break;
369ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_3:
370ebfedea0SLionel Sambuc 	flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE;
371ebfedea0SLionel Sambuc 	break;
372ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_4:
373ebfedea0SLionel Sambuc 	break;
374ebfedea0SLionel Sambuc     default:
375ebfedea0SLionel Sambuc 	krb5_abortx(context,
376ebfedea0SLionel Sambuc 		    "storage_set_flags called with bad vno (%x)", vno);
377ebfedea0SLionel Sambuc     }
378ebfedea0SLionel Sambuc     krb5_storage_set_flags(sp, flags);
379ebfedea0SLionel Sambuc }
380ebfedea0SLionel Sambuc 
381ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_open(krb5_context context,krb5_ccache id,int * fd_ret,int flags,mode_t mode)382ebfedea0SLionel Sambuc fcc_open(krb5_context context,
383ebfedea0SLionel Sambuc 	 krb5_ccache id,
384ebfedea0SLionel Sambuc 	 int *fd_ret,
385ebfedea0SLionel Sambuc 	 int flags,
386ebfedea0SLionel Sambuc 	 mode_t mode)
387ebfedea0SLionel Sambuc {
388ebfedea0SLionel Sambuc     krb5_boolean exclusive = ((flags | O_WRONLY) == flags ||
389ebfedea0SLionel Sambuc 			      (flags | O_RDWR) == flags);
390ebfedea0SLionel Sambuc     krb5_error_code ret;
391*0a6a1f1dSLionel Sambuc     const char *filename;
392ebfedea0SLionel Sambuc     int fd;
393*0a6a1f1dSLionel Sambuc 
394*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
395*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
396*0a6a1f1dSLionel Sambuc 
397*0a6a1f1dSLionel Sambuc     filename = FILENAME(id);
398*0a6a1f1dSLionel Sambuc 
399ebfedea0SLionel Sambuc     fd = open(filename, flags, mode);
400ebfedea0SLionel Sambuc     if(fd < 0) {
401ebfedea0SLionel Sambuc 	char buf[128];
402ebfedea0SLionel Sambuc 	ret = errno;
403ebfedea0SLionel Sambuc 	rk_strerror_r(ret, buf, sizeof(buf));
404ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, N_("open(%s): %s", "file, error"),
405ebfedea0SLionel Sambuc 			       filename, buf);
406ebfedea0SLionel Sambuc 	return ret;
407ebfedea0SLionel Sambuc     }
408ebfedea0SLionel Sambuc     rk_cloexec(fd);
409ebfedea0SLionel Sambuc 
410ebfedea0SLionel Sambuc     if((ret = fcc_lock(context, id, fd, exclusive)) != 0) {
411ebfedea0SLionel Sambuc 	close(fd);
412ebfedea0SLionel Sambuc 	return ret;
413ebfedea0SLionel Sambuc     }
414ebfedea0SLionel Sambuc     *fd_ret = fd;
415ebfedea0SLionel Sambuc     return 0;
416ebfedea0SLionel Sambuc }
417ebfedea0SLionel Sambuc 
418ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_initialize(krb5_context context,krb5_ccache id,krb5_principal primary_principal)419ebfedea0SLionel Sambuc fcc_initialize(krb5_context context,
420ebfedea0SLionel Sambuc 	       krb5_ccache id,
421ebfedea0SLionel Sambuc 	       krb5_principal primary_principal)
422ebfedea0SLionel Sambuc {
423ebfedea0SLionel Sambuc     krb5_fcache *f = FCACHE(id);
424ebfedea0SLionel Sambuc     int ret = 0;
425ebfedea0SLionel Sambuc     int fd;
426ebfedea0SLionel Sambuc 
427*0a6a1f1dSLionel Sambuc     if (f == NULL)
428*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
429*0a6a1f1dSLionel Sambuc 
430*0a6a1f1dSLionel Sambuc     unlink (f->filename);
431ebfedea0SLionel Sambuc 
432ebfedea0SLionel Sambuc     ret = fcc_open(context, id, &fd, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
433ebfedea0SLionel Sambuc     if(ret)
434ebfedea0SLionel Sambuc 	return ret;
435ebfedea0SLionel Sambuc     {
436ebfedea0SLionel Sambuc 	krb5_storage *sp;
437ebfedea0SLionel Sambuc 	sp = krb5_storage_emem();
438ebfedea0SLionel Sambuc 	krb5_storage_set_eof_code(sp, KRB5_CC_END);
439ebfedea0SLionel Sambuc 	if(context->fcache_vno != 0)
440ebfedea0SLionel Sambuc 	    f->version = context->fcache_vno;
441ebfedea0SLionel Sambuc 	else
442ebfedea0SLionel Sambuc 	    f->version = KRB5_FCC_FVNO_4;
443ebfedea0SLionel Sambuc 	ret |= krb5_store_int8(sp, 5);
444ebfedea0SLionel Sambuc 	ret |= krb5_store_int8(sp, f->version);
445ebfedea0SLionel Sambuc 	storage_set_flags(context, sp, f->version);
446ebfedea0SLionel Sambuc 	if(f->version == KRB5_FCC_FVNO_4 && ret == 0) {
447ebfedea0SLionel Sambuc 	    /* V4 stuff */
448ebfedea0SLionel Sambuc 	    if (context->kdc_sec_offset) {
449ebfedea0SLionel Sambuc 		ret |= krb5_store_int16 (sp, 12); /* length */
450ebfedea0SLionel Sambuc 		ret |= krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */
451ebfedea0SLionel Sambuc 		ret |= krb5_store_int16 (sp, 8); /* length of data */
452ebfedea0SLionel Sambuc 		ret |= krb5_store_int32 (sp, context->kdc_sec_offset);
453ebfedea0SLionel Sambuc 		ret |= krb5_store_int32 (sp, context->kdc_usec_offset);
454ebfedea0SLionel Sambuc 	    } else {
455ebfedea0SLionel Sambuc 		ret |= krb5_store_int16 (sp, 0);
456ebfedea0SLionel Sambuc 	    }
457ebfedea0SLionel Sambuc 	}
458ebfedea0SLionel Sambuc 	ret |= krb5_store_principal(sp, primary_principal);
459ebfedea0SLionel Sambuc 
460ebfedea0SLionel Sambuc 	ret |= write_storage(context, sp, fd);
461ebfedea0SLionel Sambuc 
462ebfedea0SLionel Sambuc 	krb5_storage_free(sp);
463ebfedea0SLionel Sambuc     }
464ebfedea0SLionel Sambuc     fcc_unlock(context, fd);
465ebfedea0SLionel Sambuc     if (close(fd) < 0)
466ebfedea0SLionel Sambuc 	if (ret == 0) {
467ebfedea0SLionel Sambuc 	    char buf[128];
468ebfedea0SLionel Sambuc 	    ret = errno;
469ebfedea0SLionel Sambuc 	    rk_strerror_r(ret, buf, sizeof(buf));
470ebfedea0SLionel Sambuc 	    krb5_set_error_message (context, ret, N_("close %s: %s", ""),
471ebfedea0SLionel Sambuc 				    FILENAME(id), buf);
472ebfedea0SLionel Sambuc 	}
473ebfedea0SLionel Sambuc     return ret;
474ebfedea0SLionel Sambuc }
475ebfedea0SLionel Sambuc 
476ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_close(krb5_context context,krb5_ccache id)477ebfedea0SLionel Sambuc fcc_close(krb5_context context,
478ebfedea0SLionel Sambuc 	  krb5_ccache id)
479ebfedea0SLionel Sambuc {
480*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
481*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
482*0a6a1f1dSLionel Sambuc 
483ebfedea0SLionel Sambuc     free (FILENAME(id));
484ebfedea0SLionel Sambuc     krb5_data_free(&id->data);
485ebfedea0SLionel Sambuc     return 0;
486ebfedea0SLionel Sambuc }
487ebfedea0SLionel Sambuc 
488ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_destroy(krb5_context context,krb5_ccache id)489ebfedea0SLionel Sambuc fcc_destroy(krb5_context context,
490ebfedea0SLionel Sambuc 	    krb5_ccache id)
491ebfedea0SLionel Sambuc {
492*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
493*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
494*0a6a1f1dSLionel Sambuc 
495ebfedea0SLionel Sambuc     _krb5_erase_file(context, FILENAME(id));
496ebfedea0SLionel Sambuc     return 0;
497ebfedea0SLionel Sambuc }
498ebfedea0SLionel Sambuc 
499ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)500ebfedea0SLionel Sambuc fcc_store_cred(krb5_context context,
501ebfedea0SLionel Sambuc 	       krb5_ccache id,
502ebfedea0SLionel Sambuc 	       krb5_creds *creds)
503ebfedea0SLionel Sambuc {
504ebfedea0SLionel Sambuc     int ret;
505ebfedea0SLionel Sambuc     int fd;
506ebfedea0SLionel Sambuc 
507ebfedea0SLionel Sambuc     ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY | O_CLOEXEC, 0);
508ebfedea0SLionel Sambuc     if(ret)
509ebfedea0SLionel Sambuc 	return ret;
510ebfedea0SLionel Sambuc     {
511ebfedea0SLionel Sambuc 	krb5_storage *sp;
512ebfedea0SLionel Sambuc 
513ebfedea0SLionel Sambuc 	sp = krb5_storage_emem();
514ebfedea0SLionel Sambuc 	krb5_storage_set_eof_code(sp, KRB5_CC_END);
515ebfedea0SLionel Sambuc 	storage_set_flags(context, sp, FCACHE(id)->version);
516ebfedea0SLionel Sambuc 	if (!krb5_config_get_bool_default(context, NULL, TRUE,
517ebfedea0SLionel Sambuc 					  "libdefaults",
518ebfedea0SLionel Sambuc 					  "fcc-mit-ticketflags",
519ebfedea0SLionel Sambuc 					  NULL))
520ebfedea0SLionel Sambuc 	    krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER);
521ebfedea0SLionel Sambuc 	ret = krb5_store_creds(sp, creds);
522ebfedea0SLionel Sambuc 	if (ret == 0)
523ebfedea0SLionel Sambuc 	    ret = write_storage(context, sp, fd);
524ebfedea0SLionel Sambuc 	krb5_storage_free(sp);
525ebfedea0SLionel Sambuc     }
526ebfedea0SLionel Sambuc     fcc_unlock(context, fd);
527ebfedea0SLionel Sambuc     if (close(fd) < 0) {
528ebfedea0SLionel Sambuc 	if (ret == 0) {
529ebfedea0SLionel Sambuc 	    char buf[128];
530ebfedea0SLionel Sambuc 	    rk_strerror_r(ret, buf, sizeof(buf));
531ebfedea0SLionel Sambuc 	    ret = errno;
532ebfedea0SLionel Sambuc 	    krb5_set_error_message (context, ret, N_("close %s: %s", ""),
533ebfedea0SLionel Sambuc 				    FILENAME(id), buf);
534ebfedea0SLionel Sambuc 	}
535ebfedea0SLionel Sambuc     }
536ebfedea0SLionel Sambuc     return ret;
537ebfedea0SLionel Sambuc }
538ebfedea0SLionel Sambuc 
539ebfedea0SLionel Sambuc static krb5_error_code
init_fcc(krb5_context context,krb5_ccache id,krb5_storage ** ret_sp,int * ret_fd,krb5_deltat * kdc_offset)540ebfedea0SLionel Sambuc init_fcc (krb5_context context,
541ebfedea0SLionel Sambuc 	  krb5_ccache id,
542ebfedea0SLionel Sambuc 	  krb5_storage **ret_sp,
543ebfedea0SLionel Sambuc 	  int *ret_fd,
544ebfedea0SLionel Sambuc 	  krb5_deltat *kdc_offset)
545ebfedea0SLionel Sambuc {
546ebfedea0SLionel Sambuc     int fd;
547ebfedea0SLionel Sambuc     int8_t pvno, tag;
548ebfedea0SLionel Sambuc     krb5_storage *sp;
549ebfedea0SLionel Sambuc     krb5_error_code ret;
550ebfedea0SLionel Sambuc 
551ebfedea0SLionel Sambuc     if (kdc_offset)
552ebfedea0SLionel Sambuc 	*kdc_offset = 0;
553ebfedea0SLionel Sambuc 
554ebfedea0SLionel Sambuc     ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
555ebfedea0SLionel Sambuc     if(ret)
556ebfedea0SLionel Sambuc 	return ret;
557ebfedea0SLionel Sambuc 
558ebfedea0SLionel Sambuc     sp = krb5_storage_from_fd(fd);
559ebfedea0SLionel Sambuc     if(sp == NULL) {
560ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
561ebfedea0SLionel Sambuc 	ret = ENOMEM;
562ebfedea0SLionel Sambuc 	goto out;
563ebfedea0SLionel Sambuc     }
564ebfedea0SLionel Sambuc     krb5_storage_set_eof_code(sp, KRB5_CC_END);
565ebfedea0SLionel Sambuc     ret = krb5_ret_int8(sp, &pvno);
566ebfedea0SLionel Sambuc     if(ret != 0) {
567ebfedea0SLionel Sambuc 	if(ret == KRB5_CC_END) {
568ebfedea0SLionel Sambuc 	    ret = ENOENT;
569ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
570ebfedea0SLionel Sambuc 				   N_("Empty credential cache file: %s", ""),
571ebfedea0SLionel Sambuc 				   FILENAME(id));
572ebfedea0SLionel Sambuc 	} else
573ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret, N_("Error reading pvno "
574ebfedea0SLionel Sambuc 						    "in cache file: %s", ""),
575ebfedea0SLionel Sambuc 				   FILENAME(id));
576ebfedea0SLionel Sambuc 	goto out;
577ebfedea0SLionel Sambuc     }
578ebfedea0SLionel Sambuc     if(pvno != 5) {
579ebfedea0SLionel Sambuc 	ret = KRB5_CCACHE_BADVNO;
580ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, N_("Bad version number in credential "
581ebfedea0SLionel Sambuc 						"cache file: %s", ""),
582ebfedea0SLionel Sambuc 			       FILENAME(id));
583ebfedea0SLionel Sambuc 	goto out;
584ebfedea0SLionel Sambuc     }
585ebfedea0SLionel Sambuc     ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */
586ebfedea0SLionel Sambuc     if(ret != 0) {
587ebfedea0SLionel Sambuc 	ret = KRB5_CC_FORMAT;
588ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, "Error reading tag in "
589ebfedea0SLionel Sambuc 			      "cache file: %s", FILENAME(id));
590ebfedea0SLionel Sambuc 	goto out;
591ebfedea0SLionel Sambuc     }
592ebfedea0SLionel Sambuc     FCACHE(id)->version = tag;
593ebfedea0SLionel Sambuc     storage_set_flags(context, sp, FCACHE(id)->version);
594ebfedea0SLionel Sambuc     switch (tag) {
595ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_4: {
596ebfedea0SLionel Sambuc 	int16_t length;
597ebfedea0SLionel Sambuc 
598ebfedea0SLionel Sambuc 	ret = krb5_ret_int16 (sp, &length);
599ebfedea0SLionel Sambuc 	if(ret) {
600ebfedea0SLionel Sambuc 	    ret = KRB5_CC_FORMAT;
601ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
602ebfedea0SLionel Sambuc 				   N_("Error reading tag length in "
603ebfedea0SLionel Sambuc 				      "cache file: %s", ""), FILENAME(id));
604ebfedea0SLionel Sambuc 	    goto out;
605ebfedea0SLionel Sambuc 	}
606ebfedea0SLionel Sambuc 	while(length > 0) {
607ebfedea0SLionel Sambuc 	    int16_t dtag, data_len;
608ebfedea0SLionel Sambuc 	    int i;
609ebfedea0SLionel Sambuc 	    int8_t dummy;
610ebfedea0SLionel Sambuc 
611ebfedea0SLionel Sambuc 	    ret = krb5_ret_int16 (sp, &dtag);
612ebfedea0SLionel Sambuc 	    if(ret) {
613ebfedea0SLionel Sambuc 		ret = KRB5_CC_FORMAT;
614ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret, N_("Error reading dtag in "
615ebfedea0SLionel Sambuc 							"cache file: %s", ""),
616ebfedea0SLionel Sambuc 				       FILENAME(id));
617ebfedea0SLionel Sambuc 		goto out;
618ebfedea0SLionel Sambuc 	    }
619ebfedea0SLionel Sambuc 	    ret = krb5_ret_int16 (sp, &data_len);
620ebfedea0SLionel Sambuc 	    if(ret) {
621ebfedea0SLionel Sambuc 		ret = KRB5_CC_FORMAT;
622ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
623ebfedea0SLionel Sambuc 				       N_("Error reading dlength "
624ebfedea0SLionel Sambuc 					  "in cache file: %s",""),
625ebfedea0SLionel Sambuc 				       FILENAME(id));
626ebfedea0SLionel Sambuc 		goto out;
627ebfedea0SLionel Sambuc 	    }
628ebfedea0SLionel Sambuc 	    switch (dtag) {
629ebfedea0SLionel Sambuc 	    case FCC_TAG_DELTATIME : {
630ebfedea0SLionel Sambuc 		int32_t offset;
631ebfedea0SLionel Sambuc 
632ebfedea0SLionel Sambuc 		ret = krb5_ret_int32 (sp, &offset);
633ebfedea0SLionel Sambuc 		ret |= krb5_ret_int32 (sp, &context->kdc_usec_offset);
634ebfedea0SLionel Sambuc 		if(ret) {
635ebfedea0SLionel Sambuc 		    ret = KRB5_CC_FORMAT;
636ebfedea0SLionel Sambuc 		    krb5_set_error_message(context, ret,
637ebfedea0SLionel Sambuc 					   N_("Error reading kdc_sec in "
638ebfedea0SLionel Sambuc 					      "cache file: %s", ""),
639ebfedea0SLionel Sambuc 					   FILENAME(id));
640ebfedea0SLionel Sambuc 		    goto out;
641ebfedea0SLionel Sambuc 		}
642ebfedea0SLionel Sambuc 		context->kdc_sec_offset = offset;
643ebfedea0SLionel Sambuc 		if (kdc_offset)
644ebfedea0SLionel Sambuc 		    *kdc_offset = offset;
645ebfedea0SLionel Sambuc 		break;
646ebfedea0SLionel Sambuc 	    }
647ebfedea0SLionel Sambuc 	    default :
648ebfedea0SLionel Sambuc 		for (i = 0; i < data_len; ++i) {
649ebfedea0SLionel Sambuc 		    ret = krb5_ret_int8 (sp, &dummy);
650ebfedea0SLionel Sambuc 		    if(ret) {
651ebfedea0SLionel Sambuc 			ret = KRB5_CC_FORMAT;
652ebfedea0SLionel Sambuc 			krb5_set_error_message(context, ret,
653ebfedea0SLionel Sambuc 					       N_("Error reading unknown "
654ebfedea0SLionel Sambuc 						  "tag in cache file: %s", ""),
655ebfedea0SLionel Sambuc 					       FILENAME(id));
656ebfedea0SLionel Sambuc 			goto out;
657ebfedea0SLionel Sambuc 		    }
658ebfedea0SLionel Sambuc 		}
659ebfedea0SLionel Sambuc 		break;
660ebfedea0SLionel Sambuc 	    }
661ebfedea0SLionel Sambuc 	    length -= 4 + data_len;
662ebfedea0SLionel Sambuc 	}
663ebfedea0SLionel Sambuc 	break;
664ebfedea0SLionel Sambuc     }
665ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_3:
666ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_2:
667ebfedea0SLionel Sambuc     case KRB5_FCC_FVNO_1:
668ebfedea0SLionel Sambuc 	break;
669ebfedea0SLionel Sambuc     default :
670ebfedea0SLionel Sambuc 	ret = KRB5_CCACHE_BADVNO;
671ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
672ebfedea0SLionel Sambuc 			       N_("Unknown version number (%d) in "
673ebfedea0SLionel Sambuc 				  "credential cache file: %s", ""),
674ebfedea0SLionel Sambuc 			       (int)tag, FILENAME(id));
675ebfedea0SLionel Sambuc 	goto out;
676ebfedea0SLionel Sambuc     }
677ebfedea0SLionel Sambuc     *ret_sp = sp;
678ebfedea0SLionel Sambuc     *ret_fd = fd;
679ebfedea0SLionel Sambuc 
680ebfedea0SLionel Sambuc     return 0;
681ebfedea0SLionel Sambuc   out:
682ebfedea0SLionel Sambuc     if(sp != NULL)
683ebfedea0SLionel Sambuc 	krb5_storage_free(sp);
684ebfedea0SLionel Sambuc     fcc_unlock(context, fd);
685ebfedea0SLionel Sambuc     close(fd);
686ebfedea0SLionel Sambuc     return ret;
687ebfedea0SLionel Sambuc }
688ebfedea0SLionel Sambuc 
689ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_principal(krb5_context context,krb5_ccache id,krb5_principal * principal)690ebfedea0SLionel Sambuc fcc_get_principal(krb5_context context,
691ebfedea0SLionel Sambuc 		  krb5_ccache id,
692ebfedea0SLionel Sambuc 		  krb5_principal *principal)
693ebfedea0SLionel Sambuc {
694ebfedea0SLionel Sambuc     krb5_error_code ret;
695ebfedea0SLionel Sambuc     int fd;
696ebfedea0SLionel Sambuc     krb5_storage *sp;
697ebfedea0SLionel Sambuc 
698ebfedea0SLionel Sambuc     ret = init_fcc (context, id, &sp, &fd, NULL);
699ebfedea0SLionel Sambuc     if (ret)
700ebfedea0SLionel Sambuc 	return ret;
701ebfedea0SLionel Sambuc     ret = krb5_ret_principal(sp, principal);
702ebfedea0SLionel Sambuc     if (ret)
703ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
704ebfedea0SLionel Sambuc     krb5_storage_free(sp);
705ebfedea0SLionel Sambuc     fcc_unlock(context, fd);
706ebfedea0SLionel Sambuc     close(fd);
707ebfedea0SLionel Sambuc     return ret;
708ebfedea0SLionel Sambuc }
709ebfedea0SLionel Sambuc 
710ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
711ebfedea0SLionel Sambuc fcc_end_get (krb5_context context,
712ebfedea0SLionel Sambuc 	     krb5_ccache id,
713ebfedea0SLionel Sambuc 	     krb5_cc_cursor *cursor);
714ebfedea0SLionel Sambuc 
715ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_first(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)716ebfedea0SLionel Sambuc fcc_get_first (krb5_context context,
717ebfedea0SLionel Sambuc 	       krb5_ccache id,
718ebfedea0SLionel Sambuc 	       krb5_cc_cursor *cursor)
719ebfedea0SLionel Sambuc {
720ebfedea0SLionel Sambuc     krb5_error_code ret;
721ebfedea0SLionel Sambuc     krb5_principal principal;
722ebfedea0SLionel Sambuc 
723*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
724*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
725*0a6a1f1dSLionel Sambuc 
726ebfedea0SLionel Sambuc     *cursor = malloc(sizeof(struct fcc_cursor));
727ebfedea0SLionel Sambuc     if (*cursor == NULL) {
728ebfedea0SLionel Sambuc         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
729ebfedea0SLionel Sambuc 	return ENOMEM;
730ebfedea0SLionel Sambuc     }
731ebfedea0SLionel Sambuc     memset(*cursor, 0, sizeof(struct fcc_cursor));
732ebfedea0SLionel Sambuc 
733ebfedea0SLionel Sambuc     ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp,
734ebfedea0SLionel Sambuc 		    &FCC_CURSOR(*cursor)->fd, NULL);
735ebfedea0SLionel Sambuc     if (ret) {
736ebfedea0SLionel Sambuc 	free(*cursor);
737ebfedea0SLionel Sambuc 	*cursor = NULL;
738ebfedea0SLionel Sambuc 	return ret;
739ebfedea0SLionel Sambuc     }
740ebfedea0SLionel Sambuc     ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
741ebfedea0SLionel Sambuc     if(ret) {
742ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
743ebfedea0SLionel Sambuc 	fcc_end_get(context, id, cursor);
744ebfedea0SLionel Sambuc 	return ret;
745ebfedea0SLionel Sambuc     }
746ebfedea0SLionel Sambuc     krb5_free_principal (context, principal);
747ebfedea0SLionel Sambuc     fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
748ebfedea0SLionel Sambuc     return 0;
749ebfedea0SLionel Sambuc }
750ebfedea0SLionel Sambuc 
751ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)752ebfedea0SLionel Sambuc fcc_get_next (krb5_context context,
753ebfedea0SLionel Sambuc 	      krb5_ccache id,
754ebfedea0SLionel Sambuc 	      krb5_cc_cursor *cursor,
755ebfedea0SLionel Sambuc 	      krb5_creds *creds)
756ebfedea0SLionel Sambuc {
757ebfedea0SLionel Sambuc     krb5_error_code ret;
758*0a6a1f1dSLionel Sambuc 
759*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
760*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
761*0a6a1f1dSLionel Sambuc 
762*0a6a1f1dSLionel Sambuc     if (FCC_CURSOR(*cursor) == NULL)
763*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 3);
764*0a6a1f1dSLionel Sambuc 
765ebfedea0SLionel Sambuc     if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
766ebfedea0SLionel Sambuc 	return ret;
767ebfedea0SLionel Sambuc 
768ebfedea0SLionel Sambuc     ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
769ebfedea0SLionel Sambuc     if (ret)
770ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
771ebfedea0SLionel Sambuc 
772ebfedea0SLionel Sambuc     fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
773ebfedea0SLionel Sambuc     return ret;
774ebfedea0SLionel Sambuc }
775ebfedea0SLionel Sambuc 
776ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_end_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)777ebfedea0SLionel Sambuc fcc_end_get (krb5_context context,
778ebfedea0SLionel Sambuc 	     krb5_ccache id,
779ebfedea0SLionel Sambuc 	     krb5_cc_cursor *cursor)
780ebfedea0SLionel Sambuc {
781*0a6a1f1dSLionel Sambuc 
782*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
783*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
784*0a6a1f1dSLionel Sambuc 
785*0a6a1f1dSLionel Sambuc     if (FCC_CURSOR(*cursor) == NULL)
786*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 3);
787*0a6a1f1dSLionel Sambuc 
788ebfedea0SLionel Sambuc     krb5_storage_free(FCC_CURSOR(*cursor)->sp);
789ebfedea0SLionel Sambuc     close (FCC_CURSOR(*cursor)->fd);
790ebfedea0SLionel Sambuc     free(*cursor);
791ebfedea0SLionel Sambuc     *cursor = NULL;
792ebfedea0SLionel Sambuc     return 0;
793ebfedea0SLionel Sambuc }
794ebfedea0SLionel Sambuc 
795ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * cred)796ebfedea0SLionel Sambuc fcc_remove_cred(krb5_context context,
797ebfedea0SLionel Sambuc 		 krb5_ccache id,
798ebfedea0SLionel Sambuc 		 krb5_flags which,
799ebfedea0SLionel Sambuc 		 krb5_creds *cred)
800ebfedea0SLionel Sambuc {
801ebfedea0SLionel Sambuc     krb5_error_code ret;
802ebfedea0SLionel Sambuc     krb5_ccache copy, newfile;
803ebfedea0SLionel Sambuc     char *newname = NULL;
804ebfedea0SLionel Sambuc     int fd;
805ebfedea0SLionel Sambuc 
806*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
807*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
808*0a6a1f1dSLionel Sambuc 
809ebfedea0SLionel Sambuc     ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &copy);
810ebfedea0SLionel Sambuc     if (ret)
811ebfedea0SLionel Sambuc 	return ret;
812ebfedea0SLionel Sambuc 
813ebfedea0SLionel Sambuc     ret = krb5_cc_copy_cache(context, id, copy);
814ebfedea0SLionel Sambuc     if (ret) {
815ebfedea0SLionel Sambuc 	krb5_cc_destroy(context, copy);
816ebfedea0SLionel Sambuc 	return ret;
817ebfedea0SLionel Sambuc     }
818ebfedea0SLionel Sambuc 
819ebfedea0SLionel Sambuc     ret = krb5_cc_remove_cred(context, copy, which, cred);
820ebfedea0SLionel Sambuc     if (ret) {
821ebfedea0SLionel Sambuc 	krb5_cc_destroy(context, copy);
822ebfedea0SLionel Sambuc 	return ret;
823ebfedea0SLionel Sambuc     }
824ebfedea0SLionel Sambuc 
825ebfedea0SLionel Sambuc     ret = asprintf(&newname, "FILE:%s.XXXXXX", FILENAME(id));
826ebfedea0SLionel Sambuc     if (ret < 0 || newname == NULL) {
827ebfedea0SLionel Sambuc 	krb5_cc_destroy(context, copy);
828ebfedea0SLionel Sambuc 	return ENOMEM;
829ebfedea0SLionel Sambuc     }
830ebfedea0SLionel Sambuc 
831ebfedea0SLionel Sambuc     fd = mkstemp(&newname[5]);
832ebfedea0SLionel Sambuc     if (fd < 0) {
833ebfedea0SLionel Sambuc 	ret = errno;
834ebfedea0SLionel Sambuc 	krb5_cc_destroy(context, copy);
835ebfedea0SLionel Sambuc 	return ret;
836ebfedea0SLionel Sambuc     }
837ebfedea0SLionel Sambuc     close(fd);
838ebfedea0SLionel Sambuc 
839ebfedea0SLionel Sambuc     ret = krb5_cc_resolve(context, newname, &newfile);
840ebfedea0SLionel Sambuc     if (ret) {
841ebfedea0SLionel Sambuc 	unlink(&newname[5]);
842ebfedea0SLionel Sambuc 	free(newname);
843ebfedea0SLionel Sambuc 	krb5_cc_destroy(context, copy);
844ebfedea0SLionel Sambuc 	return ret;
845ebfedea0SLionel Sambuc     }
846ebfedea0SLionel Sambuc 
847ebfedea0SLionel Sambuc     ret = krb5_cc_copy_cache(context, copy, newfile);
848ebfedea0SLionel Sambuc     krb5_cc_destroy(context, copy);
849ebfedea0SLionel Sambuc     if (ret) {
850ebfedea0SLionel Sambuc 	free(newname);
851ebfedea0SLionel Sambuc 	krb5_cc_destroy(context, newfile);
852ebfedea0SLionel Sambuc 	return ret;
853ebfedea0SLionel Sambuc     }
854ebfedea0SLionel Sambuc 
855ebfedea0SLionel Sambuc     ret = rk_rename(&newname[5], FILENAME(id));
856ebfedea0SLionel Sambuc     if (ret)
857ebfedea0SLionel Sambuc 	ret = errno;
858ebfedea0SLionel Sambuc     free(newname);
859ebfedea0SLionel Sambuc     krb5_cc_close(context, newfile);
860ebfedea0SLionel Sambuc 
861ebfedea0SLionel Sambuc     return ret;
862ebfedea0SLionel Sambuc }
863ebfedea0SLionel Sambuc 
864ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)865ebfedea0SLionel Sambuc fcc_set_flags(krb5_context context,
866ebfedea0SLionel Sambuc 	      krb5_ccache id,
867ebfedea0SLionel Sambuc 	      krb5_flags flags)
868ebfedea0SLionel Sambuc {
869*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
870*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
871*0a6a1f1dSLionel Sambuc 
872ebfedea0SLionel Sambuc     return 0; /* XXX */
873ebfedea0SLionel Sambuc }
874ebfedea0SLionel Sambuc 
875ebfedea0SLionel Sambuc static int KRB5_CALLCONV
fcc_get_version(krb5_context context,krb5_ccache id)876ebfedea0SLionel Sambuc fcc_get_version(krb5_context context,
877ebfedea0SLionel Sambuc 		krb5_ccache id)
878ebfedea0SLionel Sambuc {
879*0a6a1f1dSLionel Sambuc     if (FCACHE(id) == NULL)
880*0a6a1f1dSLionel Sambuc         return -1;
881*0a6a1f1dSLionel Sambuc 
882ebfedea0SLionel Sambuc     return FCACHE(id)->version;
883ebfedea0SLionel Sambuc }
884ebfedea0SLionel Sambuc 
885ebfedea0SLionel Sambuc struct fcache_iter {
886ebfedea0SLionel Sambuc     int first;
887ebfedea0SLionel Sambuc };
888ebfedea0SLionel Sambuc 
889ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_cache_first(krb5_context context,krb5_cc_cursor * cursor)890ebfedea0SLionel Sambuc fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
891ebfedea0SLionel Sambuc {
892ebfedea0SLionel Sambuc     struct fcache_iter *iter;
893ebfedea0SLionel Sambuc 
894ebfedea0SLionel Sambuc     iter = calloc(1, sizeof(*iter));
895ebfedea0SLionel Sambuc     if (iter == NULL) {
896ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
897ebfedea0SLionel Sambuc 	return ENOMEM;
898ebfedea0SLionel Sambuc     }
899ebfedea0SLionel Sambuc     iter->first = 1;
900ebfedea0SLionel Sambuc     *cursor = iter;
901ebfedea0SLionel Sambuc     return 0;
902ebfedea0SLionel Sambuc }
903ebfedea0SLionel Sambuc 
904ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_cache_next(krb5_context context,krb5_cc_cursor cursor,krb5_ccache * id)905ebfedea0SLionel Sambuc fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
906ebfedea0SLionel Sambuc {
907ebfedea0SLionel Sambuc     struct fcache_iter *iter = cursor;
908ebfedea0SLionel Sambuc     krb5_error_code ret;
909ebfedea0SLionel Sambuc     const char *fn;
910ebfedea0SLionel Sambuc     char *expandedfn = NULL;
911ebfedea0SLionel Sambuc 
912*0a6a1f1dSLionel Sambuc     if (iter == NULL)
913*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
914*0a6a1f1dSLionel Sambuc 
915ebfedea0SLionel Sambuc     if (!iter->first) {
916ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
917ebfedea0SLionel Sambuc 	return KRB5_CC_END;
918ebfedea0SLionel Sambuc     }
919ebfedea0SLionel Sambuc     iter->first = 0;
920ebfedea0SLionel Sambuc 
921ebfedea0SLionel Sambuc     fn = krb5_cc_default_name(context);
922ebfedea0SLionel Sambuc     if (fn == NULL || strncasecmp(fn, "FILE:", 5) != 0) {
923ebfedea0SLionel Sambuc 	ret = _krb5_expand_default_cc_name(context,
924ebfedea0SLionel Sambuc 					   KRB5_DEFAULT_CCNAME_FILE,
925ebfedea0SLionel Sambuc 					   &expandedfn);
926ebfedea0SLionel Sambuc 	if (ret)
927ebfedea0SLionel Sambuc 	    return ret;
928ebfedea0SLionel Sambuc 	fn = expandedfn;
929ebfedea0SLionel Sambuc     }
930ebfedea0SLionel Sambuc     /* check if file exists, don't return a non existant "next" */
931ebfedea0SLionel Sambuc     if (strncasecmp(fn, "FILE:", 5) == 0) {
932ebfedea0SLionel Sambuc 	struct stat sb;
933ebfedea0SLionel Sambuc 	ret = stat(fn + 5, &sb);
934ebfedea0SLionel Sambuc 	if (ret) {
935ebfedea0SLionel Sambuc 	    ret = KRB5_CC_END;
936ebfedea0SLionel Sambuc 	    goto out;
937ebfedea0SLionel Sambuc 	}
938ebfedea0SLionel Sambuc     }
939ebfedea0SLionel Sambuc     ret = krb5_cc_resolve(context, fn, id);
940ebfedea0SLionel Sambuc  out:
941ebfedea0SLionel Sambuc     if (expandedfn)
942ebfedea0SLionel Sambuc 	free(expandedfn);
943ebfedea0SLionel Sambuc 
944ebfedea0SLionel Sambuc     return ret;
945ebfedea0SLionel Sambuc }
946ebfedea0SLionel Sambuc 
947ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_end_cache_get(krb5_context context,krb5_cc_cursor cursor)948ebfedea0SLionel Sambuc fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
949ebfedea0SLionel Sambuc {
950ebfedea0SLionel Sambuc     struct fcache_iter *iter = cursor;
951*0a6a1f1dSLionel Sambuc 
952*0a6a1f1dSLionel Sambuc     if (iter == NULL)
953*0a6a1f1dSLionel Sambuc         return krb5_einval(context, 2);
954*0a6a1f1dSLionel Sambuc 
955ebfedea0SLionel Sambuc     free(iter);
956ebfedea0SLionel Sambuc     return 0;
957ebfedea0SLionel Sambuc }
958ebfedea0SLionel Sambuc 
959ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_move(krb5_context context,krb5_ccache from,krb5_ccache to)960ebfedea0SLionel Sambuc fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
961ebfedea0SLionel Sambuc {
962ebfedea0SLionel Sambuc     krb5_error_code ret = 0;
963ebfedea0SLionel Sambuc 
964ebfedea0SLionel Sambuc     ret = rk_rename(FILENAME(from), FILENAME(to));
965ebfedea0SLionel Sambuc 
966ebfedea0SLionel Sambuc     if (ret && errno != EXDEV) {
967ebfedea0SLionel Sambuc 	char buf[128];
968ebfedea0SLionel Sambuc 	ret = errno;
969ebfedea0SLionel Sambuc 	rk_strerror_r(ret, buf, sizeof(buf));
970ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
971ebfedea0SLionel Sambuc 			       N_("Rename of file from %s "
972ebfedea0SLionel Sambuc 				  "to %s failed: %s", ""),
973ebfedea0SLionel Sambuc 			       FILENAME(from), FILENAME(to), buf);
974ebfedea0SLionel Sambuc 	return ret;
975ebfedea0SLionel Sambuc     } else if (ret && errno == EXDEV) {
976ebfedea0SLionel Sambuc 	/* make a copy and delete the orignal */
977ebfedea0SLionel Sambuc 	krb5_ssize_t sz1, sz2;
978ebfedea0SLionel Sambuc 	int fd1, fd2;
979ebfedea0SLionel Sambuc 	char buf[BUFSIZ];
980ebfedea0SLionel Sambuc 
981ebfedea0SLionel Sambuc 	ret = fcc_open(context, from, &fd1, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
982ebfedea0SLionel Sambuc 	if(ret)
983ebfedea0SLionel Sambuc 	    return ret;
984ebfedea0SLionel Sambuc 
985ebfedea0SLionel Sambuc 	unlink(FILENAME(to));
986ebfedea0SLionel Sambuc 
987ebfedea0SLionel Sambuc 	ret = fcc_open(context, to, &fd2,
988ebfedea0SLionel Sambuc 		       O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
989ebfedea0SLionel Sambuc 	if(ret)
990ebfedea0SLionel Sambuc 	    goto out1;
991ebfedea0SLionel Sambuc 
992ebfedea0SLionel Sambuc 	while((sz1 = read(fd1, buf, sizeof(buf))) > 0) {
993ebfedea0SLionel Sambuc 	    sz2 = write(fd2, buf, sz1);
994ebfedea0SLionel Sambuc 	    if (sz1 != sz2) {
995ebfedea0SLionel Sambuc 		ret = EIO;
996ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
997ebfedea0SLionel Sambuc 				       N_("Failed to write data from one file "
998ebfedea0SLionel Sambuc 					  "credential cache to the other", ""));
999ebfedea0SLionel Sambuc 		goto out2;
1000ebfedea0SLionel Sambuc 	    }
1001ebfedea0SLionel Sambuc 	}
1002ebfedea0SLionel Sambuc 	if (sz1 < 0) {
1003ebfedea0SLionel Sambuc 	    ret = EIO;
1004ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1005ebfedea0SLionel Sambuc 				   N_("Failed to read data from one file "
1006ebfedea0SLionel Sambuc 				      "credential cache to the other", ""));
1007ebfedea0SLionel Sambuc 	    goto out2;
1008ebfedea0SLionel Sambuc 	}
1009ebfedea0SLionel Sambuc     out2:
1010ebfedea0SLionel Sambuc 	fcc_unlock(context, fd2);
1011ebfedea0SLionel Sambuc 	close(fd2);
1012ebfedea0SLionel Sambuc 
1013ebfedea0SLionel Sambuc     out1:
1014ebfedea0SLionel Sambuc 	fcc_unlock(context, fd1);
1015ebfedea0SLionel Sambuc 	close(fd1);
1016ebfedea0SLionel Sambuc 
1017ebfedea0SLionel Sambuc 	_krb5_erase_file(context, FILENAME(from));
1018ebfedea0SLionel Sambuc 
1019ebfedea0SLionel Sambuc 	if (ret) {
1020ebfedea0SLionel Sambuc 	    _krb5_erase_file(context, FILENAME(to));
1021ebfedea0SLionel Sambuc 	    return ret;
1022ebfedea0SLionel Sambuc 	}
1023ebfedea0SLionel Sambuc     }
1024ebfedea0SLionel Sambuc 
1025ebfedea0SLionel Sambuc     /* make sure ->version is uptodate */
1026ebfedea0SLionel Sambuc     {
1027ebfedea0SLionel Sambuc 	krb5_storage *sp;
1028ebfedea0SLionel Sambuc 	int fd;
1029ebfedea0SLionel Sambuc 	if ((ret = init_fcc (context, to, &sp, &fd, NULL)) == 0) {
1030ebfedea0SLionel Sambuc 	    if (sp)
1031ebfedea0SLionel Sambuc 		krb5_storage_free(sp);
1032ebfedea0SLionel Sambuc 	    fcc_unlock(context, fd);
1033ebfedea0SLionel Sambuc 	    close(fd);
1034ebfedea0SLionel Sambuc 	}
1035ebfedea0SLionel Sambuc     }
1036ebfedea0SLionel Sambuc 
1037ebfedea0SLionel Sambuc     fcc_close(context, from);
1038ebfedea0SLionel Sambuc 
1039ebfedea0SLionel Sambuc     return ret;
1040ebfedea0SLionel Sambuc }
1041ebfedea0SLionel Sambuc 
1042ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_default_name(krb5_context context,char ** str)1043ebfedea0SLionel Sambuc fcc_get_default_name(krb5_context context, char **str)
1044ebfedea0SLionel Sambuc {
1045ebfedea0SLionel Sambuc     return _krb5_expand_default_cc_name(context,
1046ebfedea0SLionel Sambuc 					KRB5_DEFAULT_CCNAME_FILE,
1047ebfedea0SLionel Sambuc 					str);
1048ebfedea0SLionel Sambuc }
1049ebfedea0SLionel Sambuc 
1050ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_lastchange(krb5_context context,krb5_ccache id,krb5_timestamp * mtime)1051ebfedea0SLionel Sambuc fcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
1052ebfedea0SLionel Sambuc {
1053ebfedea0SLionel Sambuc     krb5_error_code ret;
1054ebfedea0SLionel Sambuc     struct stat sb;
1055ebfedea0SLionel Sambuc     int fd;
1056ebfedea0SLionel Sambuc 
1057ebfedea0SLionel Sambuc     ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
1058ebfedea0SLionel Sambuc     if(ret)
1059ebfedea0SLionel Sambuc 	return ret;
1060ebfedea0SLionel Sambuc     ret = fstat(fd, &sb);
1061ebfedea0SLionel Sambuc     close(fd);
1062ebfedea0SLionel Sambuc     if (ret) {
1063ebfedea0SLionel Sambuc 	ret = errno;
1064ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, N_("Failed to stat cache file", ""));
1065ebfedea0SLionel Sambuc 	return ret;
1066ebfedea0SLionel Sambuc     }
1067ebfedea0SLionel Sambuc     *mtime = sb.st_mtime;
1068ebfedea0SLionel Sambuc     return 0;
1069ebfedea0SLionel Sambuc }
1070ebfedea0SLionel Sambuc 
1071ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_set_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat kdc_offset)1072ebfedea0SLionel Sambuc fcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
1073ebfedea0SLionel Sambuc {
1074ebfedea0SLionel Sambuc     return 0;
1075ebfedea0SLionel Sambuc }
1076ebfedea0SLionel Sambuc 
1077ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
fcc_get_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat * kdc_offset)1078ebfedea0SLionel Sambuc fcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
1079ebfedea0SLionel Sambuc {
1080ebfedea0SLionel Sambuc     krb5_error_code ret;
1081ebfedea0SLionel Sambuc     krb5_storage *sp = NULL;
1082ebfedea0SLionel Sambuc     int fd;
1083ebfedea0SLionel Sambuc     ret = init_fcc(context, id, &sp, &fd, kdc_offset);
1084ebfedea0SLionel Sambuc     if (sp)
1085ebfedea0SLionel Sambuc 	krb5_storage_free(sp);
1086ebfedea0SLionel Sambuc     fcc_unlock(context, fd);
1087ebfedea0SLionel Sambuc     close(fd);
1088ebfedea0SLionel Sambuc 
1089ebfedea0SLionel Sambuc     return ret;
1090ebfedea0SLionel Sambuc }
1091ebfedea0SLionel Sambuc 
1092ebfedea0SLionel Sambuc 
1093ebfedea0SLionel Sambuc /**
1094ebfedea0SLionel Sambuc  * Variable containing the FILE based credential cache implemention.
1095ebfedea0SLionel Sambuc  *
1096ebfedea0SLionel Sambuc  * @ingroup krb5_ccache
1097ebfedea0SLionel Sambuc  */
1098ebfedea0SLionel Sambuc 
1099ebfedea0SLionel Sambuc KRB5_LIB_VARIABLE const krb5_cc_ops krb5_fcc_ops = {
1100ebfedea0SLionel Sambuc     KRB5_CC_OPS_VERSION,
1101ebfedea0SLionel Sambuc     "FILE",
1102ebfedea0SLionel Sambuc     fcc_get_name,
1103ebfedea0SLionel Sambuc     fcc_resolve,
1104ebfedea0SLionel Sambuc     fcc_gen_new,
1105ebfedea0SLionel Sambuc     fcc_initialize,
1106ebfedea0SLionel Sambuc     fcc_destroy,
1107ebfedea0SLionel Sambuc     fcc_close,
1108ebfedea0SLionel Sambuc     fcc_store_cred,
1109ebfedea0SLionel Sambuc     NULL, /* fcc_retrieve */
1110ebfedea0SLionel Sambuc     fcc_get_principal,
1111ebfedea0SLionel Sambuc     fcc_get_first,
1112ebfedea0SLionel Sambuc     fcc_get_next,
1113ebfedea0SLionel Sambuc     fcc_end_get,
1114ebfedea0SLionel Sambuc     fcc_remove_cred,
1115ebfedea0SLionel Sambuc     fcc_set_flags,
1116ebfedea0SLionel Sambuc     fcc_get_version,
1117ebfedea0SLionel Sambuc     fcc_get_cache_first,
1118ebfedea0SLionel Sambuc     fcc_get_cache_next,
1119ebfedea0SLionel Sambuc     fcc_end_cache_get,
1120ebfedea0SLionel Sambuc     fcc_move,
1121ebfedea0SLionel Sambuc     fcc_get_default_name,
1122ebfedea0SLionel Sambuc     NULL,
1123ebfedea0SLionel Sambuc     fcc_lastchange,
1124ebfedea0SLionel Sambuc     fcc_set_kdc_offset,
1125ebfedea0SLionel Sambuc     fcc_get_kdc_offset
1126ebfedea0SLionel Sambuc };
1127