2 * lib/krb5/ccache/cc_file.c
4 * Copyright 1990,1991,1992,1993,1994,2000,2004,2007 Massachusetts Institute of Technology.
7 * Original stdio support copyright 1995 by Cygnus Support.
9 * Export of this software from the United States of America may
10 * require a specific license from the United States Government.
11 * It is the responsibility of any person or organization contemplating
12 * export to obtain such a license before exporting.
14 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15 * distribute this software and its documentation for any purpose and
16 * without fee is hereby granted, provided that the above copyright
17 * notice appear in all copies and that both that copyright notice and
18 * this permission notice appear in supporting documentation, and that
19 * the name of M.I.T. not be used in advertising or publicity pertaining
20 * to distribution of the software without specific, written prior
21 * permission. Furthermore if you modify this software you must label
22 * your software as modified software and not distribute it in such a
23 * fashion that it might be confused with the original M.I.T. software.
24 * M.I.T. makes no representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
29 * implementation of file-based credentials cache
33 If OPENCLOSE is defined, each of the functions opens and closes the
34 file whenever it needs to access it. Otherwise, the file is opened
35 once in initialize and closed once is close.
37 This library depends on UNIX-like file descriptors, and UNIX-like
38 behavior from the functions: open, close, read, write, lseek.
40 The quasi-BNF grammar for a credentials cache:
43 principal list-of-credentials
56 number of components (int32)
63 string of length bytes
68 Make sure that each time a function returns KRB5_NOMEM, everything
69 allocated earlier in the function and stack tree is freed.
73 Use pread/pwrite if available, so multiple threads can read
74 simultaneously. (That may require reader/writer locks.)
76 fcc_nseq.c and fcc_read don't check return values a lot.
88 #ifdef HAVE_NETINET_IN_H
90 #include <netinet/in.h>
92 #include "port-sockets.h"
95 # error find some way to use net-byte-order file version numbers.
98 static krb5_error_code KRB5_CALLCONV krb5_fcc_close
99 (krb5_context, krb5_ccache id);
101 static krb5_error_code KRB5_CALLCONV krb5_fcc_destroy
102 (krb5_context, krb5_ccache id);
104 static krb5_error_code KRB5_CALLCONV krb5_fcc_end_seq_get
105 (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor);
107 static krb5_error_code KRB5_CALLCONV krb5_fcc_generate_new
108 (krb5_context, krb5_ccache *id);
110 static const char * KRB5_CALLCONV krb5_fcc_get_name
111 (krb5_context, krb5_ccache id);
113 static krb5_error_code KRB5_CALLCONV krb5_fcc_get_principal
114 (krb5_context, krb5_ccache id, krb5_principal *princ);
116 static krb5_error_code KRB5_CALLCONV krb5_fcc_initialize
117 (krb5_context, krb5_ccache id, krb5_principal princ);
119 static krb5_error_code KRB5_CALLCONV krb5_fcc_next_cred
120 (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor,
123 static krb5_error_code krb5_fcc_read
124 (krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len);
125 static krb5_error_code krb5_fcc_read_principal
126 (krb5_context, krb5_ccache id, krb5_principal *princ);
127 static krb5_error_code krb5_fcc_read_keyblock
128 (krb5_context, krb5_ccache id, krb5_keyblock *keyblock);
129 static krb5_error_code krb5_fcc_read_data
130 (krb5_context, krb5_ccache id, krb5_data *data);
131 static krb5_error_code krb5_fcc_read_int32
132 (krb5_context, krb5_ccache id, krb5_int32 *i);
133 static krb5_error_code krb5_fcc_read_ui_2
134 (krb5_context, krb5_ccache id, krb5_ui_2 *i);
135 static krb5_error_code krb5_fcc_read_octet
136 (krb5_context, krb5_ccache id, krb5_octet *i);
137 static krb5_error_code krb5_fcc_read_times
138 (krb5_context, krb5_ccache id, krb5_ticket_times *t);
139 static krb5_error_code krb5_fcc_read_addrs
140 (krb5_context, krb5_ccache, krb5_address ***);
141 static krb5_error_code krb5_fcc_read_addr
142 (krb5_context, krb5_ccache, krb5_address *);
143 static krb5_error_code krb5_fcc_read_authdata
144 (krb5_context, krb5_ccache, krb5_authdata ***);
145 static krb5_error_code krb5_fcc_read_authdatum
146 (krb5_context, krb5_ccache, krb5_authdata *);
148 static krb5_error_code KRB5_CALLCONV krb5_fcc_resolve
149 (krb5_context, krb5_ccache *id, const char *residual);
151 static krb5_error_code KRB5_CALLCONV krb5_fcc_retrieve
152 (krb5_context, krb5_ccache id, krb5_flags whichfields,
153 krb5_creds *mcreds, krb5_creds *creds);
155 static krb5_error_code KRB5_CALLCONV krb5_fcc_start_seq_get
156 (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor);
158 static krb5_error_code KRB5_CALLCONV krb5_fcc_store
159 (krb5_context, krb5_ccache id, krb5_creds *creds);
161 static krb5_error_code krb5_fcc_skip_header
162 (krb5_context, krb5_ccache);
163 static krb5_error_code krb5_fcc_skip_principal
164 (krb5_context, krb5_ccache id);
166 static krb5_error_code KRB5_CALLCONV krb5_fcc_set_flags
167 (krb5_context, krb5_ccache id, krb5_flags flags);
169 static krb5_error_code KRB5_CALLCONV krb5_fcc_ptcursor_new
170 (krb5_context context, krb5_cc_ptcursor *cursor);
172 static krb5_error_code KRB5_CALLCONV krb5_fcc_ptcursor_next
173 (krb5_context context, krb5_cc_ptcursor cursor, krb5_ccache *ccache);
175 static krb5_error_code KRB5_CALLCONV krb5_fcc_ptcursor_free
176 (krb5_context context, krb5_cc_ptcursor *cursor);
178 static krb5_error_code KRB5_CALLCONV krb5_fcc_last_change_time
179 (krb5_context context, krb5_ccache id, krb5_timestamp *change_time);
181 static krb5_error_code KRB5_CALLCONV krb5_fcc_lock
182 (krb5_context context, krb5_ccache id);
184 static krb5_error_code KRB5_CALLCONV krb5_fcc_unlock
185 (krb5_context context, krb5_ccache id);
188 extern const krb5_cc_ops krb5_cc_file_ops;
190 krb5_error_code krb5_change_cache (void);
192 static krb5_error_code krb5_fcc_write
193 (krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len);
194 static krb5_error_code krb5_fcc_store_principal
195 (krb5_context, krb5_ccache id, krb5_principal princ);
196 static krb5_error_code krb5_fcc_store_keyblock
197 (krb5_context, krb5_ccache id, krb5_keyblock *keyblock);
198 static krb5_error_code krb5_fcc_store_data
199 (krb5_context, krb5_ccache id, krb5_data *data);
200 static krb5_error_code krb5_fcc_store_int32
201 (krb5_context, krb5_ccache id, krb5_int32 i);
202 static krb5_error_code krb5_fcc_store_ui_4
203 (krb5_context, krb5_ccache id, krb5_ui_4 i);
204 static krb5_error_code krb5_fcc_store_ui_2
205 (krb5_context, krb5_ccache id, krb5_int32 i);
206 static krb5_error_code krb5_fcc_store_octet
207 (krb5_context, krb5_ccache id, krb5_int32 i);
208 static krb5_error_code krb5_fcc_store_times
209 (krb5_context, krb5_ccache id, krb5_ticket_times *t);
210 static krb5_error_code krb5_fcc_store_addrs
211 (krb5_context, krb5_ccache, krb5_address **);
212 static krb5_error_code krb5_fcc_store_addr
213 (krb5_context, krb5_ccache, krb5_address *);
214 static krb5_error_code krb5_fcc_store_authdata
215 (krb5_context, krb5_ccache, krb5_authdata **);
216 static krb5_error_code krb5_fcc_store_authdatum
217 (krb5_context, krb5_ccache, krb5_authdata *);
219 static krb5_error_code krb5_fcc_interpret
222 struct _krb5_fcc_data;
223 static krb5_error_code krb5_fcc_close_file
224 (krb5_context, struct _krb5_fcc_data *data);
225 static krb5_error_code krb5_fcc_open_file
226 (krb5_context, krb5_ccache, int);
227 static krb5_error_code krb5_fcc_data_last_change_time
228 (krb5_context context, struct _krb5_fcc_data *data,
229 krb5_timestamp *change_time);
234 #define KRB5_FCC_MAXLEN 100
237 * FCC version 2 contains type information for principals. FCC
238 * version 1 does not.
240 * FCC version 3 contains keyblock encryption type information, and is
241 * architecture independent. Previous versions are not.
243 * The code will accept version 1, 2, and 3 ccaches, and depending
244 * what KRB5_FCC_DEFAULT_FVNO is set to, it will create version 1, 2,
247 * The default credentials cache should be type 3 for now (see
251 #define KRB5_FCC_FVNO_1 0x0501 /* krb v5, fcc v1 */
252 #define KRB5_FCC_FVNO_2 0x0502 /* krb v5, fcc v2 */
253 #define KRB5_FCC_FVNO_3 0x0503 /* krb v5, fcc v3 */
254 #define KRB5_FCC_FVNO_4 0x0504 /* krb v5, fcc v4 */
256 #define FCC_OPEN_AND_ERASE 1
257 #define FCC_OPEN_RDWR 2
258 #define FCC_OPEN_RDONLY 3
260 /* Credential file header tags.
261 * The header tags are constructed as:
264 * krb5_octet data[len]
265 * This format allows for older versions of the fcc processing code to skip
266 * past unrecognized tag formats.
268 #define FCC_TAG_DELTATIME 1
271 #ifdef MSDOS_FILESYSTEM
272 #define TKT_ROOT "\\tkt"
274 #define TKT_ROOT "/tmp/tkt"
278 /* macros to make checking flags easier */
279 #define OPENCLOSE(id) (((krb5_fcc_data *)id->data)->flags & KRB5_TC_OPENCLOSE)
281 typedef struct _krb5_fcc_data {
283 /* Lock this one before reading or modifying the data stored here
284 that can be changed. (Filename is fixed after
289 int mode; /* needed for locking code */
290 int version; /* version number of the file */
292 /* Buffer data on reading, for performance.
293 We used to have a stdio option, but we get more precise control
294 by using the POSIX I/O functions. */
295 #define FCC_BUFSIZ 1024
298 char buf[FCC_BUFSIZ];
301 static inline void invalidate_cache(krb5_fcc_data *data)
303 data->valid_bytes = 0;
306 static off_t fcc_lseek(krb5_fcc_data *data, off_t offset, int whence)
308 /* If we read some extra data in advance, and then want to know or
309 use our "current" position, we need to back up a little. */
310 if (whence == SEEK_CUR && data->valid_bytes) {
311 assert(data->valid_bytes > 0);
312 assert(data->cur_offset > 0);
313 assert(data->cur_offset <= data->valid_bytes);
314 offset -= (data->valid_bytes - data->cur_offset);
316 invalidate_cache(data);
317 return lseek(data->file, offset, whence);
321 struct fcc_set *next;
323 unsigned int refcount;
326 k5_cc_mutex krb5int_cc_file_mutex = K5_CC_MUTEX_PARTIAL_INITIALIZER;
327 static struct fcc_set *fccs = NULL;
329 /* Iterator over file caches. */
330 struct krb5_fcc_ptcursor_data {
334 /* An off_t can be arbitrarily complex */
335 typedef struct _krb5_fcc_cursor {
339 #define MAYBE_OPEN(CONTEXT, ID, MODE) \
341 k5_cc_mutex_assert_locked(CONTEXT, &((krb5_fcc_data *)(ID)->data)->lock); \
342 if (OPENCLOSE (ID)) { \
343 krb5_error_code maybe_open_ret; \
344 maybe_open_ret = krb5_fcc_open_file (CONTEXT,ID,MODE); \
345 if (maybe_open_ret) { \
346 k5_cc_mutex_unlock(CONTEXT, &((krb5_fcc_data *)(ID)->data)->lock); \
347 return maybe_open_ret; \
352 #define MAYBE_CLOSE(CONTEXT, ID, RET) \
354 if (OPENCLOSE (ID)) { \
355 krb5_error_code maybe_close_ret; \
356 maybe_close_ret = krb5_fcc_close_file (CONTEXT, \
357 (krb5_fcc_data *)(ID)->data); \
358 if (!(RET)) RET = maybe_close_ret; } }
360 #define MAYBE_CLOSE_IGNORE(CONTEXT, ID) \
362 if (OPENCLOSE (ID)) { \
363 (void) krb5_fcc_close_file (CONTEXT,(krb5_fcc_data *)(ID)->data); } }
365 #define CHECK(ret) if (ret != KRB5_OK) goto errout;
371 * Reads len bytes from the cache id, storing them in buf.
374 * Must be called with mutex locked.
377 * KRB5_CC_END - there were not len bytes available
378 * system errors (read)
380 static krb5_error_code
381 krb5_fcc_read(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned int len)
386 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
388 ret = read(((krb5_fcc_data *) id->data)->file, (char *) buf, len);
390 return krb5_fcc_interpret(context, errno);
396 krb5_fcc_data *data = (krb5_fcc_data *) id->data;
398 k5_cc_mutex_assert_locked(context, &data->lock);
404 assert (data->valid_bytes >= 0);
405 if (data->valid_bytes > 0)
406 assert(data->cur_offset <= data->valid_bytes);
407 if (data->valid_bytes == 0
408 || data->cur_offset == data->valid_bytes) {
409 /* Fill buffer from current file position. */
410 nread = read(data->file, data->buf, sizeof(data->buf));
413 return krb5_fcc_interpret(context, e);
417 data->valid_bytes = nread;
418 data->cur_offset = 0;
420 assert(data->cur_offset < data->valid_bytes);
422 assert(ncopied == len);
423 if (data->valid_bytes - data->cur_offset < ncopied)
424 ncopied = data->valid_bytes - data->cur_offset;
425 memcpy(buf, data->buf + data->cur_offset, ncopied);
426 data->cur_offset += ncopied;
427 assert(data->cur_offset > 0);
428 assert(data->cur_offset <= data->valid_bytes);
431 /* Don't do arithmetic on void pointers. */
432 buf = (char*)buf + ncopied;
439 * FOR ALL OF THE FOLLOWING FUNCTIONS:
442 * id is open and set to read at the appropriate place in the file
447 * Fills in the second argument with data of the appropriate type from
448 * the file. In some cases, the functions have to allocate space for
449 * variable length fields; therefore, krb5_destroy_<type> must be
450 * called for each filled in structure.
453 * system errors (read errors)
457 #define ALLOC(NUM,TYPE) \
458 (((NUM) <= (((size_t)0-1)/ sizeof(TYPE))) \
459 ? (TYPE *) calloc((NUM), sizeof(TYPE)) \
460 : (errno = ENOMEM,(TYPE *) 0))
462 static krb5_error_code
463 krb5_fcc_read_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
465 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
466 krb5_error_code kret;
467 register krb5_principal tmpprinc;
468 krb5_int32 length, type;
471 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
475 if (data->version == KRB5_FCC_FVNO_1) {
476 type = KRB5_NT_UNKNOWN;
478 /* Read principal type */
479 kret = krb5_fcc_read_int32(context, id, &type);
484 /* Read the number of components */
485 kret = krb5_fcc_read_int32(context, id, &length);
490 * DCE includes the principal's realm in the count; the new format
493 if (data->version == KRB5_FCC_FVNO_1)
496 return KRB5_CC_NOMEM;
498 tmpprinc = (krb5_principal) malloc(sizeof(krb5_principal_data));
499 if (tmpprinc == NULL)
500 return KRB5_CC_NOMEM;
502 size_t msize = length;
503 if (msize != length) {
505 return KRB5_CC_NOMEM;
507 tmpprinc->data = ALLOC (msize, krb5_data);
508 if (tmpprinc->data == 0) {
510 return KRB5_CC_NOMEM;
514 tmpprinc->magic = KV5M_PRINCIPAL;
515 tmpprinc->length = length;
516 tmpprinc->type = type;
518 kret = krb5_fcc_read_data(context, id, krb5_princ_realm(context, tmpprinc));
523 for (i=0; i < length; i++) {
524 kret = krb5_fcc_read_data(context, id, krb5_princ_component(context, tmpprinc, i));
532 free(krb5_princ_component(context, tmpprinc, i)->data);
533 free(krb5_princ_realm(context, tmpprinc)->data);
534 free(tmpprinc->data);
539 static krb5_error_code
540 krb5_fcc_read_addrs(krb5_context context, krb5_ccache id, krb5_address ***addrs)
542 krb5_error_code kret;
547 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
551 /* Read the number of components */
552 kret = krb5_fcc_read_int32(context, id, &length);
555 /* Make *addrs able to hold length pointers to krb5_address structs
556 * Add one extra for a null-terminated list
560 if (msize == 0 || msize - 1 != length || length < 0)
561 return KRB5_CC_NOMEM;
562 *addrs = ALLOC (msize, krb5_address *);
564 return KRB5_CC_NOMEM;
566 for (i=0; i < length; i++) {
567 (*addrs)[i] = (krb5_address *) malloc(sizeof(krb5_address));
568 if ((*addrs)[i] == NULL) {
569 krb5_free_addresses(context, *addrs);
571 return KRB5_CC_NOMEM;
573 (*addrs)[i]->contents = NULL;
574 kret = krb5_fcc_read_addr(context, id, (*addrs)[i]);
581 krb5_free_addresses(context, *addrs);
587 static krb5_error_code
588 krb5_fcc_read_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyblock)
590 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
591 krb5_error_code kret;
595 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
597 keyblock->magic = KV5M_KEYBLOCK;
598 keyblock->contents = 0;
600 kret = krb5_fcc_read_ui_2(context, id, &ui2);
601 keyblock->enctype = ui2;
603 if (data->version == KRB5_FCC_FVNO_3) {
604 /* This works because the old etype is the same as the new enctype. */
605 kret = krb5_fcc_read_ui_2(context, id, &ui2);
606 /* keyblock->enctype = ui2; */
610 kret = krb5_fcc_read_int32(context, id, &int32);
613 return KRB5_CC_NOMEM;
614 keyblock->length = int32;
615 /* Overflow check. */
616 if (keyblock->length != int32)
617 return KRB5_CC_NOMEM;
618 if ( keyblock->length == 0 )
620 keyblock->contents = ALLOC (keyblock->length, krb5_octet);
621 if (keyblock->contents == NULL)
622 return KRB5_CC_NOMEM;
624 kret = krb5_fcc_read(context, id, keyblock->contents, keyblock->length);
630 if (keyblock->contents) {
631 free(keyblock->contents);
632 keyblock->contents = NULL;
637 static krb5_error_code
638 krb5_fcc_read_data(krb5_context context, krb5_ccache id, krb5_data *data)
640 krb5_error_code kret;
643 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
645 data->magic = KV5M_DATA;
648 kret = krb5_fcc_read_int32(context, id, &len);
651 return KRB5_CC_NOMEM;
653 if (data->length != len || data->length + 1 == 0)
654 return KRB5_CC_NOMEM;
656 if (data->length == 0) {
661 data->data = (char *) malloc(data->length+1);
662 if (data->data == NULL)
663 return KRB5_CC_NOMEM;
665 kret = krb5_fcc_read(context, id, data->data, (unsigned) data->length);
668 data->data[data->length] = 0; /* Null terminate, just in case.... */
678 static krb5_error_code
679 krb5_fcc_read_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
681 krb5_error_code kret;
685 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
687 addr->magic = KV5M_ADDRESS;
690 kret = krb5_fcc_read_ui_2(context, id, &ui2);
692 addr->addrtype = ui2;
694 kret = krb5_fcc_read_int32(context, id, &int32);
696 if ((int32 & VALID_INT_BITS) != int32) /* Overflow int??? */
697 return KRB5_CC_NOMEM;
698 addr->length = int32;
699 /* Length field is "unsigned int", which may be smaller than 32
701 if (addr->length != int32)
702 return KRB5_CC_NOMEM; /* XXX */
704 if (addr->length == 0)
707 addr->contents = (krb5_octet *) malloc(addr->length);
708 if (addr->contents == NULL)
709 return KRB5_CC_NOMEM;
711 kret = krb5_fcc_read(context, id, addr->contents, addr->length);
716 if (addr->contents) {
717 free(addr->contents);
718 addr->contents = NULL;
723 static krb5_error_code
724 krb5_fcc_read_int32(krb5_context context, krb5_ccache id, krb5_int32 *i)
726 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
727 krb5_error_code retval;
728 unsigned char buf[4];
731 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
733 if ((data->version == KRB5_FCC_FVNO_1) ||
734 (data->version == KRB5_FCC_FVNO_2))
735 return krb5_fcc_read(context, id, (krb5_pointer) i, sizeof(krb5_int32));
737 retval = krb5_fcc_read(context, id, buf, 4);
741 val = (val << 8) | buf[1];
742 val = (val << 8) | buf[2];
743 val = (val << 8) | buf[3];
749 static krb5_error_code
750 krb5_fcc_read_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 *i)
752 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
753 krb5_error_code retval;
754 unsigned char buf[2];
756 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
758 if ((data->version == KRB5_FCC_FVNO_1) ||
759 (data->version == KRB5_FCC_FVNO_2))
760 return krb5_fcc_read(context, id, (krb5_pointer) i, sizeof(krb5_ui_2));
762 retval = krb5_fcc_read(context, id, buf, 2);
765 *i = (buf[0] << 8) + buf[1];
770 static krb5_error_code
771 krb5_fcc_read_octet(krb5_context context, krb5_ccache id, krb5_octet *i)
773 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
774 return krb5_fcc_read(context, id, (krb5_pointer) i, 1);
778 static krb5_error_code
779 krb5_fcc_read_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
781 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
782 krb5_error_code retval;
785 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
787 if ((data->version == KRB5_FCC_FVNO_1) ||
788 (data->version == KRB5_FCC_FVNO_2))
789 return krb5_fcc_read(context, id, (krb5_pointer) t, sizeof(krb5_ticket_times));
791 retval = krb5_fcc_read_int32(context, id, &i);
795 retval = krb5_fcc_read_int32(context, id, &i);
799 retval = krb5_fcc_read_int32(context, id, &i);
803 retval = krb5_fcc_read_int32(context, id, &i);
812 static krb5_error_code
813 krb5_fcc_read_authdata(krb5_context context, krb5_ccache id, krb5_authdata ***a)
815 krb5_error_code kret;
820 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
824 /* Read the number of components */
825 kret = krb5_fcc_read_int32(context, id, &length);
831 /* Make *a able to hold length pointers to krb5_authdata structs
832 * Add one extra for a null-terminated list
836 if (msize == 0 || msize - 1 != length || length < 0)
837 return KRB5_CC_NOMEM;
838 *a = ALLOC (msize, krb5_authdata *);
840 return KRB5_CC_NOMEM;
842 for (i=0; i < length; i++) {
843 (*a)[i] = (krb5_authdata *) malloc(sizeof(krb5_authdata));
844 if ((*a)[i] == NULL) {
845 krb5_free_authdata(context, *a);
847 return KRB5_CC_NOMEM;
849 (*a)[i]->contents = NULL;
850 kret = krb5_fcc_read_authdatum(context, id, (*a)[i]);
857 krb5_free_authdata(context, *a);
863 static krb5_error_code
864 krb5_fcc_read_authdatum(krb5_context context, krb5_ccache id, krb5_authdata *a)
866 krb5_error_code kret;
870 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
872 a->magic = KV5M_AUTHDATA;
875 kret = krb5_fcc_read_ui_2(context, id, &ui2);
877 a->ad_type = (krb5_authdatatype)ui2;
878 kret = krb5_fcc_read_int32(context, id, &int32);
880 if ((int32 & VALID_INT_BITS) != int32) /* Overflow int??? */
881 return KRB5_CC_NOMEM;
883 /* Value could have gotten truncated if int is smaller than 32
885 if (a->length != int32)
886 return KRB5_CC_NOMEM; /* XXX */
891 a->contents = (krb5_octet *) malloc(a->length);
892 if (a->contents == NULL)
893 return KRB5_CC_NOMEM;
895 kret = krb5_fcc_read(context, id, a->contents, a->length);
909 #define CHECK(ret) if (ret != KRB5_OK) return ret;
916 * Writes len bytes from buf into the file cred cache id.
921 static krb5_error_code
922 krb5_fcc_write(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned int len)
926 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
927 invalidate_cache((krb5_fcc_data *) id->data);
929 ret = write(((krb5_fcc_data *)id->data)->file, (char *) buf, len);
931 return krb5_fcc_interpret(context, errno);
933 return KRB5_CC_WRITE;
938 * FOR ALL OF THE FOLLOWING FUNCTIONS:
941 * ((krb5_fcc_data *) id->data)->file is open and at the right position.
946 * Stores an encoded version of the second argument in the
953 static krb5_error_code
954 krb5_fcc_store_principal(krb5_context context, krb5_ccache id, krb5_principal princ)
956 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
958 krb5_int32 i, length, tmp, type;
960 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
962 type = krb5_princ_type(context, princ);
963 tmp = length = krb5_princ_size(context, princ);
965 if (data->version == KRB5_FCC_FVNO_1) {
967 * DCE-compatible format means that the length count
968 * includes the realm. (It also doesn't include the
969 * principal type information.)
973 ret = krb5_fcc_store_int32(context, id, type);
977 ret = krb5_fcc_store_int32(context, id, tmp);
980 ret = krb5_fcc_store_data(context, id, krb5_princ_realm(context, princ));
983 for (i=0; i < length; i++) {
984 ret = krb5_fcc_store_data(context, id, krb5_princ_component(context, princ, i));
991 static krb5_error_code
992 krb5_fcc_store_addrs(krb5_context context, krb5_ccache id, krb5_address **addrs)
996 krb5_int32 i, length = 0;
998 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1000 /* Count the number of components */
1007 ret = krb5_fcc_store_int32(context, id, length);
1009 for (i=0; i < length; i++) {
1010 ret = krb5_fcc_store_addr(context, id, addrs[i]);
1017 static krb5_error_code
1018 krb5_fcc_store_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyblock)
1020 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1021 krb5_error_code ret;
1023 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1025 ret = krb5_fcc_store_ui_2(context, id, keyblock->enctype);
1027 if (data->version == KRB5_FCC_FVNO_3) {
1028 ret = krb5_fcc_store_ui_2(context, id, keyblock->enctype);
1031 ret = krb5_fcc_store_ui_4(context, id, keyblock->length);
1033 return krb5_fcc_write(context, id, (char *) keyblock->contents, keyblock->length);
1036 static krb5_error_code
1037 krb5_fcc_store_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
1039 krb5_error_code ret;
1041 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1043 ret = krb5_fcc_store_ui_2(context, id, addr->addrtype);
1045 ret = krb5_fcc_store_ui_4(context, id, addr->length);
1047 return krb5_fcc_write(context, id, (char *) addr->contents, addr->length);
1051 static krb5_error_code
1052 krb5_fcc_store_data(krb5_context context, krb5_ccache id, krb5_data *data)
1054 krb5_error_code ret;
1056 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1058 ret = krb5_fcc_store_ui_4(context, id, data->length);
1060 return krb5_fcc_write(context, id, data->data, data->length);
1063 static krb5_error_code
1064 krb5_fcc_store_int32(krb5_context context, krb5_ccache id, krb5_int32 i)
1066 return krb5_fcc_store_ui_4(context, id, (krb5_ui_4) i);
1069 static krb5_error_code
1070 krb5_fcc_store_ui_4(krb5_context context, krb5_ccache id, krb5_ui_4 i)
1072 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1073 unsigned char buf[4];
1075 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1077 if ((data->version == KRB5_FCC_FVNO_1) ||
1078 (data->version == KRB5_FCC_FVNO_2))
1079 return krb5_fcc_write(context, id, (char *) &i, sizeof(krb5_int32));
1081 buf[3] = (unsigned char) (i & 0xFF);
1083 buf[2] = (unsigned char) (i & 0xFF);
1085 buf[1] = (unsigned char) (i & 0xFF);
1087 buf[0] = (unsigned char) (i & 0xFF);
1088 return krb5_fcc_write(context, id, buf, 4);
1092 static krb5_error_code
1093 krb5_fcc_store_ui_2(krb5_context context, krb5_ccache id, krb5_int32 i)
1095 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1097 unsigned char buf[2];
1099 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1101 if ((data->version == KRB5_FCC_FVNO_1) ||
1102 (data->version == KRB5_FCC_FVNO_2)) {
1103 ibuf = (krb5_ui_2) i;
1104 return krb5_fcc_write(context, id, (char *) &ibuf, sizeof(krb5_ui_2));
1106 buf[1] = (unsigned char) (i & 0xFF);
1108 buf[0] = (unsigned char) (i & 0xFF);
1109 return krb5_fcc_write(context, id, buf, 2);
1113 static krb5_error_code
1114 krb5_fcc_store_octet(krb5_context context, krb5_ccache id, krb5_int32 i)
1118 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1120 ibuf = (krb5_octet) i;
1121 return krb5_fcc_write(context, id, (char *) &ibuf, 1);
1124 static krb5_error_code
1125 krb5_fcc_store_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
1127 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1128 krb5_error_code retval;
1130 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1132 if ((data->version == KRB5_FCC_FVNO_1) ||
1133 (data->version == KRB5_FCC_FVNO_2))
1134 return krb5_fcc_write(context, id, (char *) t, sizeof(krb5_ticket_times));
1136 retval = krb5_fcc_store_int32(context, id, t->authtime);
1138 retval = krb5_fcc_store_int32(context, id, t->starttime);
1140 retval = krb5_fcc_store_int32(context, id, t->endtime);
1142 retval = krb5_fcc_store_int32(context, id, t->renew_till);
1148 static krb5_error_code
1149 krb5_fcc_store_authdata(krb5_context context, krb5_ccache id, krb5_authdata **a)
1151 krb5_error_code ret;
1152 krb5_authdata **temp;
1153 krb5_int32 i, length=0;
1155 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1158 for (temp=a; *temp; temp++)
1162 ret = krb5_fcc_store_int32(context, id, length);
1164 for (i=0; i<length; i++) {
1165 ret = krb5_fcc_store_authdatum (context, id, a[i]);
1171 static krb5_error_code
1172 krb5_fcc_store_authdatum (krb5_context context, krb5_ccache id, krb5_authdata *a)
1174 krb5_error_code ret;
1176 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1178 ret = krb5_fcc_store_ui_2(context, id, a->ad_type);
1180 ret = krb5_fcc_store_ui_4(context, id, a->length);
1182 return krb5_fcc_write(context, id, (krb5_pointer) a->contents, a->length);
1186 static krb5_error_code
1187 krb5_fcc_close_file (krb5_context context, krb5_fcc_data *data)
1190 krb5_error_code retval;
1192 k5_cc_mutex_assert_locked(context, &data->lock);
1194 if (data->file == NO_FILE)
1195 return KRB5_FCC_INTERNAL;
1197 retval = krb5_unlock_file(context, data->file);
1198 ret = close (data->file);
1199 data->file = NO_FILE;
1203 return ret ? krb5_fcc_interpret (context, errno) : 0;
1206 #if defined(ANSI_STDIO) || defined(_WIN32)
1207 #define BINARY_MODE "b"
1209 #define BINARY_MODE ""
1212 #ifndef HAVE_SETVBUF
1214 #define setvbuf(FILE,BUF,MODE,SIZE) \
1215 ((SIZE) < BUFSIZE ? (abort(),0) : setbuf(FILE, BUF))
1218 static krb5_error_code
1219 krb5_fcc_open_file (krb5_context context, krb5_ccache id, int mode)
1221 krb5_os_context os_ctx = &context->os_context;
1222 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1226 krb5_ui_2 fcc_taglen;
1229 krb5_error_code retval = 0;
1231 k5_cc_mutex_assert_locked(context, &data->lock);
1232 invalidate_cache(data);
1234 if (data->file != NO_FILE) {
1235 /* Don't know what state it's in; shut down and start anew. */
1236 (void) krb5_unlock_file(context, data->file);
1237 (void) close (data->file);
1238 data->file = NO_FILE;
1242 case FCC_OPEN_AND_ERASE:
1243 unlink(data->filename);
1244 open_flag = O_CREAT|O_EXCL|O_TRUNC|O_RDWR;
1249 case FCC_OPEN_RDONLY:
1251 open_flag = O_RDONLY;
1255 f = THREEPARAMOPEN (data->filename, open_flag | O_BINARY, 0600);
1259 retval = KRB5_FCC_NOFILE;
1260 krb5_set_error_message(context, retval,
1261 "Credentials cache file '%s' not found",
1265 return krb5_fcc_interpret (context, errno);
1272 if (data->mode == FCC_OPEN_RDONLY)
1273 lock_flag = KRB5_LOCKMODE_SHARED;
1275 lock_flag = KRB5_LOCKMODE_EXCLUSIVE;
1276 if ((retval = krb5_lock_file(context, f, lock_flag))) {
1281 if (mode == FCC_OPEN_AND_ERASE) {
1282 /* write the version number */
1285 fcc_fvno = htons(context->fcc_default_format);
1286 data->version = context->fcc_default_format;
1287 if ((cnt = write(f, (char *)&fcc_fvno, sizeof(fcc_fvno))) !=
1289 retval = ((cnt == -1) ? krb5_fcc_interpret(context, errno) :
1295 if (data->version == KRB5_FCC_FVNO_4) {
1296 /* V4 of the credentials cache format allows for header tags */
1299 if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)
1300 fcc_flen += (2*sizeof(krb5_ui_2) + 2*sizeof(krb5_int32));
1302 /* Write header length */
1303 retval = krb5_fcc_store_ui_2(context, id, (krb5_int32)fcc_flen);
1304 if (retval) goto done;
1306 if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
1307 /* Write time offset tag */
1308 fcc_tag = FCC_TAG_DELTATIME;
1309 fcc_taglen = 2*sizeof(krb5_int32);
1311 retval = krb5_fcc_store_ui_2(context,id,(krb5_int32)fcc_tag);
1312 if (retval) goto done;
1313 retval = krb5_fcc_store_ui_2(context,id,(krb5_int32)fcc_taglen);
1314 if (retval) goto done;
1315 retval = krb5_fcc_store_int32(context,id,os_ctx->time_offset);
1316 if (retval) goto done;
1317 retval = krb5_fcc_store_int32(context,id,os_ctx->usec_offset);
1318 if (retval) goto done;
1321 invalidate_cache(data);
1325 /* verify a valid version number is there */
1326 invalidate_cache(data);
1327 if (read(f, (char *)&fcc_fvno, sizeof(fcc_fvno)) != sizeof(fcc_fvno)) {
1328 retval = KRB5_CC_FORMAT;
1331 data->version = ntohs(fcc_fvno);
1332 if ((data->version != KRB5_FCC_FVNO_4) &&
1333 (data->version != KRB5_FCC_FVNO_3) &&
1334 (data->version != KRB5_FCC_FVNO_2) &&
1335 (data->version != KRB5_FCC_FVNO_1)) {
1336 retval = KRB5_CCACHE_BADVNO;
1342 if (data->version == KRB5_FCC_FVNO_4) {
1345 if (krb5_fcc_read_ui_2(context, id, &fcc_flen) ||
1346 (fcc_flen > sizeof(buf)))
1348 retval = KRB5_CC_FORMAT;
1353 if ((fcc_flen < (2 * sizeof(krb5_ui_2))) ||
1354 krb5_fcc_read_ui_2(context, id, &fcc_tag) ||
1355 krb5_fcc_read_ui_2(context, id, &fcc_taglen) ||
1356 (fcc_taglen > (fcc_flen - 2*sizeof(krb5_ui_2))))
1358 retval = KRB5_CC_FORMAT;
1363 case FCC_TAG_DELTATIME:
1364 if (fcc_taglen != 2*sizeof(krb5_int32)) {
1365 retval = KRB5_CC_FORMAT;
1368 if (!(context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) ||
1369 (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID))
1371 if (krb5_fcc_read(context, id, buf, fcc_taglen)) {
1372 retval = KRB5_CC_FORMAT;
1377 if (krb5_fcc_read_int32(context, id, &os_ctx->time_offset) ||
1378 krb5_fcc_read_int32(context, id, &os_ctx->usec_offset))
1380 retval = KRB5_CC_FORMAT;
1384 ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
1385 KRB5_OS_TOFFSET_VALID);
1388 if (fcc_taglen && krb5_fcc_read(context,id,buf,fcc_taglen)) {
1389 retval = KRB5_CC_FORMAT;
1394 fcc_flen -= (2*sizeof(krb5_ui_2) + fcc_taglen);
1401 (void) krb5_unlock_file(context, f);
1407 static krb5_error_code
1408 krb5_fcc_skip_header(krb5_context context, krb5_ccache id)
1410 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1411 krb5_error_code kret;
1414 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1416 fcc_lseek(data, (off_t) sizeof(krb5_ui_2), SEEK_SET);
1417 if (data->version == KRB5_FCC_FVNO_4) {
1418 kret = krb5_fcc_read_ui_2(context, id, &fcc_flen);
1419 if (kret) return kret;
1420 if(fcc_lseek(data, (off_t) fcc_flen, SEEK_CUR) < 0)
1426 static krb5_error_code
1427 krb5_fcc_skip_principal(krb5_context context, krb5_ccache id)
1429 krb5_error_code kret;
1430 krb5_principal princ;
1432 k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock);
1434 kret = krb5_fcc_read_principal(context, id, &princ);
1435 if (kret != KRB5_OK)
1438 krb5_free_principal(context, princ);
1448 * Creates/refreshes the file cred cache id. If the cache exists, its
1449 * contents are destroyed.
1455 static krb5_error_code KRB5_CALLCONV
1456 krb5_fcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
1458 krb5_error_code kret = 0;
1461 kret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
1465 MAYBE_OPEN(context, id, FCC_OPEN_AND_ERASE);
1467 #if defined(HAVE_FCHMOD) || defined(HAVE_CHMOD)
1470 reti = fchmod(((krb5_fcc_data *) id->data)->file, S_IREAD | S_IWRITE);
1472 reti = chmod(((krb5_fcc_data *) id->data)->filename, S_IREAD | S_IWRITE);
1475 kret = krb5_fcc_interpret(context, errno);
1476 MAYBE_CLOSE(context, id, kret);
1477 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
1482 kret = krb5_fcc_store_principal(context, id, princ);
1484 MAYBE_CLOSE(context, id, kret);
1485 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
1486 krb5_change_cache ();
1491 * Drop the ref count; if it hits zero, remove the entry from the
1492 * fcc_set list and free it.
1494 static krb5_error_code dereference(krb5_context context, krb5_fcc_data *data)
1496 krb5_error_code kerr;
1497 struct fcc_set **fccsp;
1499 kerr = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
1502 for (fccsp = &fccs; *fccsp != NULL; fccsp = &(*fccsp)->next)
1503 if ((*fccsp)->data == data)
1505 assert(*fccsp != NULL);
1506 assert((*fccsp)->data == data);
1507 (*fccsp)->refcount--;
1508 if ((*fccsp)->refcount == 0) {
1509 struct fcc_set *temp;
1510 data = (*fccsp)->data;
1512 *fccsp = (*fccsp)->next;
1514 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1515 k5_cc_mutex_assert_unlocked(context, &data->lock);
1516 free(data->filename);
1517 zap(data->buf, sizeof(data->buf));
1518 if (data->file >= 0) {
1519 kerr = k5_cc_mutex_lock(context, &data->lock);
1522 krb5_fcc_close_file(context, data);
1523 k5_cc_mutex_unlock(context, &data->lock);
1525 k5_cc_mutex_destroy(&data->lock);
1528 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1537 * Closes the file cache, invalidates the id, and frees any resources
1538 * associated with the cache.
1540 static krb5_error_code KRB5_CALLCONV
1541 krb5_fcc_close(krb5_context context, krb5_ccache id)
1543 dereference(context, (krb5_fcc_data *) id->data);
1550 * Destroys the contents of id.
1555 static krb5_error_code KRB5_CALLCONV
1556 krb5_fcc_destroy(krb5_context context, krb5_ccache id)
1558 krb5_error_code kret = 0;
1559 krb5_fcc_data *data = (krb5_fcc_data *) id->data;
1563 unsigned long i, size;
1567 kret = k5_cc_mutex_lock(context, &data->lock);
1571 if (OPENCLOSE(id)) {
1572 invalidate_cache(data);
1573 ret = THREEPARAMOPEN(data->filename,
1574 O_RDWR | O_BINARY, 0);
1576 kret = krb5_fcc_interpret(context, errno);
1579 set_cloexec_fd(ret);
1583 fcc_lseek(data, (off_t) 0, SEEK_SET);
1585 #ifdef MSDOS_FILESYSTEM
1586 /* "disgusting bit of UNIX trivia" - that's how the writers of NFS describe
1587 ** the ability of UNIX to still write to a file which has been unlinked.
1588 ** Naturally, the PC can't do this. As a result, we have to delete the file
1589 ** after we wipe it clean but that throws off all the error handling code.
1590 ** So we have do the work ourselves.
1592 ret = fstat(data->file, &buf);
1594 kret = krb5_fcc_interpret(context, errno);
1595 size = 0; /* Nothing to wipe clean */
1597 size = (unsigned long) buf.st_size;
1599 memset(zeros, 0, BUFSIZ);
1601 wlen = (int) ((size > BUFSIZ) ? BUFSIZ : size); /* How much to write */
1602 i = write(data->file, zeros, wlen);
1604 kret = krb5_fcc_interpret(context, errno);
1605 /* Don't jump to cleanup--we still want to delete the file. */
1608 size -= i; /* We've read this much */
1611 if (OPENCLOSE(id)) {
1612 (void) close(((krb5_fcc_data *)id->data)->file);
1616 ret = unlink(data->filename);
1618 kret = krb5_fcc_interpret(context, errno);
1622 #else /* MSDOS_FILESYSTEM */
1624 ret = unlink(data->filename);
1626 kret = krb5_fcc_interpret(context, errno);
1627 if (OPENCLOSE(id)) {
1628 (void) close(((krb5_fcc_data *)id->data)->file);
1635 ret = fstat(data->file, &buf);
1637 kret = krb5_fcc_interpret(context, errno);
1638 if (OPENCLOSE(id)) {
1639 (void) close(((krb5_fcc_data *)id->data)->file);
1645 /* XXX This may not be legal XXX */
1646 size = (unsigned long) buf.st_size;
1647 memset(zeros, 0, BUFSIZ);
1648 for (i=0; i < size / BUFSIZ; i++)
1649 if (write(data->file, zeros, BUFSIZ) < 0) {
1650 kret = krb5_fcc_interpret(context, errno);
1651 if (OPENCLOSE(id)) {
1652 (void) close(((krb5_fcc_data *)id->data)->file);
1658 wlen = (unsigned int) (size % BUFSIZ);
1659 if (write(data->file, zeros, wlen) < 0) {
1660 kret = krb5_fcc_interpret(context, errno);
1661 if (OPENCLOSE(id)) {
1662 (void) close(((krb5_fcc_data *)id->data)->file);
1668 ret = close(data->file);
1672 kret = krb5_fcc_interpret(context, errno);
1674 #endif /* MSDOS_FILESYSTEM */
1677 k5_cc_mutex_unlock(context, &data->lock);
1678 dereference(context, data);
1681 krb5_change_cache ();
1685 extern const krb5_cc_ops krb5_fcc_ops;
1689 * residual is a legal path name, and a null-terminated string
1695 * creates a file-based cred cache that will reside in the file
1696 * residual. The cache is not opened, but the filename is reserved.
1699 * A filled in krb5_ccache structure "id".
1702 * KRB5_CC_NOMEM - there was insufficient memory to allocate the
1703 * krb5_ccache. id is undefined.
1706 static krb5_error_code KRB5_CALLCONV
1707 krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
1710 krb5_error_code kret;
1711 krb5_fcc_data *data;
1712 struct fcc_set *setptr;
1714 kret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
1717 for (setptr = fccs; setptr; setptr = setptr->next) {
1718 if (!strcmp(setptr->data->filename, residual))
1722 data = setptr->data;
1723 assert(setptr->refcount != 0);
1725 assert(setptr->refcount != 0);
1726 kret = k5_cc_mutex_lock(context, &data->lock);
1728 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1731 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1733 data = malloc(sizeof(krb5_fcc_data));
1735 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1736 return KRB5_CC_NOMEM;
1738 data->filename = strdup(residual);
1739 if (data->filename == NULL) {
1740 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1742 return KRB5_CC_NOMEM;
1744 kret = k5_cc_mutex_init(&data->lock);
1746 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1747 free(data->filename);
1751 kret = k5_cc_mutex_lock(context, &data->lock);
1753 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1754 k5_cc_mutex_destroy(&data->lock);
1755 free(data->filename);
1759 /* data->version,mode filled in for real later */
1760 data->version = data->mode = 0;
1761 data->flags = KRB5_TC_OPENCLOSE;
1763 data->valid_bytes = 0;
1764 setptr = malloc(sizeof(struct fcc_set));
1765 if (setptr == NULL) {
1766 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1767 k5_cc_mutex_unlock(context, &data->lock);
1768 k5_cc_mutex_destroy(&data->lock);
1769 free(data->filename);
1771 return KRB5_CC_NOMEM;
1773 setptr->refcount = 1;
1774 setptr->data = data;
1775 setptr->next = fccs;
1777 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
1780 k5_cc_mutex_assert_locked(context, &data->lock);
1781 k5_cc_mutex_unlock(context, &data->lock);
1782 lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
1784 dereference(context, data);
1785 return KRB5_CC_NOMEM;
1788 lid->ops = &krb5_fcc_ops;
1790 lid->magic = KV5M_CCACHE;
1792 /* other routines will get errors on open, and callers must expect them,
1793 if cache is non-existent/unusable */
1800 * Prepares for a sequential search of the credentials cache.
1801 * Returns and krb5_cc_cursor to be used with krb5_fcc_next_cred and
1802 * krb5_fcc_end_seq_get.
1804 * If the cache is modified between the time of this call and the time
1805 * of the final krb5_fcc_end_seq_get, the results are undefined.
1811 static krb5_error_code KRB5_CALLCONV
1812 krb5_fcc_start_seq_get(krb5_context context, krb5_ccache id,
1813 krb5_cc_cursor *cursor)
1815 krb5_fcc_cursor *fcursor;
1816 krb5_error_code kret = KRB5_OK;
1817 krb5_fcc_data *data = (krb5_fcc_data *)id->data;
1819 kret = k5_cc_mutex_lock(context, &data->lock);
1823 fcursor = (krb5_fcc_cursor *) malloc(sizeof(krb5_fcc_cursor));
1824 if (fcursor == NULL) {
1825 k5_cc_mutex_unlock(context, &data->lock);
1826 return KRB5_CC_NOMEM;
1828 if (OPENCLOSE(id)) {
1829 kret = krb5_fcc_open_file(context, id, FCC_OPEN_RDONLY);
1832 k5_cc_mutex_unlock(context, &data->lock);
1837 /* Make sure we start reading right after the primary principal */
1838 kret = krb5_fcc_skip_header(context, id);
1843 kret = krb5_fcc_skip_principal(context, id);
1849 fcursor->pos = fcc_lseek(data, (off_t) 0, SEEK_CUR);
1850 *cursor = (krb5_cc_cursor) fcursor;
1853 MAYBE_CLOSE(context, id, kret);
1854 k5_cc_mutex_unlock(context, &data->lock);
1861 * cursor is a krb5_cc_cursor originally obtained from
1862 * krb5_fcc_start_seq_get.
1868 * Fills in creds with the "next" credentals structure from the cache
1869 * id. The actual order the creds are returned in is arbitrary.
1870 * Space is allocated for the variable length fields in the
1871 * credentials structure, so the object returned must be passed to
1872 * krb5_destroy_credential.
1874 * The cursor is updated for the next call to krb5_fcc_next_cred.
1879 static krb5_error_code KRB5_CALLCONV
1880 krb5_fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
1883 #define TCHECK(ret) if (ret != KRB5_OK) goto lose;
1884 krb5_error_code kret;
1885 krb5_fcc_cursor *fcursor;
1888 krb5_fcc_data *d = (krb5_fcc_data *) id->data;
1890 kret = k5_cc_mutex_lock(context, &d->lock);
1894 memset((char *)creds, 0, sizeof(*creds));
1895 MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
1896 fcursor = (krb5_fcc_cursor *) *cursor;
1898 kret = (fcc_lseek(d, fcursor->pos, SEEK_SET) == (off_t) -1);
1900 kret = krb5_fcc_interpret(context, errno);
1901 MAYBE_CLOSE(context, id, kret);
1902 k5_cc_mutex_unlock(context, &d->lock);
1906 kret = krb5_fcc_read_principal(context, id, &creds->client);
1908 kret = krb5_fcc_read_principal(context, id, &creds->server);
1910 kret = krb5_fcc_read_keyblock(context, id, &creds->keyblock);
1912 kret = krb5_fcc_read_times(context, id, &creds->times);
1914 kret = krb5_fcc_read_octet(context, id, &octet);
1916 creds->is_skey = octet;
1917 kret = krb5_fcc_read_int32(context, id, &int32);
1919 creds->ticket_flags = int32;
1920 kret = krb5_fcc_read_addrs(context, id, &creds->addresses);
1922 kret = krb5_fcc_read_authdata(context, id, &creds->authdata);
1924 kret = krb5_fcc_read_data(context, id, &creds->ticket);
1926 kret = krb5_fcc_read_data(context, id, &creds->second_ticket);
1929 fcursor->pos = fcc_lseek(d, (off_t) 0, SEEK_CUR);
1932 MAYBE_CLOSE (context, id, kret);
1933 k5_cc_mutex_unlock(context, &d->lock);
1934 if (kret != KRB5_OK)
1935 krb5_free_cred_contents(context, creds);
1941 * cursor is a krb5_cc_cursor originally obtained from
1942 * krb5_fcc_start_seq_get.
1948 * Finishes sequential processing of the file credentials ccache id,
1949 * and invalidates the cursor (it must never be used after this call).
1952 static krb5_error_code KRB5_CALLCONV
1953 krb5_fcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
1955 /* We don't do anything with the file cache itself, so
1956 no need to lock anything. */
1958 /* don't close; it may be left open by the caller,
1959 and if not, fcc_start_seq_get and/or fcc_next_cred will do the
1961 MAYBE_CLOSE(context, id, kret); */
1962 free((krb5_fcc_cursor *) *cursor);
1969 * Creates a new file cred cache whose name is guaranteed to be
1970 * unique. The name begins with the string TKT_ROOT (from fcc.h).
1971 * The cache is not opened, but the new filename is reserved.
1974 * The filled in krb5_ccache id.
1977 * KRB5_CC_NOMEM - there was insufficient memory to allocate the
1978 * krb5_ccache. id is undefined.
1979 * system errors (from open)
1981 static krb5_error_code KRB5_CALLCONV
1982 krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
1986 krb5_error_code kret = 0;
1987 char scratch[sizeof(TKT_ROOT)+6+1]; /* +6 for the scratch part, +1 for
1989 krb5_fcc_data *data;
1990 krb5_int16 fcc_fvno = htons(context->fcc_default_format);
1991 krb5_int16 fcc_flen = 0;
1993 struct fcc_set *setptr;
1995 /* Set master lock */
1996 kret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
2000 (void) snprintf(scratch, sizeof(scratch), "%sXXXXXX", TKT_ROOT);
2001 ret = mkstemp(scratch);
2003 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2004 return krb5_fcc_interpret(context, errno);
2006 set_cloexec_fd(ret);
2008 /* Allocate memory */
2009 data = (krb5_pointer) malloc(sizeof(krb5_fcc_data));
2011 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2014 return KRB5_CC_NOMEM;
2017 data->filename = strdup(scratch);
2018 if (data->filename == NULL) {
2019 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2023 return KRB5_CC_NOMEM;
2026 kret = k5_cc_mutex_init(&data->lock);
2028 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2029 free(data->filename);
2035 kret = k5_cc_mutex_lock(context, &data->lock);
2037 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2038 k5_cc_mutex_destroy(&data->lock);
2039 free(data->filename);
2047 * The file is initially closed at the end of this call...
2051 data->valid_bytes = 0;
2052 /* data->version,mode filled in for real later */
2053 data->version = data->mode = 0;
2056 /* Ignore user's umask, set mode = 0600 */
2059 chmod(data->filename, S_IRUSR | S_IWUSR);
2062 fchmod(ret, S_IRUSR | S_IWUSR);
2064 if ((cnt = write(ret, (char *)&fcc_fvno, sizeof(fcc_fvno)))
2065 != sizeof(fcc_fvno)) {
2068 (void) unlink(data->filename);
2069 kret = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO;
2072 /* For version 4 we save a length for the rest of the header */
2073 if (context->fcc_default_format == KRB5_FCC_FVNO_4) {
2074 if ((cnt = write(ret, (char *)&fcc_flen, sizeof(fcc_flen)))
2075 != sizeof(fcc_flen)) {
2078 (void) unlink(data->filename);
2079 kret = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO;
2083 if (close(ret) == -1) {
2085 (void) unlink(data->filename);
2086 kret = krb5_fcc_interpret(context, errsave);
2091 setptr = malloc(sizeof(struct fcc_set));
2092 if (setptr == NULL) {
2093 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2094 k5_cc_mutex_unlock(context, &data->lock);
2095 k5_cc_mutex_destroy(&data->lock);
2096 free(data->filename);
2099 (void) unlink(scratch);
2100 return KRB5_CC_NOMEM;
2102 setptr->refcount = 1;
2103 setptr->data = data;
2104 setptr->next = fccs;
2106 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2108 k5_cc_mutex_assert_locked(context, &data->lock);
2109 k5_cc_mutex_unlock(context, &data->lock);
2110 lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
2112 dereference(context, data);
2113 return KRB5_CC_NOMEM;
2116 lid->ops = &krb5_fcc_ops;
2118 lid->magic = KV5M_CCACHE;
2120 /* default to open/close on every trn - otherwise destroy
2121 will get as to state confused */
2122 ((krb5_fcc_data *) lid->data)->flags = KRB5_TC_OPENCLOSE;
2127 krb5_change_cache ();
2131 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2132 k5_cc_mutex_destroy(&data->lock);
2133 free(data->filename);
2140 * id is a file credential cache
2143 * The name of the file cred cache id.
2145 static const char * KRB5_CALLCONV
2146 krb5_fcc_get_name (krb5_context context, krb5_ccache id)
2148 return (char *) ((krb5_fcc_data *) id->data)->filename;
2156 * Retrieves the primary principal from id, as set with
2157 * krb5_fcc_initialize. The principal is returned is allocated
2158 * storage that must be freed by the caller via krb5_free_principal.
2164 static krb5_error_code KRB5_CALLCONV
2165 krb5_fcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
2167 krb5_error_code kret = KRB5_OK;
2169 kret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
2173 MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
2175 /* make sure we're beyond the header */
2176 kret = krb5_fcc_skip_header(context, id);
2177 if (kret) goto done;
2178 kret = krb5_fcc_read_principal(context, id, princ);
2181 MAYBE_CLOSE(context, id, kret);
2182 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
2187 static krb5_error_code KRB5_CALLCONV
2188 krb5_fcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds)
2190 return krb5_cc_retrieve_cred_default (context, id, whichfields,
2200 * stores creds in the file cred cache
2204 * storage failure errors
2206 static krb5_error_code KRB5_CALLCONV
2207 krb5_fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
2209 #define TCHECK(ret) if (ret != KRB5_OK) goto lose;
2210 krb5_error_code ret;
2212 ret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
2216 /* Make sure we are writing to the end of the file */
2217 MAYBE_OPEN(context, id, FCC_OPEN_RDWR);
2219 /* Make sure we are writing to the end of the file */
2220 ret = fcc_lseek((krb5_fcc_data *) id->data, (off_t) 0, SEEK_END);
2222 MAYBE_CLOSE_IGNORE(context, id);
2223 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
2224 return krb5_fcc_interpret(context, errno);
2227 ret = krb5_fcc_store_principal(context, id, creds->client);
2229 ret = krb5_fcc_store_principal(context, id, creds->server);
2231 ret = krb5_fcc_store_keyblock(context, id, &creds->keyblock);
2233 ret = krb5_fcc_store_times(context, id, &creds->times);
2235 ret = krb5_fcc_store_octet(context, id, (krb5_int32) creds->is_skey);
2237 ret = krb5_fcc_store_int32(context, id, creds->ticket_flags);
2239 ret = krb5_fcc_store_addrs(context, id, creds->addresses);
2241 ret = krb5_fcc_store_authdata(context, id, creds->authdata);
2243 ret = krb5_fcc_store_data(context, id, &creds->ticket);
2245 ret = krb5_fcc_store_data(context, id, &creds->second_ticket);
2249 MAYBE_CLOSE(context, id, ret);
2250 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
2251 krb5_change_cache ();
2257 * Non-functional stub implementation for krb5_fcc_remove
2260 * KRB5_CC_NOSUPP - not implemented
2262 static krb5_error_code KRB5_CALLCONV
2263 krb5_fcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
2266 return KRB5_CC_NOSUPP;
2271 * id is a cred cache returned by krb5_fcc_resolve or
2272 * krb5_fcc_generate_new, but has not been opened by krb5_fcc_initialize.
2278 * Sets the operational flags of id to flags.
2280 static krb5_error_code KRB5_CALLCONV
2281 krb5_fcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
2283 krb5_error_code ret = KRB5_OK;
2285 ret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
2289 /* XXX This should check for illegal combinations, if any.. */
2290 if (flags & KRB5_TC_OPENCLOSE) {
2291 /* asking to turn on OPENCLOSE mode */
2293 /* XXX Is this test necessary? */
2294 && ((krb5_fcc_data *) id->data)->file != NO_FILE)
2295 (void) krb5_fcc_close_file (context, ((krb5_fcc_data *) id->data));
2297 /* asking to turn off OPENCLOSE mode, meaning it must be
2298 left open. We open if it's not yet open */
2299 MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
2302 ((krb5_fcc_data *) id->data)->flags = flags;
2303 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
2309 * id is a cred cache returned by krb5_fcc_resolve or
2310 * krb5_fcc_generate_new, but has not been opened by krb5_fcc_initialize.
2313 * id (mutex only; temporary)
2316 * Returns the operational flags of id.
2318 static krb5_error_code KRB5_CALLCONV
2319 krb5_fcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags *flags)
2321 krb5_error_code ret = KRB5_OK;
2323 ret = k5_cc_mutex_lock(context, &((krb5_fcc_data *) id->data)->lock);
2326 *flags = ((krb5_fcc_data *) id->data)->flags;
2327 k5_cc_mutex_unlock(context, &((krb5_fcc_data *) id->data)->lock);
2331 static krb5_error_code KRB5_CALLCONV
2332 krb5_fcc_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor)
2334 krb5_error_code ret = 0;
2335 krb5_cc_ptcursor n = NULL;
2336 struct krb5_fcc_ptcursor_data *cdata = NULL;
2340 n = malloc(sizeof(*n));
2343 n->ops = &krb5_fcc_ops;
2344 cdata = malloc(sizeof(struct krb5_fcc_ptcursor_data));
2345 if (cdata == NULL) {
2350 ret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
2354 ret = k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2360 krb5_fcc_ptcursor_free(context, &n);
2366 static krb5_error_code KRB5_CALLCONV
2367 krb5_fcc_ptcursor_next(krb5_context context,
2368 krb5_cc_ptcursor cursor,
2369 krb5_ccache *ccache)
2371 krb5_error_code ret = 0;
2372 struct krb5_fcc_ptcursor_data *cdata = NULL;
2376 n = malloc(sizeof(*n));
2380 cdata = cursor->data;
2382 ret = k5_cc_mutex_lock(context, &krb5int_cc_file_mutex);
2386 if (cdata->cur == NULL) {
2387 k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2393 n->ops = &krb5_fcc_ops;
2394 n->data = cdata->cur->data;
2395 cdata->cur->refcount++;
2397 cdata->cur = cdata->cur->next;
2399 ret = k5_cc_mutex_unlock(context, &krb5int_cc_file_mutex);
2403 if (ret && n != NULL) {
2411 static krb5_error_code KRB5_CALLCONV
2412 krb5_fcc_ptcursor_free(krb5_context context,
2413 krb5_cc_ptcursor *cursor)
2415 if (*cursor == NULL)
2417 if ((*cursor)->data != NULL)
2418 free((*cursor)->data);
2429 * Returns the timestamp of id's file modification date.
2430 * If an error occurs, change_time is set to 0.
2432 static krb5_error_code KRB5_CALLCONV
2433 krb5_fcc_last_change_time(krb5_context context, krb5_ccache id,
2434 krb5_timestamp *change_time)
2436 krb5_error_code kret = KRB5_OK;
2437 krb5_fcc_data *data = (krb5_fcc_data *) id->data;
2439 kret = krb5_fcc_data_last_change_time(context, data, change_time);
2444 static krb5_error_code KRB5_CALLCONV krb5_fcc_lock(krb5_context context,
2447 krb5_error_code ret = 0;
2448 krb5_fcc_data *data = (krb5_fcc_data *) id->data;
2449 ret = k5_cc_mutex_lock(context, &data->lock);
2453 static krb5_error_code KRB5_CALLCONV krb5_fcc_unlock(krb5_context context,
2456 krb5_error_code ret = 0;
2457 krb5_fcc_data *data = (krb5_fcc_data *) id->data;
2458 ret = k5_cc_mutex_unlock(context, &data->lock);
2462 static krb5_error_code
2463 krb5_fcc_data_last_change_time(krb5_context context, krb5_fcc_data *data,
2464 krb5_timestamp *change_time)
2466 krb5_error_code kret = KRB5_OK;
2473 kret = k5_cc_mutex_lock(context, &data->lock);
2478 ret = stat(data->filename, &buf);
2480 kret = krb5_fcc_interpret(context, errno);
2482 *change_time = (krb5_timestamp) buf.st_mtime;
2485 k5_cc_mutex_unlock(context, &data->lock);
2490 static krb5_error_code
2491 krb5_fcc_interpret(krb5_context context, int errnum)
2493 register krb5_error_code retval;
2496 retval = KRB5_FCC_NOFILE;
2501 case EISDIR: /* Mac doesn't have EISDIR */
2505 case ELOOP: /* Bad symlink is like no file. */
2512 retval = KRB5_FCC_PERM;
2515 case EEXIST: /* XXX */
2524 retval = KRB5_FCC_INTERNAL;
2535 retval = KRB5_CC_IO; /* XXX */
2536 krb5_set_error_message(context, retval,
2537 "Credentials cache I/O operation failed (%s)",
2543 const krb5_cc_ops krb5_fcc_ops = {
2548 krb5_fcc_generate_new,
2549 krb5_fcc_initialize,
2554 krb5_fcc_get_principal,
2555 krb5_fcc_start_seq_get,
2557 krb5_fcc_end_seq_get,
2558 krb5_fcc_remove_cred,
2561 krb5_fcc_ptcursor_new,
2562 krb5_fcc_ptcursor_next,
2563 krb5_fcc_ptcursor_free,
2565 krb5_fcc_last_change_time,
2566 NULL, /* wasdefault */
2573 * krb5_change_cache should be called after the cache changes.
2574 * A notification message is is posted out to all top level
2575 * windows so that they may recheck the cache based on the
2576 * changes made. We register a unique message type with which
2577 * we'll communicate to all other processes.
2581 krb5_change_cache (void) {
2583 PostMessage(HWND_BROADCAST, krb5_get_notification_message(), 0, 0);
2588 unsigned int KRB5_CALLCONV
2589 krb5_get_notification_message (void) {
2590 static unsigned int message = 0;
2593 message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
2600 krb5_change_cache (void)
2605 krb5_get_notification_message (void)
2612 const krb5_cc_ops krb5_cc_file_ops = {
2617 krb5_fcc_generate_new,
2618 krb5_fcc_initialize,
2623 krb5_fcc_get_principal,
2624 krb5_fcc_start_seq_get,
2626 krb5_fcc_end_seq_get,
2627 krb5_fcc_remove_cred,
2630 krb5_fcc_ptcursor_new,
2631 krb5_fcc_ptcursor_next,
2632 krb5_fcc_ptcursor_free,
2634 krb5_fcc_last_change_time,
2635 NULL, /* wasdefault */