1 /* 2 * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 36 RCSID("$Id: fcache.c,v 1.22 1999/12/02 17:05:09 joda Exp $"); 37 38 typedef struct krb5_fcache{ 39 char *filename; 40 int version; 41 }krb5_fcache; 42 43 struct fcc_cursor { 44 int fd; 45 krb5_storage *sp; 46 }; 47 48 #define KRB5_FCC_FVNO_1 1 49 #define KRB5_FCC_FVNO_2 2 50 #define KRB5_FCC_FVNO_3 3 51 #define KRB5_FCC_FVNO_4 4 52 53 #define FCC_TAG_DELTATIME 1 54 55 #define FCACHE(X) ((krb5_fcache*)(X)->data.data) 56 57 #define FILENAME(X) (FCACHE(X)->filename) 58 59 #define FCC_CURSOR(C) ((struct fcc_cursor*)(C)) 60 61 static char* 62 fcc_get_name(krb5_context context, 63 krb5_ccache id) 64 { 65 return FILENAME(id); 66 } 67 68 static krb5_error_code 69 fcc_resolve(krb5_context context, krb5_ccache *id, const char *res) 70 { 71 krb5_fcache *f; 72 f = malloc(sizeof(*f)); 73 if(f == NULL) 74 return KRB5_CC_NOMEM; 75 f->filename = strdup(res); 76 if(f->filename == NULL){ 77 free(f); 78 return KRB5_CC_NOMEM; 79 } 80 f->version = 0; 81 (*id)->data.data = f; 82 (*id)->data.length = sizeof(*f); 83 return 0; 84 } 85 86 static krb5_error_code 87 erase_file(const char *filename) 88 { 89 int fd; 90 off_t pos; 91 char buf[128]; 92 93 fd = open(filename, O_RDWR | O_BINARY); 94 if(fd < 0){ 95 if(errno == ENOENT) 96 return 0; 97 else 98 return errno; 99 } 100 pos = lseek(fd, 0, SEEK_END); 101 lseek(fd, 0, SEEK_SET); 102 memset(buf, 0, sizeof(buf)); 103 while(pos > 0) 104 pos -= write(fd, buf, sizeof(buf)); 105 close(fd); 106 unlink(filename); 107 return 0; 108 } 109 110 static krb5_error_code 111 fcc_gen_new(krb5_context context, krb5_ccache *id) 112 { 113 krb5_fcache *f; 114 int fd; 115 char *file; 116 f = malloc(sizeof(*f)); 117 if(f == NULL) 118 return KRB5_CC_NOMEM; 119 asprintf(&file, "/tmp/krb5cc_XXXXXX"); /* XXX */ 120 if(file == NULL) { 121 free(f); 122 return KRB5_CC_NOMEM; 123 } 124 fd = mkstemp(file); 125 if(fd < 0) { 126 free(f); 127 free(file); 128 return errno; 129 } 130 close(fd); 131 f->filename = file; 132 f->version = 0; 133 (*id)->data.data = f; 134 (*id)->data.length = sizeof(*f); 135 return 0; 136 } 137 138 static void 139 storage_set_flags(krb5_context context, krb5_storage *sp, int vno) 140 { 141 int flags = 0; 142 switch(vno) { 143 case KRB5_FCC_FVNO_1: 144 flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS; 145 flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE; 146 flags |= KRB5_STORAGE_HOST_BYTEORDER; 147 break; 148 case KRB5_FCC_FVNO_2: 149 flags |= KRB5_STORAGE_HOST_BYTEORDER; 150 break; 151 case KRB5_FCC_FVNO_3: 152 flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE; 153 break; 154 case KRB5_FCC_FVNO_4: 155 break; 156 default: 157 krb5_abortx(context, 158 "storage_set_flags called with bad vno (%x)", vno); 159 } 160 krb5_storage_set_flags(sp, flags); 161 } 162 163 static krb5_error_code 164 fcc_initialize(krb5_context context, 165 krb5_ccache id, 166 krb5_principal primary_principal) 167 { 168 krb5_fcache *f = FCACHE(id); 169 int ret; 170 int fd; 171 char *filename = f->filename; 172 173 if((ret = erase_file(filename))) 174 return ret; 175 176 fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); 177 if(fd == -1) 178 return errno; 179 { 180 krb5_storage *sp; 181 sp = krb5_storage_from_fd(fd); 182 if(context->fcache_vno != 0) 183 f->version = context->fcache_vno; 184 else 185 f->version = KRB5_FCC_FVNO_4; 186 krb5_store_int8(sp, 5); 187 krb5_store_int8(sp, f->version); 188 storage_set_flags(context, sp, f->version); 189 if(f->version == KRB5_FCC_FVNO_4) { 190 /* V4 stuff */ 191 if (context->kdc_sec_offset) { 192 krb5_store_int16 (sp, 12); /* length */ 193 krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */ 194 krb5_store_int16 (sp, 8); /* length of data */ 195 krb5_store_int32 (sp, context->kdc_sec_offset); 196 krb5_store_int32 (sp, context->kdc_usec_offset); 197 } else { 198 krb5_store_int16 (sp, 0); 199 } 200 } 201 krb5_store_principal(sp, primary_principal); 202 krb5_storage_free(sp); 203 } 204 close(fd); 205 206 return 0; 207 } 208 209 static krb5_error_code 210 fcc_close(krb5_context context, 211 krb5_ccache id) 212 { 213 free (FILENAME(id)); 214 krb5_data_free(&id->data); 215 return 0; 216 } 217 218 static krb5_error_code 219 fcc_destroy(krb5_context context, 220 krb5_ccache id) 221 { 222 char *f; 223 f = FILENAME(id); 224 225 erase_file(f); 226 227 return 0; 228 } 229 230 static krb5_error_code 231 fcc_store_cred(krb5_context context, 232 krb5_ccache id, 233 krb5_creds *creds) 234 { 235 int fd; 236 char *f; 237 238 f = FILENAME(id); 239 240 fd = open(f, O_WRONLY | O_APPEND | O_BINARY); 241 if(fd < 0) 242 return errno; 243 { 244 krb5_storage *sp; 245 sp = krb5_storage_from_fd(fd); 246 storage_set_flags(context, sp, FCACHE(id)->version); 247 krb5_store_creds(sp, creds); 248 krb5_storage_free(sp); 249 } 250 close(fd); 251 return 0; /* XXX */ 252 } 253 254 static krb5_error_code 255 fcc_read_cred (krb5_context context, 256 krb5_fcache *fc, 257 krb5_storage *sp, 258 krb5_creds *creds) 259 { 260 krb5_error_code ret; 261 262 storage_set_flags(context, sp, fc->version); 263 264 ret = krb5_ret_creds(sp, creds); 265 return ret; 266 } 267 268 static krb5_error_code 269 init_fcc (krb5_context context, 270 krb5_fcache *fcache, 271 krb5_storage **ret_sp, 272 int *ret_fd) 273 { 274 int fd; 275 int8_t pvno, tag; 276 krb5_storage *sp; 277 278 fd = open(fcache->filename, O_RDONLY | O_BINARY); 279 if(fd < 0) 280 return errno; 281 sp = krb5_storage_from_fd(fd); 282 krb5_ret_int8(sp, &pvno); 283 if(pvno != 5) { 284 krb5_storage_free(sp); 285 close(fd); 286 return KRB5_CCACHE_BADVNO; 287 } 288 krb5_ret_int8(sp, &tag); /* should not be host byte order */ 289 fcache->version = tag; 290 storage_set_flags(context, sp, fcache->version); 291 switch (tag) { 292 case KRB5_FCC_FVNO_4: { 293 int16_t length; 294 295 krb5_ret_int16 (sp, &length); 296 while(length > 0) { 297 int16_t tag, data_len; 298 int i; 299 int8_t dummy; 300 301 krb5_ret_int16 (sp, &tag); 302 krb5_ret_int16 (sp, &data_len); 303 switch (tag) { 304 case FCC_TAG_DELTATIME : 305 krb5_ret_int32 (sp, &context->kdc_sec_offset); 306 krb5_ret_int32 (sp, &context->kdc_usec_offset); 307 break; 308 default : 309 for (i = 0; i < data_len; ++i) 310 krb5_ret_int8 (sp, &dummy); 311 break; 312 } 313 length -= 4 + data_len; 314 } 315 break; 316 } 317 case KRB5_FCC_FVNO_3: 318 case KRB5_FCC_FVNO_2: 319 case KRB5_FCC_FVNO_1: 320 break; 321 default : 322 krb5_storage_free (sp); 323 close (fd); 324 return KRB5_CCACHE_BADVNO; 325 } 326 *ret_sp = sp; 327 *ret_fd = fd; 328 return 0; 329 } 330 331 static krb5_error_code 332 fcc_get_principal(krb5_context context, 333 krb5_ccache id, 334 krb5_principal *principal) 335 { 336 krb5_error_code ret; 337 krb5_fcache *f = FCACHE(id); 338 int fd; 339 krb5_storage *sp; 340 341 ret = init_fcc (context, f, &sp, &fd); 342 if (ret) 343 return ret; 344 krb5_ret_principal(sp, principal); 345 krb5_storage_free(sp); 346 close(fd); 347 return 0; 348 } 349 350 static krb5_error_code 351 fcc_get_first (krb5_context context, 352 krb5_ccache id, 353 krb5_cc_cursor *cursor) 354 { 355 krb5_error_code ret; 356 krb5_principal principal; 357 krb5_fcache *f = FCACHE(id); 358 359 *cursor = malloc(sizeof(struct fcc_cursor)); 360 361 ret = init_fcc (context, f, &FCC_CURSOR(*cursor)->sp, 362 &FCC_CURSOR(*cursor)->fd); 363 if (ret) 364 return ret; 365 krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal); 366 krb5_free_principal (context, principal); 367 return 0; 368 } 369 370 static krb5_error_code 371 fcc_get_next (krb5_context context, 372 krb5_ccache id, 373 krb5_cc_cursor *cursor, 374 krb5_creds *creds) 375 { 376 return fcc_read_cred (context, FCACHE(id), FCC_CURSOR(*cursor)->sp, creds); 377 } 378 379 static krb5_error_code 380 fcc_end_get (krb5_context context, 381 krb5_ccache id, 382 krb5_cc_cursor *cursor) 383 { 384 krb5_storage_free(FCC_CURSOR(*cursor)->sp); 385 close (FCC_CURSOR(*cursor)->fd); 386 free(*cursor); 387 return 0; 388 } 389 390 static krb5_error_code 391 fcc_remove_cred(krb5_context context, 392 krb5_ccache id, 393 krb5_flags which, 394 krb5_creds *cred) 395 { 396 return 0; /* XXX */ 397 } 398 399 static krb5_error_code 400 fcc_set_flags(krb5_context context, 401 krb5_ccache id, 402 krb5_flags flags) 403 { 404 return 0; /* XXX */ 405 } 406 407 static krb5_error_code 408 fcc_get_version(krb5_context context, 409 krb5_ccache id) 410 { 411 return FCACHE(id)->version; 412 } 413 414 const krb5_cc_ops krb5_fcc_ops = { 415 "FILE", 416 fcc_get_name, 417 fcc_resolve, 418 fcc_gen_new, 419 fcc_initialize, 420 fcc_destroy, 421 fcc_close, 422 fcc_store_cred, 423 NULL, /* fcc_retrieve */ 424 fcc_get_principal, 425 fcc_get_first, 426 fcc_get_next, 427 fcc_end_get, 428 fcc_remove_cred, 429 fcc_set_flags, 430 fcc_get_version 431 }; 432