xref: /freebsd/crypto/heimdal/lib/krb5/fcache.c (revision 8373020d34ceb1ac55d8f43333c1ca3680185b39)
1b528cefcSMark Murray /*
28373020dSJacques Vidrine  * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "krb5_locl.h"
35b528cefcSMark Murray 
368373020dSJacques Vidrine RCSID("$Id: fcache.c,v 1.34 2002/04/18 14:01:29 joda Exp $");
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 
618373020dSJacques Vidrine static const char*
62b528cefcSMark Murray fcc_get_name(krb5_context context,
63b528cefcSMark Murray 	     krb5_ccache id)
64b528cefcSMark Murray {
65b528cefcSMark Murray     return FILENAME(id);
66b528cefcSMark Murray }
67b528cefcSMark Murray 
68b528cefcSMark Murray static krb5_error_code
69b528cefcSMark Murray fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
70b528cefcSMark Murray {
71b528cefcSMark Murray     krb5_fcache *f;
72b528cefcSMark Murray     f = malloc(sizeof(*f));
73adb0ddaeSAssar Westerlund     if(f == NULL) {
74adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "malloc: out of memory");
75b528cefcSMark Murray 	return KRB5_CC_NOMEM;
76adb0ddaeSAssar Westerlund     }
77b528cefcSMark Murray     f->filename = strdup(res);
78b528cefcSMark Murray     if(f->filename == NULL){
79b528cefcSMark Murray 	free(f);
80adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "malloc: out of memory");
81b528cefcSMark Murray 	return KRB5_CC_NOMEM;
82b528cefcSMark Murray     }
83b528cefcSMark Murray     f->version = 0;
84b528cefcSMark Murray     (*id)->data.data = f;
85b528cefcSMark Murray     (*id)->data.length = sizeof(*f);
86b528cefcSMark Murray     return 0;
87b528cefcSMark Murray }
88b528cefcSMark Murray 
895e9cd1aeSAssar Westerlund /*
905e9cd1aeSAssar Westerlund  * Try to scrub the contents of `filename' safely.
915e9cd1aeSAssar Westerlund  */
925e9cd1aeSAssar Westerlund 
935e9cd1aeSAssar Westerlund static int
945e9cd1aeSAssar Westerlund scrub_file (int fd)
955e9cd1aeSAssar Westerlund {
965e9cd1aeSAssar Westerlund     off_t pos;
975e9cd1aeSAssar Westerlund     char buf[128];
985e9cd1aeSAssar Westerlund 
995e9cd1aeSAssar Westerlund     pos = lseek(fd, 0, SEEK_END);
1005e9cd1aeSAssar Westerlund     if (pos < 0)
1015e9cd1aeSAssar Westerlund         return errno;
1025e9cd1aeSAssar Westerlund     if (lseek(fd, 0, SEEK_SET) < 0)
1035e9cd1aeSAssar Westerlund         return errno;
1045e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
1055e9cd1aeSAssar Westerlund     while(pos > 0) {
1065e9cd1aeSAssar Westerlund         ssize_t tmp = write(fd, buf, min(sizeof(buf), pos));
1075e9cd1aeSAssar Westerlund 
1085e9cd1aeSAssar Westerlund 	if (tmp < 0)
1095e9cd1aeSAssar Westerlund 	    return errno;
1105e9cd1aeSAssar Westerlund 	pos -= tmp;
1115e9cd1aeSAssar Westerlund     }
1125e9cd1aeSAssar Westerlund     fsync (fd);
1135e9cd1aeSAssar Westerlund     return 0;
1145e9cd1aeSAssar Westerlund }
1155e9cd1aeSAssar Westerlund 
1165e9cd1aeSAssar Westerlund /*
1175e9cd1aeSAssar Westerlund  * Erase `filename' if it exists, trying to remove the contents if
1185e9cd1aeSAssar Westerlund  * it's `safe'.  We always try to remove the file, it it exists.  It's
1195e9cd1aeSAssar Westerlund  * only overwritten if it's a regular file (not a symlink and not a
1205e9cd1aeSAssar Westerlund  * hardlink)
1215e9cd1aeSAssar Westerlund  */
1225e9cd1aeSAssar Westerlund 
123b528cefcSMark Murray static krb5_error_code
124b528cefcSMark Murray erase_file(const char *filename)
125b528cefcSMark Murray {
126b528cefcSMark Murray     int fd;
1275e9cd1aeSAssar Westerlund     struct stat sb1, sb2;
1285e9cd1aeSAssar Westerlund     int ret;
1295e9cd1aeSAssar Westerlund 
1305e9cd1aeSAssar Westerlund     ret = lstat (filename, &sb1);
1315e9cd1aeSAssar Westerlund     if (ret < 0)
1325e9cd1aeSAssar Westerlund 	return errno;
133b528cefcSMark Murray 
134b528cefcSMark Murray     fd = open(filename, O_RDWR | O_BINARY);
135b528cefcSMark Murray     if(fd < 0) {
136b528cefcSMark Murray 	if(errno == ENOENT)
137b528cefcSMark Murray 	    return 0;
138b528cefcSMark Murray 	else
139b528cefcSMark Murray 	    return errno;
140b528cefcSMark Murray     }
1415e9cd1aeSAssar Westerlund     if (unlink(filename) < 0) {
142b528cefcSMark Murray         close (fd);
1435e9cd1aeSAssar Westerlund         return errno;
1445e9cd1aeSAssar Westerlund     }
1455e9cd1aeSAssar Westerlund 
1465e9cd1aeSAssar Westerlund     ret = fstat (fd, &sb2);
1475e9cd1aeSAssar Westerlund     if (ret < 0) {
1485e9cd1aeSAssar Westerlund 	close (fd);
1495e9cd1aeSAssar Westerlund 	return errno;
1505e9cd1aeSAssar Westerlund     }
1515e9cd1aeSAssar Westerlund 
1525e9cd1aeSAssar Westerlund     /* check if someone was playing with symlinks */
1535e9cd1aeSAssar Westerlund 
1545e9cd1aeSAssar Westerlund     if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
1555e9cd1aeSAssar Westerlund 	close (fd);
1565e9cd1aeSAssar Westerlund 	return EPERM;
1575e9cd1aeSAssar Westerlund     }
1585e9cd1aeSAssar Westerlund 
1595e9cd1aeSAssar Westerlund     /* there are still hard links to this file */
1605e9cd1aeSAssar Westerlund 
1615e9cd1aeSAssar Westerlund     if (sb2.st_nlink != 0) {
1625e9cd1aeSAssar Westerlund         close (fd);
163b528cefcSMark Murray         return 0;
164b528cefcSMark Murray     }
165b528cefcSMark Murray 
1665e9cd1aeSAssar Westerlund     ret = scrub_file (fd);
1675e9cd1aeSAssar Westerlund     close (fd);
1685e9cd1aeSAssar Westerlund     return ret;
1695e9cd1aeSAssar Westerlund }
1705e9cd1aeSAssar Westerlund 
171b528cefcSMark Murray static krb5_error_code
172b528cefcSMark Murray fcc_gen_new(krb5_context context, krb5_ccache *id)
173b528cefcSMark Murray {
174b528cefcSMark Murray     krb5_fcache *f;
175b528cefcSMark Murray     int fd;
176b528cefcSMark Murray     char *file;
177adb0ddaeSAssar Westerlund 
178b528cefcSMark Murray     f = malloc(sizeof(*f));
179adb0ddaeSAssar Westerlund     if(f == NULL) {
180adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "malloc: out of memory");
181b528cefcSMark Murray 	return KRB5_CC_NOMEM;
182adb0ddaeSAssar Westerlund     }
1835e9cd1aeSAssar Westerlund     asprintf (&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
184b528cefcSMark Murray     if(file == NULL) {
185b528cefcSMark Murray 	free(f);
186adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "malloc: out of memory");
187b528cefcSMark Murray 	return KRB5_CC_NOMEM;
188b528cefcSMark Murray     }
189b528cefcSMark Murray     fd = mkstemp(file);
190b528cefcSMark Murray     if(fd < 0) {
191b528cefcSMark Murray 	free(f);
192b528cefcSMark Murray 	free(file);
193adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "mkstemp %s", file);
194b528cefcSMark Murray 	return errno;
195b528cefcSMark Murray     }
196b528cefcSMark Murray     close(fd);
197b528cefcSMark Murray     f->filename = file;
198b528cefcSMark Murray     f->version = 0;
199b528cefcSMark Murray     (*id)->data.data = f;
200b528cefcSMark Murray     (*id)->data.length = sizeof(*f);
201b528cefcSMark Murray     return 0;
202b528cefcSMark Murray }
203b528cefcSMark Murray 
204b528cefcSMark Murray static void
205b528cefcSMark Murray storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
206b528cefcSMark Murray {
207b528cefcSMark Murray     int flags = 0;
208b528cefcSMark Murray     switch(vno) {
209b528cefcSMark Murray     case KRB5_FCC_FVNO_1:
210b528cefcSMark Murray 	flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
211b528cefcSMark Murray 	flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
212b528cefcSMark Murray 	flags |= KRB5_STORAGE_HOST_BYTEORDER;
213b528cefcSMark Murray 	break;
214b528cefcSMark Murray     case KRB5_FCC_FVNO_2:
215b528cefcSMark Murray 	flags |= KRB5_STORAGE_HOST_BYTEORDER;
216b528cefcSMark Murray 	break;
217b528cefcSMark Murray     case KRB5_FCC_FVNO_3:
218b528cefcSMark Murray 	flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE;
219b528cefcSMark Murray 	break;
220b528cefcSMark Murray     case KRB5_FCC_FVNO_4:
221b528cefcSMark Murray 	break;
222b528cefcSMark Murray     default:
223b528cefcSMark Murray 	krb5_abortx(context,
224b528cefcSMark Murray 		    "storage_set_flags called with bad vno (%x)", vno);
225b528cefcSMark Murray     }
226b528cefcSMark Murray     krb5_storage_set_flags(sp, flags);
227b528cefcSMark Murray }
228b528cefcSMark Murray 
229b528cefcSMark Murray static krb5_error_code
230b528cefcSMark Murray fcc_initialize(krb5_context context,
231b528cefcSMark Murray 	       krb5_ccache id,
232b528cefcSMark Murray 	       krb5_principal primary_principal)
233b528cefcSMark Murray {
234b528cefcSMark Murray     krb5_fcache *f = FCACHE(id);
2355e9cd1aeSAssar Westerlund     int ret = 0;
236b528cefcSMark Murray     int fd;
237b528cefcSMark Murray     char *filename = f->filename;
238b528cefcSMark Murray 
2395e9cd1aeSAssar Westerlund     unlink (filename);
240b528cefcSMark Murray 
241b528cefcSMark Murray     fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
242adb0ddaeSAssar Westerlund     if(fd == -1) {
243adb0ddaeSAssar Westerlund 	ret = errno;
244adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "open(%s): %s", filename,
245adb0ddaeSAssar Westerlund 			      strerror(ret));
246adb0ddaeSAssar Westerlund 	return ret;
247adb0ddaeSAssar Westerlund     }
248b528cefcSMark Murray     {
249b528cefcSMark Murray 	krb5_storage *sp;
250b528cefcSMark Murray 	sp = krb5_storage_from_fd(fd);
2518373020dSJacques Vidrine 	krb5_storage_set_eof_code(sp, KRB5_CC_END);
252b528cefcSMark Murray 	if(context->fcache_vno != 0)
253b528cefcSMark Murray 	    f->version = context->fcache_vno;
254b528cefcSMark Murray 	else
255b528cefcSMark Murray 	    f->version = KRB5_FCC_FVNO_4;
2565e9cd1aeSAssar Westerlund 	ret |= krb5_store_int8(sp, 5);
2575e9cd1aeSAssar Westerlund 	ret |= krb5_store_int8(sp, f->version);
258b528cefcSMark Murray 	storage_set_flags(context, sp, f->version);
2595e9cd1aeSAssar Westerlund 	if(f->version == KRB5_FCC_FVNO_4 && ret == 0) {
260b528cefcSMark Murray 	    /* V4 stuff */
261b528cefcSMark Murray 	    if (context->kdc_sec_offset) {
2625e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, 12); /* length */
2635e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */
2645e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, 8); /* length of data */
2655e9cd1aeSAssar Westerlund 		ret |= krb5_store_int32 (sp, context->kdc_sec_offset);
2665e9cd1aeSAssar Westerlund 		ret |= krb5_store_int32 (sp, context->kdc_usec_offset);
267b528cefcSMark Murray 	    } else {
2685e9cd1aeSAssar Westerlund 		ret |= krb5_store_int16 (sp, 0);
269b528cefcSMark Murray 	    }
270b528cefcSMark Murray 	}
2715e9cd1aeSAssar Westerlund 	ret |= krb5_store_principal(sp, primary_principal);
272b528cefcSMark Murray 	krb5_storage_free(sp);
273b528cefcSMark Murray     }
2745e9cd1aeSAssar Westerlund     if(close(fd) < 0)
275adb0ddaeSAssar Westerlund 	if (ret == 0) {
2765e9cd1aeSAssar Westerlund 	    ret = errno;
277adb0ddaeSAssar Westerlund 	    krb5_set_error_string (context, "close %s: %s", filename,
278adb0ddaeSAssar Westerlund 				   strerror(ret));
279adb0ddaeSAssar Westerlund 	}
280b528cefcSMark Murray 
2815e9cd1aeSAssar Westerlund     return ret;
282b528cefcSMark Murray }
283b528cefcSMark Murray 
284b528cefcSMark Murray static krb5_error_code
285b528cefcSMark Murray fcc_close(krb5_context context,
286b528cefcSMark Murray 	  krb5_ccache id)
287b528cefcSMark Murray {
288b528cefcSMark Murray     free (FILENAME(id));
289b528cefcSMark Murray     krb5_data_free(&id->data);
290b528cefcSMark Murray     return 0;
291b528cefcSMark Murray }
292b528cefcSMark Murray 
293b528cefcSMark Murray static krb5_error_code
294b528cefcSMark Murray fcc_destroy(krb5_context context,
295b528cefcSMark Murray 	    krb5_ccache id)
296b528cefcSMark Murray {
297b528cefcSMark Murray     char *f;
298b528cefcSMark Murray     f = FILENAME(id);
299b528cefcSMark Murray 
300b528cefcSMark Murray     erase_file(f);
301b528cefcSMark Murray 
302b528cefcSMark Murray     return 0;
303b528cefcSMark Murray }
304b528cefcSMark Murray 
305b528cefcSMark Murray static krb5_error_code
306b528cefcSMark Murray fcc_store_cred(krb5_context context,
307b528cefcSMark Murray 	       krb5_ccache id,
308b528cefcSMark Murray 	       krb5_creds *creds)
309b528cefcSMark Murray {
3105e9cd1aeSAssar Westerlund     int ret;
311b528cefcSMark Murray     int fd;
312b528cefcSMark Murray     char *f;
313b528cefcSMark Murray 
314b528cefcSMark Murray     f = FILENAME(id);
315b528cefcSMark Murray 
316b528cefcSMark Murray     fd = open(f, O_WRONLY | O_APPEND | O_BINARY);
317adb0ddaeSAssar Westerlund     if(fd < 0) {
318adb0ddaeSAssar Westerlund 	ret = errno;
319adb0ddaeSAssar Westerlund 	krb5_set_error_string (context, "open(%s): %s", f, strerror(ret));
320adb0ddaeSAssar Westerlund 	return ret;
321adb0ddaeSAssar Westerlund     }
322b528cefcSMark Murray     {
323b528cefcSMark Murray 	krb5_storage *sp;
324b528cefcSMark Murray 	sp = krb5_storage_from_fd(fd);
3258373020dSJacques Vidrine 	krb5_storage_set_eof_code(sp, KRB5_CC_END);
326b528cefcSMark Murray 	storage_set_flags(context, sp, FCACHE(id)->version);
3275e9cd1aeSAssar Westerlund 	ret = krb5_store_creds(sp, creds);
328b528cefcSMark Murray 	krb5_storage_free(sp);
329b528cefcSMark Murray     }
3305e9cd1aeSAssar Westerlund     if (close(fd) < 0)
331adb0ddaeSAssar Westerlund 	if (ret == 0) {
3325e9cd1aeSAssar Westerlund 	    ret = errno;
333adb0ddaeSAssar Westerlund 	    krb5_set_error_string (context, "close %s: %s", f, strerror(ret));
334adb0ddaeSAssar Westerlund 	}
3355e9cd1aeSAssar Westerlund     return ret;
336b528cefcSMark Murray }
337b528cefcSMark Murray 
338b528cefcSMark Murray static krb5_error_code
339b528cefcSMark Murray fcc_read_cred (krb5_context context,
340b528cefcSMark Murray 	       krb5_fcache *fc,
341b528cefcSMark Murray 	       krb5_storage *sp,
342b528cefcSMark Murray 	       krb5_creds *creds)
343b528cefcSMark Murray {
344b528cefcSMark Murray     krb5_error_code ret;
345b528cefcSMark Murray 
346b528cefcSMark Murray     storage_set_flags(context, sp, fc->version);
347b528cefcSMark Murray 
348b528cefcSMark Murray     ret = krb5_ret_creds(sp, creds);
349b528cefcSMark Murray     return ret;
350b528cefcSMark Murray }
351b528cefcSMark Murray 
352b528cefcSMark Murray static krb5_error_code
353b528cefcSMark Murray init_fcc (krb5_context context,
354b528cefcSMark Murray 	  krb5_fcache *fcache,
355b528cefcSMark Murray 	  krb5_storage **ret_sp,
356b528cefcSMark Murray 	  int *ret_fd)
357b528cefcSMark Murray {
358b528cefcSMark Murray     int fd;
359b528cefcSMark Murray     int8_t pvno, tag;
360b528cefcSMark Murray     krb5_storage *sp;
3615e9cd1aeSAssar Westerlund     krb5_error_code ret;
362b528cefcSMark Murray 
363b528cefcSMark Murray     fd = open(fcache->filename, O_RDONLY | O_BINARY);
364adb0ddaeSAssar Westerlund     if(fd < 0) {
365adb0ddaeSAssar Westerlund 	ret = errno;
366adb0ddaeSAssar Westerlund 	krb5_set_error_string(context, "open(%s): %s", fcache->filename,
367adb0ddaeSAssar Westerlund 			      strerror(ret));
368adb0ddaeSAssar Westerlund 	return ret;
369adb0ddaeSAssar Westerlund     }
370b528cefcSMark Murray     sp = krb5_storage_from_fd(fd);
3718373020dSJacques Vidrine     krb5_storage_set_eof_code(sp, KRB5_CC_END);
3725e9cd1aeSAssar Westerlund     ret = krb5_ret_int8(sp, &pvno);
3738373020dSJacques Vidrine     if(ret == KRB5_CC_END)
3745e9cd1aeSAssar Westerlund 	return ENOENT;
3755e9cd1aeSAssar Westerlund     if(ret)
3765e9cd1aeSAssar Westerlund 	return ret;
377b528cefcSMark Murray     if(pvno != 5) {
378b528cefcSMark Murray 	krb5_storage_free(sp);
379b528cefcSMark Murray 	close(fd);
380b528cefcSMark Murray 	return KRB5_CCACHE_BADVNO;
381b528cefcSMark Murray     }
382b528cefcSMark Murray     krb5_ret_int8(sp, &tag); /* should not be host byte order */
383b528cefcSMark Murray     fcache->version = tag;
384b528cefcSMark Murray     storage_set_flags(context, sp, fcache->version);
385b528cefcSMark Murray     switch (tag) {
386b528cefcSMark Murray     case KRB5_FCC_FVNO_4: {
387b528cefcSMark Murray 	int16_t length;
388b528cefcSMark Murray 
389b528cefcSMark Murray 	krb5_ret_int16 (sp, &length);
390b528cefcSMark Murray 	while(length > 0) {
391b528cefcSMark Murray 	    int16_t tag, data_len;
392b528cefcSMark Murray 	    int i;
393b528cefcSMark Murray 	    int8_t dummy;
394b528cefcSMark Murray 
395b528cefcSMark Murray 	    krb5_ret_int16 (sp, &tag);
396b528cefcSMark Murray 	    krb5_ret_int16 (sp, &data_len);
397b528cefcSMark Murray 	    switch (tag) {
398b528cefcSMark Murray 	    case FCC_TAG_DELTATIME :
399b528cefcSMark Murray 		krb5_ret_int32 (sp, &context->kdc_sec_offset);
400b528cefcSMark Murray 		krb5_ret_int32 (sp, &context->kdc_usec_offset);
401b528cefcSMark Murray 		break;
402b528cefcSMark Murray 	    default :
403b528cefcSMark Murray 		for (i = 0; i < data_len; ++i)
404b528cefcSMark Murray 		    krb5_ret_int8 (sp, &dummy);
405b528cefcSMark Murray 		break;
406b528cefcSMark Murray 	    }
407b528cefcSMark Murray 	    length -= 4 + data_len;
408b528cefcSMark Murray 	}
409b528cefcSMark Murray 	break;
410b528cefcSMark Murray     }
411b528cefcSMark Murray     case KRB5_FCC_FVNO_3:
412b528cefcSMark Murray     case KRB5_FCC_FVNO_2:
413b528cefcSMark Murray     case KRB5_FCC_FVNO_1:
414b528cefcSMark Murray 	break;
415b528cefcSMark Murray     default :
416b528cefcSMark Murray 	krb5_storage_free (sp);
417b528cefcSMark Murray 	close (fd);
418b528cefcSMark Murray 	return KRB5_CCACHE_BADVNO;
419b528cefcSMark Murray     }
420b528cefcSMark Murray     *ret_sp = sp;
421b528cefcSMark Murray     *ret_fd = fd;
422b528cefcSMark Murray     return 0;
423b528cefcSMark Murray }
424b528cefcSMark Murray 
425b528cefcSMark Murray static krb5_error_code
426b528cefcSMark Murray fcc_get_principal(krb5_context context,
427b528cefcSMark Murray 		  krb5_ccache id,
428b528cefcSMark Murray 		  krb5_principal *principal)
429b528cefcSMark Murray {
430b528cefcSMark Murray     krb5_error_code ret;
431b528cefcSMark Murray     krb5_fcache *f = FCACHE(id);
432b528cefcSMark Murray     int fd;
433b528cefcSMark Murray     krb5_storage *sp;
434b528cefcSMark Murray 
435b528cefcSMark Murray     ret = init_fcc (context, f, &sp, &fd);
436b528cefcSMark Murray     if (ret)
437b528cefcSMark Murray 	return ret;
4385e9cd1aeSAssar Westerlund     ret = krb5_ret_principal(sp, principal);
439b528cefcSMark Murray     krb5_storage_free(sp);
440b528cefcSMark Murray     close(fd);
4415e9cd1aeSAssar Westerlund     return ret;
442b528cefcSMark Murray }
443b528cefcSMark Murray 
444b528cefcSMark Murray static krb5_error_code
445b528cefcSMark Murray fcc_get_first (krb5_context context,
446b528cefcSMark Murray 	       krb5_ccache id,
447b528cefcSMark Murray 	       krb5_cc_cursor *cursor)
448b528cefcSMark Murray {
449b528cefcSMark Murray     krb5_error_code ret;
450b528cefcSMark Murray     krb5_principal principal;
451b528cefcSMark Murray     krb5_fcache *f = FCACHE(id);
452b528cefcSMark Murray 
453b528cefcSMark Murray     *cursor = malloc(sizeof(struct fcc_cursor));
454b528cefcSMark Murray 
455b528cefcSMark Murray     ret = init_fcc (context, f, &FCC_CURSOR(*cursor)->sp,
456b528cefcSMark Murray 		    &FCC_CURSOR(*cursor)->fd);
457b528cefcSMark Murray     if (ret)
458b528cefcSMark Murray 	return ret;
459b528cefcSMark Murray     krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
460b528cefcSMark Murray     krb5_free_principal (context, principal);
461b528cefcSMark Murray     return 0;
462b528cefcSMark Murray }
463b528cefcSMark Murray 
464b528cefcSMark Murray static krb5_error_code
465b528cefcSMark Murray fcc_get_next (krb5_context context,
466b528cefcSMark Murray 	      krb5_ccache id,
467b528cefcSMark Murray 	      krb5_cc_cursor *cursor,
468b528cefcSMark Murray 	      krb5_creds *creds)
469b528cefcSMark Murray {
470b528cefcSMark Murray     return fcc_read_cred (context, FCACHE(id), FCC_CURSOR(*cursor)->sp, creds);
471b528cefcSMark Murray }
472b528cefcSMark Murray 
473b528cefcSMark Murray static krb5_error_code
474b528cefcSMark Murray fcc_end_get (krb5_context context,
475b528cefcSMark Murray 	     krb5_ccache id,
476b528cefcSMark Murray 	     krb5_cc_cursor *cursor)
477b528cefcSMark Murray {
478b528cefcSMark Murray     krb5_storage_free(FCC_CURSOR(*cursor)->sp);
479b528cefcSMark Murray     close (FCC_CURSOR(*cursor)->fd);
480b528cefcSMark Murray     free(*cursor);
481b528cefcSMark Murray     return 0;
482b528cefcSMark Murray }
483b528cefcSMark Murray 
484b528cefcSMark Murray static krb5_error_code
485b528cefcSMark Murray fcc_remove_cred(krb5_context context,
486b528cefcSMark Murray 		 krb5_ccache id,
487b528cefcSMark Murray 		 krb5_flags which,
488b528cefcSMark Murray 		 krb5_creds *cred)
489b528cefcSMark Murray {
490b528cefcSMark Murray     return 0; /* XXX */
491b528cefcSMark Murray }
492b528cefcSMark Murray 
493b528cefcSMark Murray static krb5_error_code
494b528cefcSMark Murray fcc_set_flags(krb5_context context,
495b528cefcSMark Murray 	      krb5_ccache id,
496b528cefcSMark Murray 	      krb5_flags flags)
497b528cefcSMark Murray {
498b528cefcSMark Murray     return 0; /* XXX */
499b528cefcSMark Murray }
500b528cefcSMark Murray 
501b528cefcSMark Murray static krb5_error_code
502b528cefcSMark Murray fcc_get_version(krb5_context context,
503b528cefcSMark Murray 		krb5_ccache id)
504b528cefcSMark Murray {
505b528cefcSMark Murray     return FCACHE(id)->version;
506b528cefcSMark Murray }
507b528cefcSMark Murray 
508b528cefcSMark Murray const krb5_cc_ops krb5_fcc_ops = {
509b528cefcSMark Murray     "FILE",
510b528cefcSMark Murray     fcc_get_name,
511b528cefcSMark Murray     fcc_resolve,
512b528cefcSMark Murray     fcc_gen_new,
513b528cefcSMark Murray     fcc_initialize,
514b528cefcSMark Murray     fcc_destroy,
515b528cefcSMark Murray     fcc_close,
516b528cefcSMark Murray     fcc_store_cred,
517b528cefcSMark Murray     NULL, /* fcc_retrieve */
518b528cefcSMark Murray     fcc_get_principal,
519b528cefcSMark Murray     fcc_get_first,
520b528cefcSMark Murray     fcc_get_next,
521b528cefcSMark Murray     fcc_end_get,
522b528cefcSMark Murray     fcc_remove_cred,
523b528cefcSMark Murray     fcc_set_flags,
524b528cefcSMark Murray     fcc_get_version
525b528cefcSMark Murray };
526