1b528cefcSMark Murray /* 21c43270aSJacques Vidrine * Copyright (c) 1997 - 2004 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 361c43270aSJacques Vidrine RCSID("$Id: fcache.c,v 1.34.6.6 2004/03/10 13:30:59 lha 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 681c43270aSJacques Vidrine int 691c43270aSJacques Vidrine _krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive, 701c43270aSJacques Vidrine const char *filename) 711c43270aSJacques Vidrine { 721c43270aSJacques Vidrine int ret; 731c43270aSJacques Vidrine #ifdef HAVE_FCNTL 741c43270aSJacques Vidrine struct flock l; 751c43270aSJacques Vidrine 761c43270aSJacques Vidrine l.l_start = 0; 771c43270aSJacques Vidrine l.l_len = 0; 781c43270aSJacques Vidrine l.l_type = exclusive ? F_WRLCK : F_RDLCK; 791c43270aSJacques Vidrine l.l_whence = SEEK_SET; 801c43270aSJacques Vidrine ret = fcntl(fd, F_SETLKW, &l); 811c43270aSJacques Vidrine #else 821c43270aSJacques Vidrine ret = flock(fd, exclusive ? LOCK_EX : LOCK_SH); 831c43270aSJacques Vidrine #endif 841c43270aSJacques Vidrine if(ret < 0) 851c43270aSJacques Vidrine ret = errno; 861c43270aSJacques Vidrine if(ret == EACCES) /* fcntl can return EACCES instead of EAGAIN */ 871c43270aSJacques Vidrine ret = EAGAIN; 881c43270aSJacques Vidrine 891c43270aSJacques Vidrine switch (ret) { 901c43270aSJacques Vidrine case 0: 911c43270aSJacques Vidrine break; 921c43270aSJacques Vidrine case EINVAL: /* filesystem doesn't support locking, let the user have it */ 931c43270aSJacques Vidrine ret = 0; 941c43270aSJacques Vidrine break; 951c43270aSJacques Vidrine case EAGAIN: 961c43270aSJacques Vidrine krb5_set_error_string(context, "timed out locking cache file %s", 971c43270aSJacques Vidrine filename); 981c43270aSJacques Vidrine break; 991c43270aSJacques Vidrine default: 1001c43270aSJacques Vidrine krb5_set_error_string(context, "error locking cache file %s: %s", 1011c43270aSJacques Vidrine filename, strerror(ret)); 1021c43270aSJacques Vidrine break; 1031c43270aSJacques Vidrine } 1041c43270aSJacques Vidrine return ret; 1051c43270aSJacques Vidrine } 1061c43270aSJacques Vidrine 1071c43270aSJacques Vidrine int 1081c43270aSJacques Vidrine _krb5_xunlock(int fd) 1091c43270aSJacques Vidrine { 1101c43270aSJacques Vidrine #ifdef HAVE_FCNTL_LOCK 1111c43270aSJacques Vidrine struct flock l; 1121c43270aSJacques Vidrine l.l_start = 0; 1131c43270aSJacques Vidrine l.l_len = 0; 1141c43270aSJacques Vidrine l.l_type = F_UNLCK; 1151c43270aSJacques Vidrine l.l_whence = SEEK_SET; 1161c43270aSJacques Vidrine return fcntl(fd, F_SETLKW, &l); 1171c43270aSJacques Vidrine #else 1181c43270aSJacques Vidrine return flock(fd, LOCK_UN); 1191c43270aSJacques Vidrine #endif 1201c43270aSJacques Vidrine } 1211c43270aSJacques Vidrine 1221c43270aSJacques Vidrine static krb5_error_code 1231c43270aSJacques Vidrine fcc_lock(krb5_context context, krb5_ccache id, 1241c43270aSJacques Vidrine int fd, krb5_boolean exclusive) 1251c43270aSJacques Vidrine { 1261c43270aSJacques Vidrine return _krb5_xlock(context, fd, exclusive, fcc_get_name(context, id)); 1271c43270aSJacques Vidrine } 1281c43270aSJacques Vidrine 1291c43270aSJacques Vidrine static krb5_error_code 1301c43270aSJacques Vidrine fcc_unlock(krb5_context context, int fd) 1311c43270aSJacques Vidrine { 1321c43270aSJacques Vidrine return _krb5_xunlock(fd); 1331c43270aSJacques Vidrine } 1341c43270aSJacques Vidrine 135b528cefcSMark Murray static krb5_error_code 136b528cefcSMark Murray fcc_resolve(krb5_context context, krb5_ccache *id, const char *res) 137b528cefcSMark Murray { 138b528cefcSMark Murray krb5_fcache *f; 139b528cefcSMark Murray f = malloc(sizeof(*f)); 140adb0ddaeSAssar Westerlund if(f == NULL) { 141adb0ddaeSAssar Westerlund krb5_set_error_string(context, "malloc: out of memory"); 142b528cefcSMark Murray return KRB5_CC_NOMEM; 143adb0ddaeSAssar Westerlund } 144b528cefcSMark Murray f->filename = strdup(res); 145b528cefcSMark Murray if(f->filename == NULL){ 146b528cefcSMark Murray free(f); 147adb0ddaeSAssar Westerlund krb5_set_error_string(context, "malloc: out of memory"); 148b528cefcSMark Murray return KRB5_CC_NOMEM; 149b528cefcSMark Murray } 150b528cefcSMark Murray f->version = 0; 151b528cefcSMark Murray (*id)->data.data = f; 152b528cefcSMark Murray (*id)->data.length = sizeof(*f); 153b528cefcSMark Murray return 0; 154b528cefcSMark Murray } 155b528cefcSMark Murray 1565e9cd1aeSAssar Westerlund /* 1575e9cd1aeSAssar Westerlund * Try to scrub the contents of `filename' safely. 1585e9cd1aeSAssar Westerlund */ 1595e9cd1aeSAssar Westerlund 1605e9cd1aeSAssar Westerlund static int 1615e9cd1aeSAssar Westerlund scrub_file (int fd) 1625e9cd1aeSAssar Westerlund { 1635e9cd1aeSAssar Westerlund off_t pos; 1645e9cd1aeSAssar Westerlund char buf[128]; 1655e9cd1aeSAssar Westerlund 1665e9cd1aeSAssar Westerlund pos = lseek(fd, 0, SEEK_END); 1675e9cd1aeSAssar Westerlund if (pos < 0) 1685e9cd1aeSAssar Westerlund return errno; 1695e9cd1aeSAssar Westerlund if (lseek(fd, 0, SEEK_SET) < 0) 1705e9cd1aeSAssar Westerlund return errno; 1715e9cd1aeSAssar Westerlund memset(buf, 0, sizeof(buf)); 1725e9cd1aeSAssar Westerlund while(pos > 0) { 1735e9cd1aeSAssar Westerlund ssize_t tmp = write(fd, buf, min(sizeof(buf), pos)); 1745e9cd1aeSAssar Westerlund 1755e9cd1aeSAssar Westerlund if (tmp < 0) 1765e9cd1aeSAssar Westerlund return errno; 1775e9cd1aeSAssar Westerlund pos -= tmp; 1785e9cd1aeSAssar Westerlund } 1795e9cd1aeSAssar Westerlund fsync (fd); 1805e9cd1aeSAssar Westerlund return 0; 1815e9cd1aeSAssar Westerlund } 1825e9cd1aeSAssar Westerlund 1835e9cd1aeSAssar Westerlund /* 1845e9cd1aeSAssar Westerlund * Erase `filename' if it exists, trying to remove the contents if 1855e9cd1aeSAssar Westerlund * it's `safe'. We always try to remove the file, it it exists. It's 1865e9cd1aeSAssar Westerlund * only overwritten if it's a regular file (not a symlink and not a 1875e9cd1aeSAssar Westerlund * hardlink) 1885e9cd1aeSAssar Westerlund */ 1895e9cd1aeSAssar Westerlund 190b528cefcSMark Murray static krb5_error_code 191b528cefcSMark Murray erase_file(const char *filename) 192b528cefcSMark Murray { 193b528cefcSMark Murray int fd; 1945e9cd1aeSAssar Westerlund struct stat sb1, sb2; 1955e9cd1aeSAssar Westerlund int ret; 1965e9cd1aeSAssar Westerlund 1975e9cd1aeSAssar Westerlund ret = lstat (filename, &sb1); 1985e9cd1aeSAssar Westerlund if (ret < 0) 1995e9cd1aeSAssar Westerlund return errno; 200b528cefcSMark Murray 201b528cefcSMark Murray fd = open(filename, O_RDWR | O_BINARY); 202b528cefcSMark Murray if(fd < 0) { 203b528cefcSMark Murray if(errno == ENOENT) 204b528cefcSMark Murray return 0; 205b528cefcSMark Murray else 206b528cefcSMark Murray return errno; 207b528cefcSMark Murray } 2085e9cd1aeSAssar Westerlund if (unlink(filename) < 0) { 209b528cefcSMark Murray close (fd); 2105e9cd1aeSAssar Westerlund return errno; 2115e9cd1aeSAssar Westerlund } 2125e9cd1aeSAssar Westerlund ret = fstat (fd, &sb2); 2135e9cd1aeSAssar Westerlund if (ret < 0) { 2145e9cd1aeSAssar Westerlund close (fd); 2155e9cd1aeSAssar Westerlund return errno; 2165e9cd1aeSAssar Westerlund } 2175e9cd1aeSAssar Westerlund 2185e9cd1aeSAssar Westerlund /* check if someone was playing with symlinks */ 2195e9cd1aeSAssar Westerlund 2205e9cd1aeSAssar Westerlund if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) { 2215e9cd1aeSAssar Westerlund close (fd); 2225e9cd1aeSAssar Westerlund return EPERM; 2235e9cd1aeSAssar Westerlund } 2245e9cd1aeSAssar Westerlund 2255e9cd1aeSAssar Westerlund /* there are still hard links to this file */ 2265e9cd1aeSAssar Westerlund 2275e9cd1aeSAssar Westerlund if (sb2.st_nlink != 0) { 2285e9cd1aeSAssar Westerlund close (fd); 229b528cefcSMark Murray return 0; 230b528cefcSMark Murray } 231b528cefcSMark Murray 2325e9cd1aeSAssar Westerlund ret = scrub_file (fd); 2335e9cd1aeSAssar Westerlund close (fd); 2345e9cd1aeSAssar Westerlund return ret; 2355e9cd1aeSAssar Westerlund } 2365e9cd1aeSAssar Westerlund 237b528cefcSMark Murray static krb5_error_code 238b528cefcSMark Murray fcc_gen_new(krb5_context context, krb5_ccache *id) 239b528cefcSMark Murray { 240b528cefcSMark Murray krb5_fcache *f; 241b528cefcSMark Murray int fd; 242b528cefcSMark Murray char *file; 243adb0ddaeSAssar Westerlund 244b528cefcSMark Murray f = malloc(sizeof(*f)); 245adb0ddaeSAssar Westerlund if(f == NULL) { 246adb0ddaeSAssar Westerlund krb5_set_error_string(context, "malloc: out of memory"); 247b528cefcSMark Murray return KRB5_CC_NOMEM; 248adb0ddaeSAssar Westerlund } 2495e9cd1aeSAssar Westerlund asprintf (&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT); 250b528cefcSMark Murray if(file == NULL) { 251b528cefcSMark Murray free(f); 252adb0ddaeSAssar Westerlund krb5_set_error_string(context, "malloc: out of memory"); 253b528cefcSMark Murray return KRB5_CC_NOMEM; 254b528cefcSMark Murray } 255b528cefcSMark Murray fd = mkstemp(file); 256b528cefcSMark Murray if(fd < 0) { 257b528cefcSMark Murray free(f); 258b528cefcSMark Murray free(file); 259adb0ddaeSAssar Westerlund krb5_set_error_string(context, "mkstemp %s", file); 260b528cefcSMark Murray return errno; 261b528cefcSMark Murray } 262b528cefcSMark Murray close(fd); 263b528cefcSMark Murray f->filename = file; 264b528cefcSMark Murray f->version = 0; 265b528cefcSMark Murray (*id)->data.data = f; 266b528cefcSMark Murray (*id)->data.length = sizeof(*f); 267b528cefcSMark Murray return 0; 268b528cefcSMark Murray } 269b528cefcSMark Murray 270b528cefcSMark Murray static void 271b528cefcSMark Murray storage_set_flags(krb5_context context, krb5_storage *sp, int vno) 272b528cefcSMark Murray { 273b528cefcSMark Murray int flags = 0; 274b528cefcSMark Murray switch(vno) { 275b528cefcSMark Murray case KRB5_FCC_FVNO_1: 276b528cefcSMark Murray flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS; 277b528cefcSMark Murray flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE; 278b528cefcSMark Murray flags |= KRB5_STORAGE_HOST_BYTEORDER; 279b528cefcSMark Murray break; 280b528cefcSMark Murray case KRB5_FCC_FVNO_2: 281b528cefcSMark Murray flags |= KRB5_STORAGE_HOST_BYTEORDER; 282b528cefcSMark Murray break; 283b528cefcSMark Murray case KRB5_FCC_FVNO_3: 284b528cefcSMark Murray flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE; 285b528cefcSMark Murray break; 286b528cefcSMark Murray case KRB5_FCC_FVNO_4: 287b528cefcSMark Murray break; 288b528cefcSMark Murray default: 289b528cefcSMark Murray krb5_abortx(context, 290b528cefcSMark Murray "storage_set_flags called with bad vno (%x)", vno); 291b528cefcSMark Murray } 292b528cefcSMark Murray krb5_storage_set_flags(sp, flags); 293b528cefcSMark Murray } 294b528cefcSMark Murray 295b528cefcSMark Murray static krb5_error_code 2961c43270aSJacques Vidrine fcc_open(krb5_context context, 2971c43270aSJacques Vidrine krb5_ccache id, 2981c43270aSJacques Vidrine int *fd_ret, 2991c43270aSJacques Vidrine int flags, 3001c43270aSJacques Vidrine mode_t mode) 3011c43270aSJacques Vidrine { 3021c43270aSJacques Vidrine krb5_boolean exclusive = ((flags | O_WRONLY) == flags || 3031c43270aSJacques Vidrine (flags | O_RDWR) == flags); 3041c43270aSJacques Vidrine krb5_error_code ret; 3051c43270aSJacques Vidrine const char *filename = FILENAME(id); 3061c43270aSJacques Vidrine int fd; 3071c43270aSJacques Vidrine fd = open(filename, flags, mode); 3081c43270aSJacques Vidrine if(fd < 0) { 3091c43270aSJacques Vidrine ret = errno; 3101c43270aSJacques Vidrine krb5_set_error_string(context, "open(%s): %s", filename, 3111c43270aSJacques Vidrine strerror(ret)); 3121c43270aSJacques Vidrine return ret; 3131c43270aSJacques Vidrine } 3141c43270aSJacques Vidrine 3151c43270aSJacques Vidrine if((ret = fcc_lock(context, id, fd, exclusive)) != 0) { 3161c43270aSJacques Vidrine close(fd); 3171c43270aSJacques Vidrine return ret; 3181c43270aSJacques Vidrine } 3191c43270aSJacques Vidrine *fd_ret = fd; 3201c43270aSJacques Vidrine return 0; 3211c43270aSJacques Vidrine } 3221c43270aSJacques Vidrine 3231c43270aSJacques Vidrine static krb5_error_code 324b528cefcSMark Murray fcc_initialize(krb5_context context, 325b528cefcSMark Murray krb5_ccache id, 326b528cefcSMark Murray krb5_principal primary_principal) 327b528cefcSMark Murray { 328b528cefcSMark Murray krb5_fcache *f = FCACHE(id); 3295e9cd1aeSAssar Westerlund int ret = 0; 330b528cefcSMark Murray int fd; 331b528cefcSMark Murray char *filename = f->filename; 332b528cefcSMark Murray 3335e9cd1aeSAssar Westerlund unlink (filename); 334b528cefcSMark Murray 3351c43270aSJacques Vidrine ret = fcc_open(context, id, &fd, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); 3361c43270aSJacques Vidrine if(ret) 337adb0ddaeSAssar Westerlund return ret; 338b528cefcSMark Murray { 339b528cefcSMark Murray krb5_storage *sp; 340b528cefcSMark Murray sp = krb5_storage_from_fd(fd); 3418373020dSJacques Vidrine krb5_storage_set_eof_code(sp, KRB5_CC_END); 342b528cefcSMark Murray if(context->fcache_vno != 0) 343b528cefcSMark Murray f->version = context->fcache_vno; 344b528cefcSMark Murray else 345b528cefcSMark Murray f->version = KRB5_FCC_FVNO_4; 3465e9cd1aeSAssar Westerlund ret |= krb5_store_int8(sp, 5); 3475e9cd1aeSAssar Westerlund ret |= krb5_store_int8(sp, f->version); 348b528cefcSMark Murray storage_set_flags(context, sp, f->version); 3495e9cd1aeSAssar Westerlund if(f->version == KRB5_FCC_FVNO_4 && ret == 0) { 350b528cefcSMark Murray /* V4 stuff */ 351b528cefcSMark Murray if (context->kdc_sec_offset) { 3525e9cd1aeSAssar Westerlund ret |= krb5_store_int16 (sp, 12); /* length */ 3535e9cd1aeSAssar Westerlund ret |= krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */ 3545e9cd1aeSAssar Westerlund ret |= krb5_store_int16 (sp, 8); /* length of data */ 3555e9cd1aeSAssar Westerlund ret |= krb5_store_int32 (sp, context->kdc_sec_offset); 3565e9cd1aeSAssar Westerlund ret |= krb5_store_int32 (sp, context->kdc_usec_offset); 357b528cefcSMark Murray } else { 3585e9cd1aeSAssar Westerlund ret |= krb5_store_int16 (sp, 0); 359b528cefcSMark Murray } 360b528cefcSMark Murray } 3615e9cd1aeSAssar Westerlund ret |= krb5_store_principal(sp, primary_principal); 3621c43270aSJacques Vidrine 363b528cefcSMark Murray krb5_storage_free(sp); 364b528cefcSMark Murray } 3651c43270aSJacques Vidrine fcc_unlock(context, fd); 3665e9cd1aeSAssar Westerlund if (close(fd) < 0) 367adb0ddaeSAssar Westerlund if (ret == 0) { 3685e9cd1aeSAssar Westerlund ret = errno; 3691c43270aSJacques Vidrine krb5_set_error_string (context, "close %s: %s", 3701c43270aSJacques Vidrine FILENAME(id), strerror(ret)); 371adb0ddaeSAssar Westerlund } 3725e9cd1aeSAssar Westerlund return ret; 373b528cefcSMark Murray } 374b528cefcSMark Murray 375b528cefcSMark Murray static krb5_error_code 376b528cefcSMark Murray fcc_close(krb5_context context, 377b528cefcSMark Murray krb5_ccache id) 378b528cefcSMark Murray { 379b528cefcSMark Murray free (FILENAME(id)); 380b528cefcSMark Murray krb5_data_free(&id->data); 381b528cefcSMark Murray return 0; 382b528cefcSMark Murray } 383b528cefcSMark Murray 384b528cefcSMark Murray static krb5_error_code 385b528cefcSMark Murray fcc_destroy(krb5_context context, 386b528cefcSMark Murray krb5_ccache id) 387b528cefcSMark Murray { 3881c43270aSJacques Vidrine erase_file(FILENAME(id)); 389b528cefcSMark Murray return 0; 390b528cefcSMark Murray } 391b528cefcSMark Murray 392b528cefcSMark Murray static krb5_error_code 393b528cefcSMark Murray fcc_store_cred(krb5_context context, 394b528cefcSMark Murray krb5_ccache id, 395b528cefcSMark Murray krb5_creds *creds) 396b528cefcSMark Murray { 3975e9cd1aeSAssar Westerlund int ret; 398b528cefcSMark Murray int fd; 399b528cefcSMark Murray 4001c43270aSJacques Vidrine ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY, 0); 4011c43270aSJacques Vidrine if(ret) 402adb0ddaeSAssar Westerlund return ret; 403b528cefcSMark Murray { 404b528cefcSMark Murray krb5_storage *sp; 405b528cefcSMark Murray sp = krb5_storage_from_fd(fd); 4068373020dSJacques Vidrine krb5_storage_set_eof_code(sp, KRB5_CC_END); 407b528cefcSMark Murray storage_set_flags(context, sp, FCACHE(id)->version); 4081c43270aSJacques Vidrine if (krb5_config_get_bool_default(context, NULL, FALSE, 4091c43270aSJacques Vidrine "libdefaults", 4101c43270aSJacques Vidrine "fcc-mit-ticketflags", 4111c43270aSJacques Vidrine NULL)) 4121c43270aSJacques Vidrine ret = _krb5_store_creds_heimdal_0_7(sp, creds); 4131c43270aSJacques Vidrine else 4141c43270aSJacques Vidrine ret = _krb5_store_creds_heimdal_pre_0_7(sp, creds); 415b528cefcSMark Murray krb5_storage_free(sp); 416b528cefcSMark Murray } 4171c43270aSJacques Vidrine fcc_unlock(context, fd); 4185e9cd1aeSAssar Westerlund if (close(fd) < 0) 419adb0ddaeSAssar Westerlund if (ret == 0) { 4205e9cd1aeSAssar Westerlund ret = errno; 4211c43270aSJacques Vidrine krb5_set_error_string (context, "close %s: %s", 4221c43270aSJacques Vidrine FILENAME(id), strerror(ret)); 423adb0ddaeSAssar Westerlund } 4245e9cd1aeSAssar Westerlund return ret; 425b528cefcSMark Murray } 426b528cefcSMark Murray 427b528cefcSMark Murray static krb5_error_code 428b528cefcSMark Murray init_fcc (krb5_context context, 4291c43270aSJacques Vidrine krb5_ccache id, 430b528cefcSMark Murray krb5_storage **ret_sp, 431b528cefcSMark Murray int *ret_fd) 432b528cefcSMark Murray { 433b528cefcSMark Murray int fd; 434b528cefcSMark Murray int8_t pvno, tag; 435b528cefcSMark Murray krb5_storage *sp; 4365e9cd1aeSAssar Westerlund krb5_error_code ret; 437b528cefcSMark Murray 4381c43270aSJacques Vidrine ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY, 0); 4391c43270aSJacques Vidrine 4405e9cd1aeSAssar Westerlund if(ret) 4415e9cd1aeSAssar Westerlund return ret; 4421c43270aSJacques Vidrine 4431c43270aSJacques Vidrine sp = krb5_storage_from_fd(fd); 4441c43270aSJacques Vidrine if(sp == NULL) { 4451c43270aSJacques Vidrine ret = ENOMEM; 4461c43270aSJacques Vidrine goto out; 447b528cefcSMark Murray } 4481c43270aSJacques Vidrine krb5_storage_set_eof_code(sp, KRB5_CC_END); 4491c43270aSJacques Vidrine ret = krb5_ret_int8(sp, &pvno); 4501c43270aSJacques Vidrine if(ret != 0) { 4511c43270aSJacques Vidrine if(ret == KRB5_CC_END) 4521c43270aSJacques Vidrine ret = ENOENT; /* empty file */ 4531c43270aSJacques Vidrine goto out; 4541c43270aSJacques Vidrine } 4551c43270aSJacques Vidrine if(pvno != 5) { 4561c43270aSJacques Vidrine ret = KRB5_CCACHE_BADVNO; 4571c43270aSJacques Vidrine goto out; 4581c43270aSJacques Vidrine } 4591c43270aSJacques Vidrine ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */ 4601c43270aSJacques Vidrine if(ret != 0) { 4611c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 4621c43270aSJacques Vidrine goto out; 4631c43270aSJacques Vidrine } 4641c43270aSJacques Vidrine FCACHE(id)->version = tag; 4651c43270aSJacques Vidrine storage_set_flags(context, sp, FCACHE(id)->version); 466b528cefcSMark Murray switch (tag) { 467b528cefcSMark Murray case KRB5_FCC_FVNO_4: { 468b528cefcSMark Murray int16_t length; 469b528cefcSMark Murray 4701c43270aSJacques Vidrine ret = krb5_ret_int16 (sp, &length); 4711c43270aSJacques Vidrine if(ret) { 4721c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 4731c43270aSJacques Vidrine goto out; 4741c43270aSJacques Vidrine } 475b528cefcSMark Murray while(length > 0) { 476b528cefcSMark Murray int16_t tag, data_len; 477b528cefcSMark Murray int i; 478b528cefcSMark Murray int8_t dummy; 479b528cefcSMark Murray 4801c43270aSJacques Vidrine ret = krb5_ret_int16 (sp, &tag); 4811c43270aSJacques Vidrine if(ret) { 4821c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 4831c43270aSJacques Vidrine goto out; 4841c43270aSJacques Vidrine } 4851c43270aSJacques Vidrine ret = krb5_ret_int16 (sp, &data_len); 4861c43270aSJacques Vidrine if(ret) { 4871c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 4881c43270aSJacques Vidrine goto out; 4891c43270aSJacques Vidrine } 490b528cefcSMark Murray switch (tag) { 491b528cefcSMark Murray case FCC_TAG_DELTATIME : 4921c43270aSJacques Vidrine ret = krb5_ret_int32 (sp, &context->kdc_sec_offset); 4931c43270aSJacques Vidrine if(ret) { 4941c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 4951c43270aSJacques Vidrine goto out; 4961c43270aSJacques Vidrine } 4971c43270aSJacques Vidrine ret = krb5_ret_int32 (sp, &context->kdc_usec_offset); 4981c43270aSJacques Vidrine if(ret) { 4991c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 5001c43270aSJacques Vidrine goto out; 5011c43270aSJacques Vidrine } 502b528cefcSMark Murray break; 503b528cefcSMark Murray default : 5041c43270aSJacques Vidrine for (i = 0; i < data_len; ++i) { 5051c43270aSJacques Vidrine ret = krb5_ret_int8 (sp, &dummy); 5061c43270aSJacques Vidrine if(ret) { 5071c43270aSJacques Vidrine ret = KRB5_CC_FORMAT; 5081c43270aSJacques Vidrine goto out; 5091c43270aSJacques Vidrine } 5101c43270aSJacques Vidrine } 511b528cefcSMark Murray break; 512b528cefcSMark Murray } 513b528cefcSMark Murray length -= 4 + data_len; 514b528cefcSMark Murray } 515b528cefcSMark Murray break; 516b528cefcSMark Murray } 517b528cefcSMark Murray case KRB5_FCC_FVNO_3: 518b528cefcSMark Murray case KRB5_FCC_FVNO_2: 519b528cefcSMark Murray case KRB5_FCC_FVNO_1: 520b528cefcSMark Murray break; 521b528cefcSMark Murray default : 5221c43270aSJacques Vidrine ret = KRB5_CCACHE_BADVNO; 5231c43270aSJacques Vidrine goto out; 524b528cefcSMark Murray } 525b528cefcSMark Murray *ret_sp = sp; 526b528cefcSMark Murray *ret_fd = fd; 5271c43270aSJacques Vidrine 528b528cefcSMark Murray return 0; 5291c43270aSJacques Vidrine out: 5301c43270aSJacques Vidrine if(sp != NULL) 5311c43270aSJacques Vidrine krb5_storage_free(sp); 5321c43270aSJacques Vidrine fcc_unlock(context, fd); 5331c43270aSJacques Vidrine close(fd); 5341c43270aSJacques Vidrine return ret; 535b528cefcSMark Murray } 536b528cefcSMark Murray 537b528cefcSMark Murray static krb5_error_code 538b528cefcSMark Murray fcc_get_principal(krb5_context context, 539b528cefcSMark Murray krb5_ccache id, 540b528cefcSMark Murray krb5_principal *principal) 541b528cefcSMark Murray { 542b528cefcSMark Murray krb5_error_code ret; 543b528cefcSMark Murray int fd; 544b528cefcSMark Murray krb5_storage *sp; 545b528cefcSMark Murray 5461c43270aSJacques Vidrine ret = init_fcc (context, id, &sp, &fd); 547b528cefcSMark Murray if (ret) 548b528cefcSMark Murray return ret; 5495e9cd1aeSAssar Westerlund ret = krb5_ret_principal(sp, principal); 550b528cefcSMark Murray krb5_storage_free(sp); 5511c43270aSJacques Vidrine fcc_unlock(context, fd); 552b528cefcSMark Murray close(fd); 5535e9cd1aeSAssar Westerlund return ret; 554b528cefcSMark Murray } 555b528cefcSMark Murray 556b528cefcSMark Murray static krb5_error_code 5571c43270aSJacques Vidrine fcc_end_get (krb5_context context, 5581c43270aSJacques Vidrine krb5_ccache id, 5591c43270aSJacques Vidrine krb5_cc_cursor *cursor); 5601c43270aSJacques Vidrine 5611c43270aSJacques Vidrine static krb5_error_code 562b528cefcSMark Murray fcc_get_first (krb5_context context, 563b528cefcSMark Murray krb5_ccache id, 564b528cefcSMark Murray krb5_cc_cursor *cursor) 565b528cefcSMark Murray { 566b528cefcSMark Murray krb5_error_code ret; 567b528cefcSMark Murray krb5_principal principal; 568b528cefcSMark Murray 569b528cefcSMark Murray *cursor = malloc(sizeof(struct fcc_cursor)); 570b528cefcSMark Murray 5711c43270aSJacques Vidrine ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp, 572b528cefcSMark Murray &FCC_CURSOR(*cursor)->fd); 5731c43270aSJacques Vidrine if (ret) { 5741c43270aSJacques Vidrine free(*cursor); 575b528cefcSMark Murray return ret; 5761c43270aSJacques Vidrine } 5771c43270aSJacques Vidrine ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal); 5781c43270aSJacques Vidrine if(ret) { 5791c43270aSJacques Vidrine fcc_end_get(context, id, cursor); 5801c43270aSJacques Vidrine return ret; 5811c43270aSJacques Vidrine } 582b528cefcSMark Murray krb5_free_principal (context, principal); 5831c43270aSJacques Vidrine fcc_unlock(context, FCC_CURSOR(*cursor)->fd); 584b528cefcSMark Murray return 0; 585b528cefcSMark Murray } 586b528cefcSMark Murray 587b528cefcSMark Murray static krb5_error_code 588b528cefcSMark Murray fcc_get_next (krb5_context context, 589b528cefcSMark Murray krb5_ccache id, 590b528cefcSMark Murray krb5_cc_cursor *cursor, 591b528cefcSMark Murray krb5_creds *creds) 592b528cefcSMark Murray { 5931c43270aSJacques Vidrine krb5_error_code ret; 5941c43270aSJacques Vidrine if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0) 5951c43270aSJacques Vidrine return ret; 5961c43270aSJacques Vidrine 5971c43270aSJacques Vidrine ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds); 5981c43270aSJacques Vidrine 5991c43270aSJacques Vidrine fcc_unlock(context, FCC_CURSOR(*cursor)->fd); 6001c43270aSJacques Vidrine return ret; 601b528cefcSMark Murray } 602b528cefcSMark Murray 603b528cefcSMark Murray static krb5_error_code 604b528cefcSMark Murray fcc_end_get (krb5_context context, 605b528cefcSMark Murray krb5_ccache id, 606b528cefcSMark Murray krb5_cc_cursor *cursor) 607b528cefcSMark Murray { 608b528cefcSMark Murray krb5_storage_free(FCC_CURSOR(*cursor)->sp); 609b528cefcSMark Murray close (FCC_CURSOR(*cursor)->fd); 610b528cefcSMark Murray free(*cursor); 6111c43270aSJacques Vidrine *cursor = NULL; 612b528cefcSMark Murray return 0; 613b528cefcSMark Murray } 614b528cefcSMark Murray 615b528cefcSMark Murray static krb5_error_code 616b528cefcSMark Murray fcc_remove_cred(krb5_context context, 617b528cefcSMark Murray krb5_ccache id, 618b528cefcSMark Murray krb5_flags which, 619b528cefcSMark Murray krb5_creds *cred) 620b528cefcSMark Murray { 621b528cefcSMark Murray return 0; /* XXX */ 622b528cefcSMark Murray } 623b528cefcSMark Murray 624b528cefcSMark Murray static krb5_error_code 625b528cefcSMark Murray fcc_set_flags(krb5_context context, 626b528cefcSMark Murray krb5_ccache id, 627b528cefcSMark Murray krb5_flags flags) 628b528cefcSMark Murray { 629b528cefcSMark Murray return 0; /* XXX */ 630b528cefcSMark Murray } 631b528cefcSMark Murray 632b528cefcSMark Murray static krb5_error_code 633b528cefcSMark Murray fcc_get_version(krb5_context context, 634b528cefcSMark Murray krb5_ccache id) 635b528cefcSMark Murray { 636b528cefcSMark Murray return FCACHE(id)->version; 637b528cefcSMark Murray } 638b528cefcSMark Murray 639b528cefcSMark Murray const krb5_cc_ops krb5_fcc_ops = { 640b528cefcSMark Murray "FILE", 641b528cefcSMark Murray fcc_get_name, 642b528cefcSMark Murray fcc_resolve, 643b528cefcSMark Murray fcc_gen_new, 644b528cefcSMark Murray fcc_initialize, 645b528cefcSMark Murray fcc_destroy, 646b528cefcSMark Murray fcc_close, 647b528cefcSMark Murray fcc_store_cred, 648b528cefcSMark Murray NULL, /* fcc_retrieve */ 649b528cefcSMark Murray fcc_get_principal, 650b528cefcSMark Murray fcc_get_first, 651b528cefcSMark Murray fcc_get_next, 652b528cefcSMark Murray fcc_end_get, 653b528cefcSMark Murray fcc_remove_cred, 654b528cefcSMark Murray fcc_set_flags, 655b528cefcSMark Murray fcc_get_version 656b528cefcSMark Murray }; 657