xref: /freebsd/crypto/heimdal/lib/krb5/fcache.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6*ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7*ae771770SStanislav Sedov  *
8b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
9b528cefcSMark Murray  * modification, are permitted provided that the following conditions
10b528cefcSMark Murray  * are met:
11b528cefcSMark Murray  *
12b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
13b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
14b528cefcSMark Murray  *
15b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
16b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
17b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
18b528cefcSMark Murray  *
19b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
20b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
21b528cefcSMark Murray  *    without specific prior written permission.
22b528cefcSMark Murray  *
23b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b528cefcSMark Murray  * SUCH DAMAGE.
34b528cefcSMark Murray  */
35b528cefcSMark Murray 
36b528cefcSMark Murray #include "krb5_locl.h"
37b528cefcSMark Murray 
38b528cefcSMark Murray typedef struct krb5_fcache{
39b528cefcSMark Murray     char *filename;
40b528cefcSMark Murray     int version;
41b528cefcSMark Murray }krb5_fcache;
42b528cefcSMark Murray 
43b528cefcSMark Murray struct fcc_cursor {
44b528cefcSMark Murray     int fd;
45b528cefcSMark Murray     krb5_storage *sp;
46b528cefcSMark Murray };
47b528cefcSMark Murray 
48b528cefcSMark Murray #define KRB5_FCC_FVNO_1 1
49b528cefcSMark Murray #define KRB5_FCC_FVNO_2 2
50b528cefcSMark Murray #define KRB5_FCC_FVNO_3 3
51b528cefcSMark Murray #define KRB5_FCC_FVNO_4 4
52b528cefcSMark Murray 
53b528cefcSMark Murray #define FCC_TAG_DELTATIME 1
54b528cefcSMark Murray 
55b528cefcSMark Murray #define FCACHE(X) ((krb5_fcache*)(X)->data.data)
56b528cefcSMark Murray 
57b528cefcSMark Murray #define FILENAME(X) (FCACHE(X)->filename)
58b528cefcSMark Murray 
59b528cefcSMark Murray #define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
60b528cefcSMark Murray 
61*ae771770SStanislav Sedov static const char* KRB5_CALLCONV
fcc_get_name(krb5_context context,krb5_ccache id)62b528cefcSMark Murray fcc_get_name(krb5_context context,
63b528cefcSMark Murray 	     krb5_ccache id)
64b528cefcSMark Murray {
65*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
66*ae771770SStanislav Sedov         return NULL;
67*ae771770SStanislav Sedov 
68b528cefcSMark Murray     return FILENAME(id);
69b528cefcSMark Murray }
70b528cefcSMark Murray 
711c43270aSJacques Vidrine int
_krb5_xlock(krb5_context context,int fd,krb5_boolean exclusive,const char * filename)721c43270aSJacques Vidrine _krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive,
731c43270aSJacques Vidrine 	    const char *filename)
741c43270aSJacques Vidrine {
751c43270aSJacques Vidrine     int ret;
761c43270aSJacques Vidrine #ifdef HAVE_FCNTL
771c43270aSJacques Vidrine     struct flock l;
781c43270aSJacques Vidrine 
791c43270aSJacques Vidrine     l.l_start = 0;
801c43270aSJacques Vidrine     l.l_len = 0;
811c43270aSJacques Vidrine     l.l_type = exclusive ? F_WRLCK : F_RDLCK;
821c43270aSJacques Vidrine     l.l_whence = SEEK_SET;
831c43270aSJacques Vidrine     ret = fcntl(fd, F_SETLKW, &l);
841c43270aSJacques Vidrine #else
851c43270aSJacques Vidrine     ret = flock(fd, exclusive ? LOCK_EX : LOCK_SH);
861c43270aSJacques Vidrine #endif
871c43270aSJacques Vidrine     if(ret < 0)
881c43270aSJacques Vidrine 	ret = errno;
891c43270aSJacques Vidrine     if(ret == EACCES) /* fcntl can return EACCES instead of EAGAIN */
901c43270aSJacques Vidrine 	ret = EAGAIN;
911c43270aSJacques Vidrine 
921c43270aSJacques Vidrine     switch (ret) {
931c43270aSJacques Vidrine     case 0:
941c43270aSJacques Vidrine 	break;
951c43270aSJacques Vidrine     case EINVAL: /* filesystem doesn't support locking, let the user have it */
961c43270aSJacques Vidrine 	ret = 0;
971c43270aSJacques Vidrine 	break;
981c43270aSJacques Vidrine     case EAGAIN:
99*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
100*ae771770SStanislav Sedov 			       N_("timed out locking cache file %s", "file"),
1011c43270aSJacques Vidrine 			       filename);
1021c43270aSJacques Vidrine 	break;
103*ae771770SStanislav Sedov     default: {
104*ae771770SStanislav Sedov 	char buf[128];
105*ae771770SStanislav Sedov 	rk_strerror_r(ret, buf, sizeof(buf));
106*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
107*ae771770SStanislav Sedov 			       N_("error locking cache file %s: %s",
108*ae771770SStanislav Sedov 				  "file, error"), filename, buf);
1091c43270aSJacques Vidrine 	break;
1101c43270aSJacques Vidrine     }
111*ae771770SStanislav Sedov     }
1121c43270aSJacques Vidrine     return ret;
1131c43270aSJacques Vidrine }
1141c43270aSJacques Vidrine 
1151c43270aSJacques Vidrine int
_krb5_xunlock(krb5_context context,int fd)116c19800e8SDoug Rabson _krb5_xunlock(krb5_context context, int fd)
1171c43270aSJacques Vidrine {
118c19800e8SDoug Rabson     int ret;
119c19800e8SDoug Rabson #ifdef HAVE_FCNTL
1201c43270aSJacques Vidrine     struct flock l;
1211c43270aSJacques Vidrine     l.l_start = 0;
1221c43270aSJacques Vidrine     l.l_len = 0;
1231c43270aSJacques Vidrine     l.l_type = F_UNLCK;
1241c43270aSJacques Vidrine     l.l_whence = SEEK_SET;
125c19800e8SDoug Rabson     ret = fcntl(fd, F_SETLKW, &l);
1261c43270aSJacques Vidrine #else
127c19800e8SDoug Rabson     ret = flock(fd, LOCK_UN);
1281c43270aSJacques Vidrine #endif
129c19800e8SDoug Rabson     if (ret < 0)
130c19800e8SDoug Rabson 	ret = errno;
131c19800e8SDoug Rabson     switch (ret) {
132c19800e8SDoug Rabson     case 0:
133c19800e8SDoug Rabson 	break;
134c19800e8SDoug Rabson     case EINVAL: /* filesystem doesn't support locking, let the user have it */
135c19800e8SDoug Rabson 	ret = 0;
136c19800e8SDoug Rabson 	break;
137*ae771770SStanislav Sedov     default: {
138*ae771770SStanislav Sedov 	char buf[128];
139*ae771770SStanislav Sedov 	rk_strerror_r(ret, buf, sizeof(buf));
140*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
141*ae771770SStanislav Sedov 			       N_("Failed to unlock file: %s", ""), buf);
142c19800e8SDoug Rabson 	break;
143c19800e8SDoug Rabson     }
144*ae771770SStanislav Sedov     }
145c19800e8SDoug Rabson     return ret;
1461c43270aSJacques Vidrine }
1471c43270aSJacques Vidrine 
1481c43270aSJacques Vidrine static krb5_error_code
write_storage(krb5_context context,krb5_storage * sp,int fd)149*ae771770SStanislav Sedov write_storage(krb5_context context, krb5_storage *sp, int fd)
150*ae771770SStanislav Sedov {
151*ae771770SStanislav Sedov     krb5_error_code ret;
152*ae771770SStanislav Sedov     krb5_data data;
153*ae771770SStanislav Sedov     ssize_t sret;
154*ae771770SStanislav Sedov 
155*ae771770SStanislav Sedov     ret = krb5_storage_to_data(sp, &data);
156*ae771770SStanislav Sedov     if (ret) {
157*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
158*ae771770SStanislav Sedov 	return ret;
159*ae771770SStanislav Sedov     }
160*ae771770SStanislav Sedov     sret = write(fd, data.data, data.length);
161*ae771770SStanislav Sedov     ret = (sret != (ssize_t)data.length);
162*ae771770SStanislav Sedov     krb5_data_free(&data);
163*ae771770SStanislav Sedov     if (ret) {
164*ae771770SStanislav Sedov 	ret = errno;
165*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
166*ae771770SStanislav Sedov 			       N_("Failed to write FILE credential data", ""));
167*ae771770SStanislav Sedov 	return ret;
168*ae771770SStanislav Sedov     }
169*ae771770SStanislav Sedov     return 0;
170*ae771770SStanislav Sedov }
171*ae771770SStanislav Sedov 
172*ae771770SStanislav Sedov 
173*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_lock(krb5_context context,krb5_ccache id,int fd,krb5_boolean exclusive)1741c43270aSJacques Vidrine fcc_lock(krb5_context context, krb5_ccache id,
1751c43270aSJacques Vidrine 	 int fd, krb5_boolean exclusive)
1761c43270aSJacques Vidrine {
1771c43270aSJacques Vidrine     return _krb5_xlock(context, fd, exclusive, fcc_get_name(context, id));
1781c43270aSJacques Vidrine }
1791c43270aSJacques Vidrine 
180*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_unlock(krb5_context context,int fd)1811c43270aSJacques Vidrine fcc_unlock(krb5_context context, int fd)
1821c43270aSJacques Vidrine {
183c19800e8SDoug Rabson     return _krb5_xunlock(context, fd);
1841c43270aSJacques Vidrine }
1851c43270aSJacques Vidrine 
186*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_resolve(krb5_context context,krb5_ccache * id,const char * res)187b528cefcSMark Murray fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
188b528cefcSMark Murray {
189b528cefcSMark Murray     krb5_fcache *f;
190b528cefcSMark Murray     f = malloc(sizeof(*f));
191adb0ddaeSAssar Westerlund     if(f == NULL) {
192*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
193*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
194b528cefcSMark Murray 	return KRB5_CC_NOMEM;
195adb0ddaeSAssar Westerlund     }
196b528cefcSMark Murray     f->filename = strdup(res);
197b528cefcSMark Murray     if(f->filename == NULL){
198b528cefcSMark Murray 	free(f);
199*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
200*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
201b528cefcSMark Murray 	return KRB5_CC_NOMEM;
202b528cefcSMark Murray     }
203b528cefcSMark Murray     f->version = 0;
204b528cefcSMark Murray     (*id)->data.data = f;
205b528cefcSMark Murray     (*id)->data.length = sizeof(*f);
206b528cefcSMark Murray     return 0;
207b528cefcSMark Murray }
208b528cefcSMark Murray 
2095e9cd1aeSAssar Westerlund /*
2105e9cd1aeSAssar Westerlund  * Try to scrub the contents of `filename' safely.
2115e9cd1aeSAssar Westerlund  */
2125e9cd1aeSAssar Westerlund 
2135e9cd1aeSAssar Westerlund static int
scrub_file(int fd)2145e9cd1aeSAssar Westerlund scrub_file (int fd)
2155e9cd1aeSAssar Westerlund {
2165e9cd1aeSAssar Westerlund     off_t pos;
2175e9cd1aeSAssar Westerlund     char buf[128];
2185e9cd1aeSAssar Westerlund 
2195e9cd1aeSAssar Westerlund     pos = lseek(fd, 0, SEEK_END);
2205e9cd1aeSAssar Westerlund     if (pos < 0)
2215e9cd1aeSAssar Westerlund         return errno;
2225e9cd1aeSAssar Westerlund     if (lseek(fd, 0, SEEK_SET) < 0)
2235e9cd1aeSAssar Westerlund         return errno;
2245e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
2255e9cd1aeSAssar Westerlund     while(pos > 0) {
226*ae771770SStanislav Sedov         ssize_t tmp = write(fd, buf, min((off_t)sizeof(buf), pos));
2275e9cd1aeSAssar Westerlund 
2285e9cd1aeSAssar Westerlund 	if (tmp < 0)
2295e9cd1aeSAssar Westerlund 	    return errno;
2305e9cd1aeSAssar Westerlund 	pos -= tmp;
2315e9cd1aeSAssar Westerlund     }
232*ae771770SStanislav Sedov #ifdef _MSC_VER
233*ae771770SStanislav Sedov     _commit (fd);
234*ae771770SStanislav Sedov #else
2355e9cd1aeSAssar Westerlund     fsync (fd);
236*ae771770SStanislav Sedov #endif
2375e9cd1aeSAssar Westerlund     return 0;
2385e9cd1aeSAssar Westerlund }
2395e9cd1aeSAssar Westerlund 
2405e9cd1aeSAssar Westerlund /*
2415e9cd1aeSAssar Westerlund  * Erase `filename' if it exists, trying to remove the contents if
2425e9cd1aeSAssar Westerlund  * it's `safe'.  We always try to remove the file, it it exists.  It's
2435e9cd1aeSAssar Westerlund  * only overwritten if it's a regular file (not a symlink and not a
2445e9cd1aeSAssar Westerlund  * hardlink)
2455e9cd1aeSAssar Westerlund  */
2465e9cd1aeSAssar Westerlund 
247*ae771770SStanislav Sedov krb5_error_code
_krb5_erase_file(krb5_context context,const char * filename)248*ae771770SStanislav Sedov _krb5_erase_file(krb5_context context, const char *filename)
249b528cefcSMark Murray {
250b528cefcSMark Murray     int fd;
2515e9cd1aeSAssar Westerlund     struct stat sb1, sb2;
2525e9cd1aeSAssar Westerlund     int ret;
2535e9cd1aeSAssar Westerlund 
2545e9cd1aeSAssar Westerlund     ret = lstat (filename, &sb1);
2555e9cd1aeSAssar Westerlund     if (ret < 0)
2565e9cd1aeSAssar Westerlund 	return errno;
257b528cefcSMark Murray 
258b528cefcSMark Murray     fd = open(filename, O_RDWR | O_BINARY);
259b528cefcSMark Murray     if(fd < 0) {
260b528cefcSMark Murray 	if(errno == ENOENT)
261b528cefcSMark Murray 	    return 0;
262b528cefcSMark Murray 	else
263b528cefcSMark Murray 	    return errno;
264b528cefcSMark Murray     }
265*ae771770SStanislav Sedov     rk_cloexec(fd);
266*ae771770SStanislav Sedov     ret = _krb5_xlock(context, fd, 1, filename);
267*ae771770SStanislav Sedov     if (ret) {
268*ae771770SStanislav Sedov 	close(fd);
269*ae771770SStanislav Sedov 	return ret;
270*ae771770SStanislav Sedov     }
2715e9cd1aeSAssar Westerlund     if (unlink(filename) < 0) {
272*ae771770SStanislav Sedov 	_krb5_xunlock(context, fd);
273b528cefcSMark Murray         close (fd);
2745e9cd1aeSAssar Westerlund         return errno;
2755e9cd1aeSAssar Westerlund     }
2765e9cd1aeSAssar Westerlund     ret = fstat (fd, &sb2);
2775e9cd1aeSAssar Westerlund     if (ret < 0) {
278*ae771770SStanislav Sedov 	_krb5_xunlock(context, fd);
2795e9cd1aeSAssar Westerlund 	close (fd);
2805e9cd1aeSAssar Westerlund 	return errno;
2815e9cd1aeSAssar Westerlund     }
2825e9cd1aeSAssar Westerlund 
2835e9cd1aeSAssar Westerlund     /* check if someone was playing with symlinks */
2845e9cd1aeSAssar Westerlund 
2855e9cd1aeSAssar Westerlund     if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
286*ae771770SStanislav Sedov 	_krb5_xunlock(context, fd);
2875e9cd1aeSAssar Westerlund 	close (fd);
2885e9cd1aeSAssar Westerlund 	return EPERM;
2895e9cd1aeSAssar Westerlund     }
2905e9cd1aeSAssar Westerlund 
2915e9cd1aeSAssar Westerlund     /* there are still hard links to this file */
2925e9cd1aeSAssar Westerlund 
2935e9cd1aeSAssar Westerlund     if (sb2.st_nlink != 0) {
294*ae771770SStanislav Sedov 	_krb5_xunlock(context, fd);
2955e9cd1aeSAssar Westerlund         close (fd);
296b528cefcSMark Murray         return 0;
297b528cefcSMark Murray     }
298b528cefcSMark Murray 
2995e9cd1aeSAssar Westerlund     ret = scrub_file (fd);
300*ae771770SStanislav Sedov     if (ret) {
301*ae771770SStanislav Sedov 	_krb5_xunlock(context, fd);
302*ae771770SStanislav Sedov 	close(fd);
303*ae771770SStanislav Sedov 	return ret;
304*ae771770SStanislav Sedov     }
305*ae771770SStanislav Sedov     ret = _krb5_xunlock(context, fd);
3065e9cd1aeSAssar Westerlund     close (fd);
3075e9cd1aeSAssar Westerlund     return ret;
3085e9cd1aeSAssar Westerlund }
3095e9cd1aeSAssar Westerlund 
310*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_gen_new(krb5_context context,krb5_ccache * id)311b528cefcSMark Murray fcc_gen_new(krb5_context context, krb5_ccache *id)
312b528cefcSMark Murray {
313*ae771770SStanislav Sedov     char *file = NULL, *exp_file = NULL;
314*ae771770SStanislav Sedov     krb5_error_code ret;
315b528cefcSMark Murray     krb5_fcache *f;
316b528cefcSMark Murray     int fd;
317adb0ddaeSAssar Westerlund 
318b528cefcSMark Murray     f = malloc(sizeof(*f));
319adb0ddaeSAssar Westerlund     if(f == NULL) {
320*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
321*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
322b528cefcSMark Murray 	return KRB5_CC_NOMEM;
323adb0ddaeSAssar Westerlund     }
324*ae771770SStanislav Sedov     ret = asprintf (&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
325*ae771770SStanislav Sedov     if(ret < 0 || file == NULL) {
326b528cefcSMark Murray 	free(f);
327*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_CC_NOMEM,
328*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
329b528cefcSMark Murray 	return KRB5_CC_NOMEM;
330b528cefcSMark Murray     }
331*ae771770SStanislav Sedov     ret = _krb5_expand_path_tokens(context, file, &exp_file);
332b528cefcSMark Murray     free(file);
333*ae771770SStanislav Sedov     if (ret)
334c19800e8SDoug Rabson 	return ret;
335*ae771770SStanislav Sedov 
336*ae771770SStanislav Sedov     file = exp_file;
337*ae771770SStanislav Sedov 
338*ae771770SStanislav Sedov     fd = mkstemp(exp_file);
339*ae771770SStanislav Sedov     if(fd < 0) {
340*ae771770SStanislav Sedov 	int xret = errno;
341*ae771770SStanislav Sedov 	krb5_set_error_message(context, xret, N_("mkstemp %s failed", ""), exp_file);
342*ae771770SStanislav Sedov 	free(f);
343*ae771770SStanislav Sedov 	free(exp_file);
344*ae771770SStanislav Sedov 	return xret;
345b528cefcSMark Murray     }
346b528cefcSMark Murray     close(fd);
347*ae771770SStanislav Sedov     f->filename = exp_file;
348b528cefcSMark Murray     f->version = 0;
349b528cefcSMark Murray     (*id)->data.data = f;
350b528cefcSMark Murray     (*id)->data.length = sizeof(*f);
351b528cefcSMark Murray     return 0;
352b528cefcSMark Murray }
353b528cefcSMark Murray 
354b528cefcSMark Murray static void
storage_set_flags(krb5_context context,krb5_storage * sp,int vno)355b528cefcSMark Murray storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
356b528cefcSMark Murray {
357b528cefcSMark Murray     int flags = 0;
358b528cefcSMark Murray     switch(vno) {
359b528cefcSMark Murray     case KRB5_FCC_FVNO_1:
360b528cefcSMark Murray 	flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
361b528cefcSMark Murray 	flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
362b528cefcSMark Murray 	flags |= KRB5_STORAGE_HOST_BYTEORDER;
363b528cefcSMark Murray 	break;
364b528cefcSMark Murray     case KRB5_FCC_FVNO_2:
365b528cefcSMark Murray 	flags |= KRB5_STORAGE_HOST_BYTEORDER;
366b528cefcSMark Murray 	break;
367b528cefcSMark Murray     case KRB5_FCC_FVNO_3:
368b528cefcSMark Murray 	flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE;
369b528cefcSMark Murray 	break;
370b528cefcSMark Murray     case KRB5_FCC_FVNO_4:
371b528cefcSMark Murray 	break;
372b528cefcSMark Murray     default:
373b528cefcSMark Murray 	krb5_abortx(context,
374b528cefcSMark Murray 		    "storage_set_flags called with bad vno (%x)", vno);
375b528cefcSMark Murray     }
376b528cefcSMark Murray     krb5_storage_set_flags(sp, flags);
377b528cefcSMark Murray }
378b528cefcSMark Murray 
379*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_open(krb5_context context,krb5_ccache id,int * fd_ret,int flags,mode_t mode)3801c43270aSJacques Vidrine fcc_open(krb5_context context,
3811c43270aSJacques Vidrine 	 krb5_ccache id,
3821c43270aSJacques Vidrine 	 int *fd_ret,
3831c43270aSJacques Vidrine 	 int flags,
3841c43270aSJacques Vidrine 	 mode_t mode)
3851c43270aSJacques Vidrine {
3861c43270aSJacques Vidrine     krb5_boolean exclusive = ((flags | O_WRONLY) == flags ||
3871c43270aSJacques Vidrine 			      (flags | O_RDWR) == flags);
3881c43270aSJacques Vidrine     krb5_error_code ret;
389*ae771770SStanislav Sedov     const char *filename;
3901c43270aSJacques Vidrine     int fd;
391*ae771770SStanislav Sedov 
392*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
393*ae771770SStanislav Sedov         return krb5_einval(context, 2);
394*ae771770SStanislav Sedov 
395*ae771770SStanislav Sedov     filename = FILENAME(id);
396*ae771770SStanislav Sedov 
3971c43270aSJacques Vidrine     fd = open(filename, flags, mode);
3981c43270aSJacques Vidrine     if(fd < 0) {
399*ae771770SStanislav Sedov 	char buf[128];
4001c43270aSJacques Vidrine 	ret = errno;
401*ae771770SStanislav Sedov 	rk_strerror_r(ret, buf, sizeof(buf));
402*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("open(%s): %s", "file, error"),
403*ae771770SStanislav Sedov 			       filename, buf);
4041c43270aSJacques Vidrine 	return ret;
4051c43270aSJacques Vidrine     }
406*ae771770SStanislav Sedov     rk_cloexec(fd);
4071c43270aSJacques Vidrine 
4081c43270aSJacques Vidrine     if((ret = fcc_lock(context, id, fd, exclusive)) != 0) {
4091c43270aSJacques Vidrine 	close(fd);
4101c43270aSJacques Vidrine 	return ret;
4111c43270aSJacques Vidrine     }
4121c43270aSJacques Vidrine     *fd_ret = fd;
4131c43270aSJacques Vidrine     return 0;
4141c43270aSJacques Vidrine }
4151c43270aSJacques Vidrine 
416*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_initialize(krb5_context context,krb5_ccache id,krb5_principal primary_principal)417b528cefcSMark Murray fcc_initialize(krb5_context context,
418b528cefcSMark Murray 	       krb5_ccache id,
419b528cefcSMark Murray 	       krb5_principal primary_principal)
420b528cefcSMark Murray {
421b528cefcSMark Murray     krb5_fcache *f = FCACHE(id);
4225e9cd1aeSAssar Westerlund     int ret = 0;
423b528cefcSMark Murray     int fd;
424b528cefcSMark Murray 
425*ae771770SStanislav Sedov     if (f == NULL)
426*ae771770SStanislav Sedov         return krb5_einval(context, 2);
427b528cefcSMark Murray 
428*ae771770SStanislav Sedov     unlink (f->filename);
429*ae771770SStanislav Sedov 
430*ae771770SStanislav Sedov     ret = fcc_open(context, id, &fd, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
4311c43270aSJacques Vidrine     if(ret)
432adb0ddaeSAssar Westerlund 	return ret;
433b528cefcSMark Murray     {
434b528cefcSMark Murray 	krb5_storage *sp;
435*ae771770SStanislav Sedov 	sp = krb5_storage_emem();
4368373020dSJacques Vidrine 	krb5_storage_set_eof_code(sp, KRB5_CC_END);
437b528cefcSMark Murray 	if(context->fcache_vno != 0)
438b528cefcSMark Murray 	    f->version = context->fcache_vno;
439b528cefcSMark Murray 	else
440b528cefcSMark Murray 	    f->version = KRB5_FCC_FVNO_4;
4415e9cd1aeSAssar Westerlund 	ret |= krb5_store_int8(sp, 5);
4425e9cd1aeSAssar Westerlund 	ret |= krb5_store_int8(sp, f->version);
443b528cefcSMark Murray 	storage_set_flags(context, sp, f->version);
4445e9cd1aeSAssar Westerlund 	if(f->version == KRB5_FCC_FVNO_4 && ret == 0) {
445b528cefcSMark Murray 	    /* V4 stuff */
446b528cefcSMark Murray 	    if (context->kdc_sec_offset) {
4475e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, 12); /* length */
4485e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */
4495e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, 8); /* length of data */
4505e9cd1aeSAssar Westerlund 		ret |= krb5_store_int32 (sp, context->kdc_sec_offset);
4515e9cd1aeSAssar Westerlund 		ret |= krb5_store_int32 (sp, context->kdc_usec_offset);
452b528cefcSMark Murray 	    } else {
4535e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, 0);
454b528cefcSMark Murray 	    }
455b528cefcSMark Murray 	}
4565e9cd1aeSAssar Westerlund 	ret |= krb5_store_principal(sp, primary_principal);
4571c43270aSJacques Vidrine 
458*ae771770SStanislav Sedov 	ret |= write_storage(context, sp, fd);
459*ae771770SStanislav Sedov 
460b528cefcSMark Murray 	krb5_storage_free(sp);
461b528cefcSMark Murray     }
4621c43270aSJacques Vidrine     fcc_unlock(context, fd);
4635e9cd1aeSAssar Westerlund     if (close(fd) < 0)
464adb0ddaeSAssar Westerlund 	if (ret == 0) {
465*ae771770SStanislav Sedov 	    char buf[128];
4665e9cd1aeSAssar Westerlund 	    ret = errno;
467*ae771770SStanislav Sedov 	    rk_strerror_r(ret, buf, sizeof(buf));
468*ae771770SStanislav Sedov 	    krb5_set_error_message (context, ret, N_("close %s: %s", ""),
469*ae771770SStanislav Sedov 				    FILENAME(id), buf);
470adb0ddaeSAssar Westerlund 	}
4715e9cd1aeSAssar Westerlund     return ret;
472b528cefcSMark Murray }
473b528cefcSMark Murray 
474*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_close(krb5_context context,krb5_ccache id)475b528cefcSMark Murray fcc_close(krb5_context context,
476b528cefcSMark Murray 	  krb5_ccache id)
477b528cefcSMark Murray {
478*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
479*ae771770SStanislav Sedov         return krb5_einval(context, 2);
480*ae771770SStanislav Sedov 
481b528cefcSMark Murray     free (FILENAME(id));
482b528cefcSMark Murray     krb5_data_free(&id->data);
483b528cefcSMark Murray     return 0;
484b528cefcSMark Murray }
485b528cefcSMark Murray 
486*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_destroy(krb5_context context,krb5_ccache id)487b528cefcSMark Murray fcc_destroy(krb5_context context,
488b528cefcSMark Murray 	    krb5_ccache id)
489b528cefcSMark Murray {
490*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
491*ae771770SStanislav Sedov         return krb5_einval(context, 2);
492*ae771770SStanislav Sedov 
493*ae771770SStanislav Sedov     _krb5_erase_file(context, FILENAME(id));
494b528cefcSMark Murray     return 0;
495b528cefcSMark Murray }
496b528cefcSMark Murray 
497*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)498b528cefcSMark Murray fcc_store_cred(krb5_context context,
499b528cefcSMark Murray 	       krb5_ccache id,
500b528cefcSMark Murray 	       krb5_creds *creds)
501b528cefcSMark Murray {
5025e9cd1aeSAssar Westerlund     int ret;
503b528cefcSMark Murray     int fd;
504b528cefcSMark Murray 
505*ae771770SStanislav Sedov     ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY | O_CLOEXEC, 0);
5061c43270aSJacques Vidrine     if(ret)
507adb0ddaeSAssar Westerlund 	return ret;
508b528cefcSMark Murray     {
509b528cefcSMark Murray 	krb5_storage *sp;
510*ae771770SStanislav Sedov 
511*ae771770SStanislav Sedov 	sp = krb5_storage_emem();
5128373020dSJacques Vidrine 	krb5_storage_set_eof_code(sp, KRB5_CC_END);
513b528cefcSMark Murray 	storage_set_flags(context, sp, FCACHE(id)->version);
514c19800e8SDoug Rabson 	if (!krb5_config_get_bool_default(context, NULL, TRUE,
5151c43270aSJacques Vidrine 					  "libdefaults",
5161c43270aSJacques Vidrine 					  "fcc-mit-ticketflags",
5171c43270aSJacques Vidrine 					  NULL))
518c19800e8SDoug Rabson 	    krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER);
519c19800e8SDoug Rabson 	ret = krb5_store_creds(sp, creds);
520*ae771770SStanislav Sedov 	if (ret == 0)
521*ae771770SStanislav Sedov 	    ret = write_storage(context, sp, fd);
522b528cefcSMark Murray 	krb5_storage_free(sp);
523b528cefcSMark Murray     }
5241c43270aSJacques Vidrine     fcc_unlock(context, fd);
525*ae771770SStanislav Sedov     if (close(fd) < 0) {
526adb0ddaeSAssar Westerlund 	if (ret == 0) {
527*ae771770SStanislav Sedov 	    char buf[128];
528*ae771770SStanislav Sedov 	    rk_strerror_r(ret, buf, sizeof(buf));
5295e9cd1aeSAssar Westerlund 	    ret = errno;
530*ae771770SStanislav Sedov 	    krb5_set_error_message (context, ret, N_("close %s: %s", ""),
531*ae771770SStanislav Sedov 				    FILENAME(id), buf);
532*ae771770SStanislav Sedov 	}
533adb0ddaeSAssar Westerlund     }
5345e9cd1aeSAssar Westerlund     return ret;
535b528cefcSMark Murray }
536b528cefcSMark Murray 
537b528cefcSMark Murray static krb5_error_code
init_fcc(krb5_context context,krb5_ccache id,krb5_storage ** ret_sp,int * ret_fd,krb5_deltat * kdc_offset)538b528cefcSMark Murray init_fcc (krb5_context context,
5391c43270aSJacques Vidrine 	  krb5_ccache id,
540b528cefcSMark Murray 	  krb5_storage **ret_sp,
541*ae771770SStanislav Sedov 	  int *ret_fd,
542*ae771770SStanislav Sedov 	  krb5_deltat *kdc_offset)
543b528cefcSMark Murray {
544b528cefcSMark Murray     int fd;
545b528cefcSMark Murray     int8_t pvno, tag;
546b528cefcSMark Murray     krb5_storage *sp;
5475e9cd1aeSAssar Westerlund     krb5_error_code ret;
548b528cefcSMark Murray 
549*ae771770SStanislav Sedov     if (kdc_offset)
550*ae771770SStanislav Sedov 	*kdc_offset = 0;
551*ae771770SStanislav Sedov 
552*ae771770SStanislav Sedov     ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
5535e9cd1aeSAssar Westerlund     if(ret)
5545e9cd1aeSAssar Westerlund 	return ret;
5551c43270aSJacques Vidrine 
5561c43270aSJacques Vidrine     sp = krb5_storage_from_fd(fd);
5571c43270aSJacques Vidrine     if(sp == NULL) {
558*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
5591c43270aSJacques Vidrine 	ret = ENOMEM;
5601c43270aSJacques Vidrine 	goto out;
561b528cefcSMark Murray     }
5621c43270aSJacques Vidrine     krb5_storage_set_eof_code(sp, KRB5_CC_END);
5631c43270aSJacques Vidrine     ret = krb5_ret_int8(sp, &pvno);
5641c43270aSJacques Vidrine     if(ret != 0) {
565c19800e8SDoug Rabson 	if(ret == KRB5_CC_END) {
566c19800e8SDoug Rabson 	    ret = ENOENT;
567*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
568*ae771770SStanislav Sedov 				   N_("Empty credential cache file: %s", ""),
569*ae771770SStanislav Sedov 				   FILENAME(id));
570c19800e8SDoug Rabson 	} else
571*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, N_("Error reading pvno "
572*ae771770SStanislav Sedov 						    "in cache file: %s", ""),
573*ae771770SStanislav Sedov 				   FILENAME(id));
5741c43270aSJacques Vidrine 	goto out;
5751c43270aSJacques Vidrine     }
5761c43270aSJacques Vidrine     if(pvno != 5) {
5771c43270aSJacques Vidrine 	ret = KRB5_CCACHE_BADVNO;
578*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("Bad version number in credential "
579*ae771770SStanislav Sedov 						"cache file: %s", ""),
580*ae771770SStanislav Sedov 			       FILENAME(id));
5811c43270aSJacques Vidrine 	goto out;
5821c43270aSJacques Vidrine     }
5831c43270aSJacques Vidrine     ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */
5841c43270aSJacques Vidrine     if(ret != 0) {
5851c43270aSJacques Vidrine 	ret = KRB5_CC_FORMAT;
586*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "Error reading tag in "
587*ae771770SStanislav Sedov 			      "cache file: %s", FILENAME(id));
5881c43270aSJacques Vidrine 	goto out;
5891c43270aSJacques Vidrine     }
5901c43270aSJacques Vidrine     FCACHE(id)->version = tag;
5911c43270aSJacques Vidrine     storage_set_flags(context, sp, FCACHE(id)->version);
592b528cefcSMark Murray     switch (tag) {
593b528cefcSMark Murray     case KRB5_FCC_FVNO_4: {
594b528cefcSMark Murray 	int16_t length;
595b528cefcSMark Murray 
5961c43270aSJacques Vidrine 	ret = krb5_ret_int16 (sp, &length);
5971c43270aSJacques Vidrine 	if(ret) {
5981c43270aSJacques Vidrine 	    ret = KRB5_CC_FORMAT;
599*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
600*ae771770SStanislav Sedov 				   N_("Error reading tag length in "
601*ae771770SStanislav Sedov 				      "cache file: %s", ""), FILENAME(id));
6021c43270aSJacques Vidrine 	    goto out;
6031c43270aSJacques Vidrine 	}
604b528cefcSMark Murray 	while(length > 0) {
605c19800e8SDoug Rabson 	    int16_t dtag, data_len;
606b528cefcSMark Murray 	    int i;
607b528cefcSMark Murray 	    int8_t dummy;
608b528cefcSMark Murray 
609c19800e8SDoug Rabson 	    ret = krb5_ret_int16 (sp, &dtag);
6101c43270aSJacques Vidrine 	    if(ret) {
6111c43270aSJacques Vidrine 		ret = KRB5_CC_FORMAT;
612*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, N_("Error reading dtag in "
613*ae771770SStanislav Sedov 							"cache file: %s", ""),
614*ae771770SStanislav Sedov 				       FILENAME(id));
6151c43270aSJacques Vidrine 		goto out;
6161c43270aSJacques Vidrine 	    }
6171c43270aSJacques Vidrine 	    ret = krb5_ret_int16 (sp, &data_len);
6181c43270aSJacques Vidrine 	    if(ret) {
6191c43270aSJacques Vidrine 		ret = KRB5_CC_FORMAT;
620*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
621*ae771770SStanislav Sedov 				       N_("Error reading dlength "
622*ae771770SStanislav Sedov 					  "in cache file: %s",""),
623*ae771770SStanislav Sedov 				       FILENAME(id));
6241c43270aSJacques Vidrine 		goto out;
6251c43270aSJacques Vidrine 	    }
626c19800e8SDoug Rabson 	    switch (dtag) {
627*ae771770SStanislav Sedov 	    case FCC_TAG_DELTATIME : {
628*ae771770SStanislav Sedov 		int32_t offset;
629*ae771770SStanislav Sedov 
630*ae771770SStanislav Sedov 		ret = krb5_ret_int32 (sp, &offset);
631*ae771770SStanislav Sedov 		ret |= krb5_ret_int32 (sp, &context->kdc_usec_offset);
6321c43270aSJacques Vidrine 		if(ret) {
6331c43270aSJacques Vidrine 		    ret = KRB5_CC_FORMAT;
634*ae771770SStanislav Sedov 		    krb5_set_error_message(context, ret,
635*ae771770SStanislav Sedov 					   N_("Error reading kdc_sec in "
636*ae771770SStanislav Sedov 					      "cache file: %s", ""),
637*ae771770SStanislav Sedov 					   FILENAME(id));
6381c43270aSJacques Vidrine 		    goto out;
6391c43270aSJacques Vidrine 		}
640*ae771770SStanislav Sedov 		context->kdc_sec_offset = offset;
641*ae771770SStanislav Sedov 		if (kdc_offset)
642*ae771770SStanislav Sedov 		    *kdc_offset = offset;
643b528cefcSMark Murray 		break;
644*ae771770SStanislav Sedov 	    }
645b528cefcSMark Murray 	    default :
6461c43270aSJacques Vidrine 		for (i = 0; i < data_len; ++i) {
6471c43270aSJacques Vidrine 		    ret = krb5_ret_int8 (sp, &dummy);
6481c43270aSJacques Vidrine 		    if(ret) {
6491c43270aSJacques Vidrine 			ret = KRB5_CC_FORMAT;
650*ae771770SStanislav Sedov 			krb5_set_error_message(context, ret,
651*ae771770SStanislav Sedov 					       N_("Error reading unknown "
652*ae771770SStanislav Sedov 						  "tag in cache file: %s", ""),
653*ae771770SStanislav Sedov 					       FILENAME(id));
6541c43270aSJacques Vidrine 			goto out;
6551c43270aSJacques Vidrine 		    }
6561c43270aSJacques Vidrine 		}
657b528cefcSMark Murray 		break;
658b528cefcSMark Murray 	    }
659b528cefcSMark Murray 	    length -= 4 + data_len;
660b528cefcSMark Murray 	}
661b528cefcSMark Murray 	break;
662b528cefcSMark Murray     }
663b528cefcSMark Murray     case KRB5_FCC_FVNO_3:
664b528cefcSMark Murray     case KRB5_FCC_FVNO_2:
665b528cefcSMark Murray     case KRB5_FCC_FVNO_1:
666b528cefcSMark Murray 	break;
667b528cefcSMark Murray     default :
6681c43270aSJacques Vidrine 	ret = KRB5_CCACHE_BADVNO;
669*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
670*ae771770SStanislav Sedov 			       N_("Unknown version number (%d) in "
671*ae771770SStanislav Sedov 				  "credential cache file: %s", ""),
672c19800e8SDoug Rabson 			       (int)tag, FILENAME(id));
6731c43270aSJacques Vidrine 	goto out;
674b528cefcSMark Murray     }
675b528cefcSMark Murray     *ret_sp = sp;
676b528cefcSMark Murray     *ret_fd = fd;
6771c43270aSJacques Vidrine 
678b528cefcSMark Murray     return 0;
6791c43270aSJacques Vidrine   out:
6801c43270aSJacques Vidrine     if(sp != NULL)
6811c43270aSJacques Vidrine 	krb5_storage_free(sp);
6821c43270aSJacques Vidrine     fcc_unlock(context, fd);
6831c43270aSJacques Vidrine     close(fd);
6841c43270aSJacques Vidrine     return ret;
685b528cefcSMark Murray }
686b528cefcSMark Murray 
687*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_principal(krb5_context context,krb5_ccache id,krb5_principal * principal)688b528cefcSMark Murray fcc_get_principal(krb5_context context,
689b528cefcSMark Murray 		  krb5_ccache id,
690b528cefcSMark Murray 		  krb5_principal *principal)
691b528cefcSMark Murray {
692b528cefcSMark Murray     krb5_error_code ret;
693b528cefcSMark Murray     int fd;
694b528cefcSMark Murray     krb5_storage *sp;
695b528cefcSMark Murray 
696*ae771770SStanislav Sedov     ret = init_fcc (context, id, &sp, &fd, NULL);
697b528cefcSMark Murray     if (ret)
698b528cefcSMark Murray 	return ret;
6995e9cd1aeSAssar Westerlund     ret = krb5_ret_principal(sp, principal);
700c19800e8SDoug Rabson     if (ret)
701*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
702b528cefcSMark Murray     krb5_storage_free(sp);
7031c43270aSJacques Vidrine     fcc_unlock(context, fd);
704b528cefcSMark Murray     close(fd);
7055e9cd1aeSAssar Westerlund     return ret;
706b528cefcSMark Murray }
707b528cefcSMark Murray 
708*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
7091c43270aSJacques Vidrine fcc_end_get (krb5_context context,
7101c43270aSJacques Vidrine 	     krb5_ccache id,
7111c43270aSJacques Vidrine 	     krb5_cc_cursor *cursor);
7121c43270aSJacques Vidrine 
713*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_first(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)714b528cefcSMark Murray fcc_get_first (krb5_context context,
715b528cefcSMark Murray 	       krb5_ccache id,
716b528cefcSMark Murray 	       krb5_cc_cursor *cursor)
717b528cefcSMark Murray {
718b528cefcSMark Murray     krb5_error_code ret;
719b528cefcSMark Murray     krb5_principal principal;
720b528cefcSMark Murray 
721*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
722*ae771770SStanislav Sedov         return krb5_einval(context, 2);
723*ae771770SStanislav Sedov 
724b528cefcSMark Murray     *cursor = malloc(sizeof(struct fcc_cursor));
725c19800e8SDoug Rabson     if (*cursor == NULL) {
726*ae771770SStanislav Sedov         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
727c19800e8SDoug Rabson 	return ENOMEM;
728c19800e8SDoug Rabson     }
729c19800e8SDoug Rabson     memset(*cursor, 0, sizeof(struct fcc_cursor));
730b528cefcSMark Murray 
7311c43270aSJacques Vidrine     ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp,
732*ae771770SStanislav Sedov 		    &FCC_CURSOR(*cursor)->fd, NULL);
7331c43270aSJacques Vidrine     if (ret) {
7341c43270aSJacques Vidrine 	free(*cursor);
735c19800e8SDoug Rabson 	*cursor = NULL;
736b528cefcSMark Murray 	return ret;
7371c43270aSJacques Vidrine     }
7381c43270aSJacques Vidrine     ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
7391c43270aSJacques Vidrine     if(ret) {
740*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
7411c43270aSJacques Vidrine 	fcc_end_get(context, id, cursor);
7421c43270aSJacques Vidrine 	return ret;
7431c43270aSJacques Vidrine     }
744b528cefcSMark Murray     krb5_free_principal (context, principal);
7451c43270aSJacques Vidrine     fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
746b528cefcSMark Murray     return 0;
747b528cefcSMark Murray }
748b528cefcSMark Murray 
749*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)750b528cefcSMark Murray fcc_get_next (krb5_context context,
751b528cefcSMark Murray 	      krb5_ccache id,
752b528cefcSMark Murray 	      krb5_cc_cursor *cursor,
753b528cefcSMark Murray 	      krb5_creds *creds)
754b528cefcSMark Murray {
7551c43270aSJacques Vidrine     krb5_error_code ret;
756*ae771770SStanislav Sedov 
757*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
758*ae771770SStanislav Sedov         return krb5_einval(context, 2);
759*ae771770SStanislav Sedov 
760*ae771770SStanislav Sedov     if (FCC_CURSOR(*cursor) == NULL)
761*ae771770SStanislav Sedov         return krb5_einval(context, 3);
762*ae771770SStanislav Sedov 
7631c43270aSJacques Vidrine     if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
7641c43270aSJacques Vidrine 	return ret;
7651c43270aSJacques Vidrine 
7661c43270aSJacques Vidrine     ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
767c19800e8SDoug Rabson     if (ret)
768*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
7691c43270aSJacques Vidrine 
7701c43270aSJacques Vidrine     fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
7711c43270aSJacques Vidrine     return ret;
772b528cefcSMark Murray }
773b528cefcSMark Murray 
774*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_end_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)775b528cefcSMark Murray fcc_end_get (krb5_context context,
776b528cefcSMark Murray 	     krb5_ccache id,
777b528cefcSMark Murray 	     krb5_cc_cursor *cursor)
778b528cefcSMark Murray {
779*ae771770SStanislav Sedov 
780*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
781*ae771770SStanislav Sedov         return krb5_einval(context, 2);
782*ae771770SStanislav Sedov 
783*ae771770SStanislav Sedov     if (FCC_CURSOR(*cursor) == NULL)
784*ae771770SStanislav Sedov         return krb5_einval(context, 3);
785*ae771770SStanislav Sedov 
786b528cefcSMark Murray     krb5_storage_free(FCC_CURSOR(*cursor)->sp);
787b528cefcSMark Murray     close (FCC_CURSOR(*cursor)->fd);
788b528cefcSMark Murray     free(*cursor);
7891c43270aSJacques Vidrine     *cursor = NULL;
790b528cefcSMark Murray     return 0;
791b528cefcSMark Murray }
792b528cefcSMark Murray 
793*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * cred)794b528cefcSMark Murray fcc_remove_cred(krb5_context context,
795b528cefcSMark Murray 		 krb5_ccache id,
796b528cefcSMark Murray 		 krb5_flags which,
797b528cefcSMark Murray 		 krb5_creds *cred)
798b528cefcSMark Murray {
799c19800e8SDoug Rabson     krb5_error_code ret;
800*ae771770SStanislav Sedov     krb5_ccache copy, newfile;
801*ae771770SStanislav Sedov     char *newname = NULL;
802*ae771770SStanislav Sedov     int fd;
803c19800e8SDoug Rabson 
804*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
805*ae771770SStanislav Sedov         return krb5_einval(context, 2);
806*ae771770SStanislav Sedov 
807*ae771770SStanislav Sedov     ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &copy);
808c19800e8SDoug Rabson     if (ret)
809c19800e8SDoug Rabson 	return ret;
810c19800e8SDoug Rabson 
811c19800e8SDoug Rabson     ret = krb5_cc_copy_cache(context, id, copy);
812c19800e8SDoug Rabson     if (ret) {
813c19800e8SDoug Rabson 	krb5_cc_destroy(context, copy);
814c19800e8SDoug Rabson 	return ret;
815c19800e8SDoug Rabson     }
816c19800e8SDoug Rabson 
817c19800e8SDoug Rabson     ret = krb5_cc_remove_cred(context, copy, which, cred);
818c19800e8SDoug Rabson     if (ret) {
819c19800e8SDoug Rabson 	krb5_cc_destroy(context, copy);
820c19800e8SDoug Rabson 	return ret;
821c19800e8SDoug Rabson     }
822c19800e8SDoug Rabson 
823*ae771770SStanislav Sedov     ret = asprintf(&newname, "FILE:%s.XXXXXX", FILENAME(id));
824*ae771770SStanislav Sedov     if (ret < 0 || newname == NULL) {
825c19800e8SDoug Rabson 	krb5_cc_destroy(context, copy);
826*ae771770SStanislav Sedov 	return ENOMEM;
827*ae771770SStanislav Sedov     }
828*ae771770SStanislav Sedov 
829*ae771770SStanislav Sedov     fd = mkstemp(&newname[5]);
830*ae771770SStanislav Sedov     if (fd < 0) {
831*ae771770SStanislav Sedov 	ret = errno;
832*ae771770SStanislav Sedov 	krb5_cc_destroy(context, copy);
833*ae771770SStanislav Sedov 	return ret;
834*ae771770SStanislav Sedov     }
835*ae771770SStanislav Sedov     close(fd);
836*ae771770SStanislav Sedov 
837*ae771770SStanislav Sedov     ret = krb5_cc_resolve(context, newname, &newfile);
838*ae771770SStanislav Sedov     if (ret) {
839*ae771770SStanislav Sedov 	unlink(&newname[5]);
840*ae771770SStanislav Sedov 	free(newname);
841*ae771770SStanislav Sedov 	krb5_cc_destroy(context, copy);
842*ae771770SStanislav Sedov 	return ret;
843*ae771770SStanislav Sedov     }
844*ae771770SStanislav Sedov 
845*ae771770SStanislav Sedov     ret = krb5_cc_copy_cache(context, copy, newfile);
846*ae771770SStanislav Sedov     krb5_cc_destroy(context, copy);
847*ae771770SStanislav Sedov     if (ret) {
848*ae771770SStanislav Sedov 	free(newname);
849*ae771770SStanislav Sedov 	krb5_cc_destroy(context, newfile);
850*ae771770SStanislav Sedov 	return ret;
851*ae771770SStanislav Sedov     }
852*ae771770SStanislav Sedov 
853*ae771770SStanislav Sedov     ret = rk_rename(&newname[5], FILENAME(id));
854*ae771770SStanislav Sedov     if (ret)
855*ae771770SStanislav Sedov 	ret = errno;
856*ae771770SStanislav Sedov     free(newname);
857*ae771770SStanislav Sedov     krb5_cc_close(context, newfile);
858c19800e8SDoug Rabson 
859c19800e8SDoug Rabson     return ret;
860b528cefcSMark Murray }
861b528cefcSMark Murray 
862*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)863b528cefcSMark Murray fcc_set_flags(krb5_context context,
864b528cefcSMark Murray 	      krb5_ccache id,
865b528cefcSMark Murray 	      krb5_flags flags)
866b528cefcSMark Murray {
867*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
868*ae771770SStanislav Sedov         return krb5_einval(context, 2);
869*ae771770SStanislav Sedov 
870b528cefcSMark Murray     return 0; /* XXX */
871b528cefcSMark Murray }
872b528cefcSMark Murray 
873*ae771770SStanislav Sedov static int KRB5_CALLCONV
fcc_get_version(krb5_context context,krb5_ccache id)874b528cefcSMark Murray fcc_get_version(krb5_context context,
875b528cefcSMark Murray 		krb5_ccache id)
876b528cefcSMark Murray {
877*ae771770SStanislav Sedov     if (FCACHE(id) == NULL)
878*ae771770SStanislav Sedov         return -1;
879*ae771770SStanislav Sedov 
880b528cefcSMark Murray     return FCACHE(id)->version;
881b528cefcSMark Murray }
882b528cefcSMark Murray 
883c19800e8SDoug Rabson struct fcache_iter {
884c19800e8SDoug Rabson     int first;
885c19800e8SDoug Rabson };
886c19800e8SDoug Rabson 
887*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_cache_first(krb5_context context,krb5_cc_cursor * cursor)888c19800e8SDoug Rabson fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
889c19800e8SDoug Rabson {
890c19800e8SDoug Rabson     struct fcache_iter *iter;
891c19800e8SDoug Rabson 
892c19800e8SDoug Rabson     iter = calloc(1, sizeof(*iter));
893c19800e8SDoug Rabson     if (iter == NULL) {
894*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
895c19800e8SDoug Rabson 	return ENOMEM;
896c19800e8SDoug Rabson     }
897c19800e8SDoug Rabson     iter->first = 1;
898c19800e8SDoug Rabson     *cursor = iter;
899c19800e8SDoug Rabson     return 0;
900c19800e8SDoug Rabson }
901c19800e8SDoug Rabson 
902*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_cache_next(krb5_context context,krb5_cc_cursor cursor,krb5_ccache * id)903c19800e8SDoug Rabson fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
904c19800e8SDoug Rabson {
905c19800e8SDoug Rabson     struct fcache_iter *iter = cursor;
906c19800e8SDoug Rabson     krb5_error_code ret;
907c19800e8SDoug Rabson     const char *fn;
908c19800e8SDoug Rabson     char *expandedfn = NULL;
909c19800e8SDoug Rabson 
910*ae771770SStanislav Sedov     if (iter == NULL)
911*ae771770SStanislav Sedov         return krb5_einval(context, 2);
912*ae771770SStanislav Sedov 
913c19800e8SDoug Rabson     if (!iter->first) {
914*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
915c19800e8SDoug Rabson 	return KRB5_CC_END;
916c19800e8SDoug Rabson     }
917c19800e8SDoug Rabson     iter->first = 0;
918c19800e8SDoug Rabson 
919c19800e8SDoug Rabson     fn = krb5_cc_default_name(context);
920*ae771770SStanislav Sedov     if (fn == NULL || strncasecmp(fn, "FILE:", 5) != 0) {
921c19800e8SDoug Rabson 	ret = _krb5_expand_default_cc_name(context,
922c19800e8SDoug Rabson 					   KRB5_DEFAULT_CCNAME_FILE,
923c19800e8SDoug Rabson 					   &expandedfn);
924c19800e8SDoug Rabson 	if (ret)
925c19800e8SDoug Rabson 	    return ret;
926*ae771770SStanislav Sedov 	fn = expandedfn;
927*ae771770SStanislav Sedov     }
928*ae771770SStanislav Sedov     /* check if file exists, don't return a non existant "next" */
929*ae771770SStanislav Sedov     if (strncasecmp(fn, "FILE:", 5) == 0) {
930*ae771770SStanislav Sedov 	struct stat sb;
931*ae771770SStanislav Sedov 	ret = stat(fn + 5, &sb);
932*ae771770SStanislav Sedov 	if (ret) {
933*ae771770SStanislav Sedov 	    ret = KRB5_CC_END;
934*ae771770SStanislav Sedov 	    goto out;
935*ae771770SStanislav Sedov 	}
936c19800e8SDoug Rabson     }
937c19800e8SDoug Rabson     ret = krb5_cc_resolve(context, fn, id);
938*ae771770SStanislav Sedov  out:
939c19800e8SDoug Rabson     if (expandedfn)
940c19800e8SDoug Rabson 	free(expandedfn);
941c19800e8SDoug Rabson 
942c19800e8SDoug Rabson     return ret;
943c19800e8SDoug Rabson }
944c19800e8SDoug Rabson 
945*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_end_cache_get(krb5_context context,krb5_cc_cursor cursor)946c19800e8SDoug Rabson fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
947c19800e8SDoug Rabson {
948c19800e8SDoug Rabson     struct fcache_iter *iter = cursor;
949*ae771770SStanislav Sedov 
950*ae771770SStanislav Sedov     if (iter == NULL)
951*ae771770SStanislav Sedov         return krb5_einval(context, 2);
952*ae771770SStanislav Sedov 
953c19800e8SDoug Rabson     free(iter);
954c19800e8SDoug Rabson     return 0;
955c19800e8SDoug Rabson }
956c19800e8SDoug Rabson 
957*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_move(krb5_context context,krb5_ccache from,krb5_ccache to)958c19800e8SDoug Rabson fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
959c19800e8SDoug Rabson {
960c19800e8SDoug Rabson     krb5_error_code ret = 0;
961c19800e8SDoug Rabson 
962*ae771770SStanislav Sedov     ret = rk_rename(FILENAME(from), FILENAME(to));
963*ae771770SStanislav Sedov 
964c19800e8SDoug Rabson     if (ret && errno != EXDEV) {
965*ae771770SStanislav Sedov 	char buf[128];
966c19800e8SDoug Rabson 	ret = errno;
967*ae771770SStanislav Sedov 	rk_strerror_r(ret, buf, sizeof(buf));
968*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
969*ae771770SStanislav Sedov 			       N_("Rename of file from %s "
970*ae771770SStanislav Sedov 				  "to %s failed: %s", ""),
971*ae771770SStanislav Sedov 			       FILENAME(from), FILENAME(to), buf);
972c19800e8SDoug Rabson 	return ret;
973c19800e8SDoug Rabson     } else if (ret && errno == EXDEV) {
974c19800e8SDoug Rabson 	/* make a copy and delete the orignal */
975c19800e8SDoug Rabson 	krb5_ssize_t sz1, sz2;
976c19800e8SDoug Rabson 	int fd1, fd2;
977c19800e8SDoug Rabson 	char buf[BUFSIZ];
978c19800e8SDoug Rabson 
979*ae771770SStanislav Sedov 	ret = fcc_open(context, from, &fd1, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
980c19800e8SDoug Rabson 	if(ret)
981c19800e8SDoug Rabson 	    return ret;
982c19800e8SDoug Rabson 
983c19800e8SDoug Rabson 	unlink(FILENAME(to));
984c19800e8SDoug Rabson 
985c19800e8SDoug Rabson 	ret = fcc_open(context, to, &fd2,
986*ae771770SStanislav Sedov 		       O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
987c19800e8SDoug Rabson 	if(ret)
988c19800e8SDoug Rabson 	    goto out1;
989c19800e8SDoug Rabson 
990c19800e8SDoug Rabson 	while((sz1 = read(fd1, buf, sizeof(buf))) > 0) {
991c19800e8SDoug Rabson 	    sz2 = write(fd2, buf, sz1);
992c19800e8SDoug Rabson 	    if (sz1 != sz2) {
993c19800e8SDoug Rabson 		ret = EIO;
994*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
995*ae771770SStanislav Sedov 				       N_("Failed to write data from one file "
996*ae771770SStanislav Sedov 					  "credential cache to the other", ""));
997c19800e8SDoug Rabson 		goto out2;
998c19800e8SDoug Rabson 	    }
999c19800e8SDoug Rabson 	}
1000c19800e8SDoug Rabson 	if (sz1 < 0) {
1001c19800e8SDoug Rabson 	    ret = EIO;
1002*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
1003*ae771770SStanislav Sedov 				   N_("Failed to read data from one file "
1004*ae771770SStanislav Sedov 				      "credential cache to the other", ""));
1005c19800e8SDoug Rabson 	    goto out2;
1006c19800e8SDoug Rabson 	}
1007c19800e8SDoug Rabson     out2:
1008c19800e8SDoug Rabson 	fcc_unlock(context, fd2);
1009c19800e8SDoug Rabson 	close(fd2);
1010c19800e8SDoug Rabson 
1011c19800e8SDoug Rabson     out1:
1012c19800e8SDoug Rabson 	fcc_unlock(context, fd1);
1013c19800e8SDoug Rabson 	close(fd1);
1014c19800e8SDoug Rabson 
1015*ae771770SStanislav Sedov 	_krb5_erase_file(context, FILENAME(from));
1016*ae771770SStanislav Sedov 
1017c19800e8SDoug Rabson 	if (ret) {
1018*ae771770SStanislav Sedov 	    _krb5_erase_file(context, FILENAME(to));
1019c19800e8SDoug Rabson 	    return ret;
1020c19800e8SDoug Rabson 	}
1021c19800e8SDoug Rabson     }
1022c19800e8SDoug Rabson 
1023c19800e8SDoug Rabson     /* make sure ->version is uptodate */
1024c19800e8SDoug Rabson     {
1025c19800e8SDoug Rabson 	krb5_storage *sp;
1026c19800e8SDoug Rabson 	int fd;
1027*ae771770SStanislav Sedov 	if ((ret = init_fcc (context, to, &sp, &fd, NULL)) == 0) {
1028*ae771770SStanislav Sedov 	    if (sp)
1029c19800e8SDoug Rabson 		krb5_storage_free(sp);
1030c19800e8SDoug Rabson 	    fcc_unlock(context, fd);
1031c19800e8SDoug Rabson 	    close(fd);
1032c19800e8SDoug Rabson 	}
1033*ae771770SStanislav Sedov     }
1034*ae771770SStanislav Sedov 
1035*ae771770SStanislav Sedov     fcc_close(context, from);
1036*ae771770SStanislav Sedov 
1037c19800e8SDoug Rabson     return ret;
1038c19800e8SDoug Rabson }
1039c19800e8SDoug Rabson 
1040*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_default_name(krb5_context context,char ** str)1041*ae771770SStanislav Sedov fcc_get_default_name(krb5_context context, char **str)
1042c19800e8SDoug Rabson {
1043c19800e8SDoug Rabson     return _krb5_expand_default_cc_name(context,
1044c19800e8SDoug Rabson 					KRB5_DEFAULT_CCNAME_FILE,
1045c19800e8SDoug Rabson 					str);
1046c19800e8SDoug Rabson }
1047c19800e8SDoug Rabson 
1048*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_lastchange(krb5_context context,krb5_ccache id,krb5_timestamp * mtime)1049*ae771770SStanislav Sedov fcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
1050*ae771770SStanislav Sedov {
1051*ae771770SStanislav Sedov     krb5_error_code ret;
1052*ae771770SStanislav Sedov     struct stat sb;
1053*ae771770SStanislav Sedov     int fd;
1054*ae771770SStanislav Sedov 
1055*ae771770SStanislav Sedov     ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
1056*ae771770SStanislav Sedov     if(ret)
1057*ae771770SStanislav Sedov 	return ret;
1058*ae771770SStanislav Sedov     ret = fstat(fd, &sb);
1059*ae771770SStanislav Sedov     close(fd);
1060*ae771770SStanislav Sedov     if (ret) {
1061*ae771770SStanislav Sedov 	ret = errno;
1062*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("Failed to stat cache file", ""));
1063*ae771770SStanislav Sedov 	return ret;
1064*ae771770SStanislav Sedov     }
1065*ae771770SStanislav Sedov     *mtime = sb.st_mtime;
1066*ae771770SStanislav Sedov     return 0;
1067*ae771770SStanislav Sedov }
1068*ae771770SStanislav Sedov 
1069*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_set_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat kdc_offset)1070*ae771770SStanislav Sedov fcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
1071*ae771770SStanislav Sedov {
1072*ae771770SStanislav Sedov     return 0;
1073*ae771770SStanislav Sedov }
1074*ae771770SStanislav Sedov 
1075*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
fcc_get_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat * kdc_offset)1076*ae771770SStanislav Sedov fcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
1077*ae771770SStanislav Sedov {
1078*ae771770SStanislav Sedov     krb5_error_code ret;
1079*ae771770SStanislav Sedov     krb5_storage *sp = NULL;
1080*ae771770SStanislav Sedov     int fd;
1081*ae771770SStanislav Sedov     ret = init_fcc(context, id, &sp, &fd, kdc_offset);
1082*ae771770SStanislav Sedov     if (sp)
1083*ae771770SStanislav Sedov 	krb5_storage_free(sp);
1084*ae771770SStanislav Sedov     fcc_unlock(context, fd);
1085*ae771770SStanislav Sedov     close(fd);
1086*ae771770SStanislav Sedov 
1087*ae771770SStanislav Sedov     return ret;
1088*ae771770SStanislav Sedov }
1089*ae771770SStanislav Sedov 
1090*ae771770SStanislav Sedov 
1091c19800e8SDoug Rabson /**
1092c19800e8SDoug Rabson  * Variable containing the FILE based credential cache implemention.
1093c19800e8SDoug Rabson  *
1094c19800e8SDoug Rabson  * @ingroup krb5_ccache
1095c19800e8SDoug Rabson  */
1096c19800e8SDoug Rabson 
1097*ae771770SStanislav Sedov KRB5_LIB_VARIABLE const krb5_cc_ops krb5_fcc_ops = {
1098*ae771770SStanislav Sedov     KRB5_CC_OPS_VERSION,
1099b528cefcSMark Murray     "FILE",
1100b528cefcSMark Murray     fcc_get_name,
1101b528cefcSMark Murray     fcc_resolve,
1102b528cefcSMark Murray     fcc_gen_new,
1103b528cefcSMark Murray     fcc_initialize,
1104b528cefcSMark Murray     fcc_destroy,
1105b528cefcSMark Murray     fcc_close,
1106b528cefcSMark Murray     fcc_store_cred,
1107b528cefcSMark Murray     NULL, /* fcc_retrieve */
1108b528cefcSMark Murray     fcc_get_principal,
1109b528cefcSMark Murray     fcc_get_first,
1110b528cefcSMark Murray     fcc_get_next,
1111b528cefcSMark Murray     fcc_end_get,
1112b528cefcSMark Murray     fcc_remove_cred,
1113b528cefcSMark Murray     fcc_set_flags,
1114c19800e8SDoug Rabson     fcc_get_version,
1115c19800e8SDoug Rabson     fcc_get_cache_first,
1116c19800e8SDoug Rabson     fcc_get_cache_next,
1117c19800e8SDoug Rabson     fcc_end_cache_get,
1118c19800e8SDoug Rabson     fcc_move,
1119*ae771770SStanislav Sedov     fcc_get_default_name,
1120*ae771770SStanislav Sedov     NULL,
1121*ae771770SStanislav Sedov     fcc_lastchange,
1122*ae771770SStanislav Sedov     fcc_set_kdc_offset,
1123*ae771770SStanislav Sedov     fcc_get_kdc_offset
1124b528cefcSMark Murray };
1125