1 /* ccapi/server/ccs_ccache.c */ 2 /* 3 * Copyright 2006, 2007 Massachusetts Institute of Technology. 4 * All Rights Reserved. 5 * 6 * Export of this software from the United States of America may 7 * require a specific license from the United States Government. 8 * It is the responsibility of any person or organization contemplating 9 * export to obtain such a license before exporting. 10 * 11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 12 * distribute this software and its documentation for any purpose and 13 * without fee is hereby granted, provided that the above copyright 14 * notice appear in all copies and that both that copyright notice and 15 * this permission notice appear in supporting documentation, and that 16 * the name of M.I.T. not be used in advertising or publicity pertaining 17 * to distribution of the software without specific, written prior 18 * permission. Furthermore if you modify this software you must label 19 * your software as modified software and not distribute it in such a 20 * fashion that it might be confused with the original M.I.T. software. 21 * M.I.T. makes no representations about the suitability of 22 * this software for any purpose. It is provided "as is" without express 23 * or implied warranty. 24 */ 25 26 #include "ccs_common.h" 27 #include "ccs_os_notify.h" 28 29 struct ccs_ccache_d { 30 cci_identifier_t identifier; 31 ccs_lock_state_t lock_state; 32 cc_uint32 creds_version; 33 char *name; 34 char *v5_principal; 35 cc_time_t last_default_time; 36 cc_time_t last_changed_time; 37 cc_uint32 kdc_time_offset_v5_valid; 38 cc_time_t kdc_time_offset_v5; 39 ccs_credentials_list_t credentials; 40 ccs_callback_array_t change_callbacks; 41 }; 42 43 struct ccs_ccache_d ccs_ccache_initializer = { NULL, NULL, 0, NULL, NULL, 0, 0, 0, 0, NULL, NULL }; 44 45 /* ------------------------------------------------------------------------ */ 46 47 cc_int32 ccs_ccache_new (ccs_ccache_t *out_ccache, 48 cc_uint32 in_creds_version, 49 const char *in_name, 50 const char *in_principal, 51 ccs_ccache_list_t io_ccache_list) 52 { 53 cc_int32 err = ccNoError; 54 ccs_ccache_t ccache = NULL; 55 56 if (!out_ccache ) { err = cci_check_error (ccErrBadParam); } 57 if (!in_name ) { err = cci_check_error (ccErrBadParam); } 58 if (!in_principal) { err = cci_check_error (ccErrBadParam); } 59 60 if (!err) { 61 ccache = malloc (sizeof (*ccache)); 62 if (ccache) { 63 *ccache = ccs_ccache_initializer; 64 } else { 65 err = cci_check_error (ccErrNoMem); 66 } 67 } 68 69 if (!err) { 70 err = ccs_server_new_identifier (&ccache->identifier); 71 } 72 73 if (!err) { 74 err = ccs_lock_state_new (&ccache->lock_state, 75 ccErrInvalidCCache, 76 ccErrCCacheLocked, 77 ccErrCCacheUnlocked); 78 } 79 80 if (!err) { 81 ccache->name = strdup (in_name); 82 if (!ccache->name) { err = cci_check_error (ccErrNoMem); } 83 } 84 85 if (!err) { 86 ccache->creds_version = in_creds_version; 87 88 if (ccache->creds_version == cc_credentials_v5) { 89 ccache->v5_principal = strdup (in_principal); 90 if (!ccache->v5_principal) { err = cci_check_error (ccErrNoMem); } 91 92 } else { 93 err = cci_check_error (ccErrBadCredentialsVersion); 94 } 95 } 96 97 if (!err) { 98 err = ccs_credentials_list_new (&ccache->credentials); 99 } 100 101 if (!err) { 102 err = ccs_callback_array_new (&ccache->change_callbacks); 103 } 104 105 if (!err) { 106 cc_uint64 now = time (NULL); 107 cc_uint64 count = 0; 108 109 err = ccs_ccache_list_count (io_ccache_list, &count); 110 111 if (!err) { 112 /* first cache is default */ 113 ccache->last_default_time = (count == 0) ? now : 0; 114 cci_debug_printf ("%s ccache->last_default_time is %d.", 115 __FUNCTION__, ccache->last_default_time); 116 ccache->last_changed_time = now; 117 } 118 } 119 120 if (!err) { 121 /* Add self to the list of ccaches */ 122 err = ccs_ccache_list_add (io_ccache_list, ccache); 123 } 124 125 if (!err) { 126 *out_ccache = ccache; 127 ccache = NULL; 128 } 129 130 ccs_ccache_release (ccache); 131 132 return cci_check_error (err); 133 } 134 135 /* ------------------------------------------------------------------------ */ 136 137 cc_int32 ccs_ccache_reset (ccs_ccache_t io_ccache, 138 ccs_cache_collection_t io_cache_collection, 139 cc_uint32 in_creds_version, 140 const char *in_principal) 141 { 142 cc_int32 err = ccNoError; 143 char *v5_principal = NULL; 144 ccs_credentials_list_t credentials = NULL; 145 146 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 147 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 148 if (!in_principal ) { err = cci_check_error (ccErrBadParam); } 149 150 if (!err) { 151 io_ccache->creds_version = in_creds_version; 152 153 if (io_ccache->creds_version == cc_credentials_v5) { 154 v5_principal = strdup (in_principal); 155 if (!v5_principal) { err = cci_check_error (ccErrNoMem); } 156 157 } else { 158 err = cci_check_error (ccErrBadCredentialsVersion); 159 } 160 } 161 162 if (!err) { 163 err = ccs_credentials_list_new (&credentials); 164 } 165 166 if (!err) { 167 io_ccache->kdc_time_offset_v5 = 0; 168 io_ccache->kdc_time_offset_v5_valid = 0; 169 170 if (io_ccache->v5_principal) { free (io_ccache->v5_principal); } 171 io_ccache->v5_principal = v5_principal; 172 v5_principal = NULL; /* take ownership */ 173 174 ccs_credentials_list_release (io_ccache->credentials); 175 io_ccache->credentials = credentials; 176 credentials = NULL; /* take ownership */ 177 178 err = ccs_ccache_changed (io_ccache, io_cache_collection); 179 } 180 181 free (v5_principal); 182 ccs_credentials_list_release (credentials); 183 184 return cci_check_error (err); 185 } 186 187 /* ------------------------------------------------------------------------ */ 188 189 cc_int32 ccs_ccache_swap_contents (ccs_ccache_t io_source_ccache, 190 ccs_ccache_t io_destination_ccache, 191 ccs_cache_collection_t io_cache_collection) 192 { 193 cc_int32 err = ccNoError; 194 195 if (!io_source_ccache ) { err = cci_check_error (ccErrBadParam); } 196 if (!io_destination_ccache) { err = cci_check_error (ccErrBadParam); } 197 198 if (!err) { 199 struct ccs_ccache_d temp_ccache = *io_destination_ccache; 200 201 /* swap everything */ 202 *io_destination_ccache = *io_source_ccache; 203 *io_source_ccache = temp_ccache; 204 205 /* swap back the name and identifier */ 206 io_source_ccache->identifier = io_destination_ccache->identifier; 207 io_destination_ccache->identifier = temp_ccache.identifier; 208 209 io_source_ccache->name = io_destination_ccache->name; 210 io_destination_ccache->name = temp_ccache.name; 211 } 212 213 if (!err) { 214 err = ccs_ccache_changed (io_source_ccache, io_cache_collection); 215 } 216 217 if (!err) { 218 err = ccs_ccache_changed (io_destination_ccache, io_cache_collection); 219 } 220 221 return cci_check_error (err); 222 } 223 224 /* ------------------------------------------------------------------------ */ 225 226 cc_int32 ccs_ccache_release (ccs_ccache_t io_ccache) 227 { 228 cc_int32 err = ccNoError; 229 230 if (!err && io_ccache) { 231 cci_identifier_release (io_ccache->identifier); 232 ccs_lock_state_release (io_ccache->lock_state); 233 free (io_ccache->name); 234 free (io_ccache->v5_principal); 235 ccs_credentials_list_release (io_ccache->credentials); 236 ccs_callback_array_release (io_ccache->change_callbacks); 237 free (io_ccache); 238 } 239 240 return cci_check_error (err); 241 } 242 243 #ifdef TARGET_OS_MAC 244 #pragma mark - 245 #endif 246 247 /* ------------------------------------------------------------------------ */ 248 249 cc_int32 ccs_ccache_compare_identifier (ccs_ccache_t in_ccache, 250 cci_identifier_t in_identifier, 251 cc_uint32 *out_equal) 252 { 253 cc_int32 err = ccNoError; 254 255 if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } 256 if (!in_identifier) { err = cci_check_error (ccErrBadParam); } 257 if (!out_equal ) { err = cci_check_error (ccErrBadParam); } 258 259 if (!err) { 260 err = cci_identifier_compare (in_ccache->identifier, 261 in_identifier, 262 out_equal); 263 } 264 265 return cci_check_error (err); 266 } 267 268 /* ------------------------------------------------------------------------ */ 269 270 cc_int32 ccs_ccache_compare_name (ccs_ccache_t in_ccache, 271 const char *in_name, 272 cc_uint32 *out_equal) 273 { 274 cc_int32 err = ccNoError; 275 276 if (!in_ccache) { err = cci_check_error (ccErrBadParam); } 277 if (!in_name ) { err = cci_check_error (ccErrBadParam); } 278 if (!out_equal) { err = cci_check_error (ccErrBadParam); } 279 280 if (!err) { 281 *out_equal = (strcmp (in_ccache->name, in_name) == 0); 282 } 283 284 return cci_check_error (err); 285 } 286 287 #ifdef TARGET_OS_MAC 288 #pragma mark - 289 #endif 290 291 /* ------------------------------------------------------------------------ */ 292 293 cc_int32 ccs_ccache_changed (ccs_ccache_t io_ccache, 294 ccs_cache_collection_t io_cache_collection) 295 { 296 cc_int32 err = ccNoError; 297 k5_ipc_stream reply_data = NULL; 298 299 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 300 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 301 302 if (!err) { 303 cc_time_t now = time (NULL); 304 305 if (io_ccache->last_changed_time < now) { 306 io_ccache->last_changed_time = now; 307 } else { 308 io_ccache->last_changed_time++; 309 } 310 } 311 312 if (!err) { 313 err = ccs_cache_collection_changed (io_cache_collection); 314 } 315 316 if (!err) { 317 err = krb5int_ipc_stream_new (&reply_data); 318 } 319 320 if (!err) { 321 err = krb5int_ipc_stream_write_time (reply_data, io_ccache->last_changed_time); 322 } 323 324 if (!err) { 325 /* Loop over callbacks sending messages to them */ 326 cc_uint64 i; 327 cc_uint64 count = ccs_callback_array_count (io_ccache->change_callbacks); 328 329 for (i = 0; !err && i < count; i++) { 330 ccs_callback_t callback = ccs_callback_array_object_at_index (io_ccache->change_callbacks, i); 331 332 err = ccs_callback_reply_to_client (callback, reply_data); 333 334 if (!err) { 335 cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback); 336 err = ccs_callback_array_remove (io_ccache->change_callbacks, i); 337 break; 338 } 339 } 340 } 341 342 if (!err) { 343 err = ccs_os_notify_ccache_changed (io_cache_collection, 344 io_ccache->name); 345 } 346 347 krb5int_ipc_stream_release (reply_data); 348 349 return cci_check_error (err); 350 } 351 352 /* ------------------------------------------------------------------------ */ 353 354 static cc_int32 ccs_ccache_invalidate_change_callback (ccs_callback_owner_t io_ccache, 355 ccs_callback_t in_callback) 356 { 357 cc_int32 err = ccNoError; 358 359 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 360 if (!in_callback) { err = cci_check_error (ccErrBadParam); } 361 362 if (!err) { 363 /* Remove callback */ 364 ccs_ccache_t ccache = (ccs_ccache_t) io_ccache; 365 cc_uint64 i; 366 cc_uint64 count = ccs_callback_array_count (ccache->change_callbacks); 367 368 for (i = 0; !err && i < count; i++) { 369 ccs_callback_t callback = ccs_callback_array_object_at_index (ccache->change_callbacks, i); 370 371 if (callback == in_callback) { 372 cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback); 373 err = ccs_callback_array_remove (ccache->change_callbacks, i); 374 break; 375 } 376 } 377 } 378 379 return cci_check_error (err); 380 } 381 382 /* ------------------------------------------------------------------------ */ 383 384 cc_int32 ccs_ccache_notify_default_state_changed (ccs_ccache_t io_ccache, 385 ccs_cache_collection_t io_cache_collection, 386 cc_uint32 in_new_default_state) 387 { 388 cc_int32 err = ccNoError; 389 390 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 391 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 392 393 if (!err && in_new_default_state) { 394 cc_time_t now = time (NULL); 395 396 if (io_ccache->last_default_time < now) { 397 io_ccache->last_default_time = now; 398 } else { 399 io_ccache->last_default_time++; 400 } 401 } 402 403 if (!err) { 404 err = ccs_ccache_changed (io_ccache, io_cache_collection); 405 } 406 407 return cci_check_error (err); 408 } 409 410 #ifdef TARGET_OS_MAC 411 #pragma mark - 412 #endif 413 414 /* ------------------------------------------------------------------------ */ 415 416 cc_int32 ccs_ccache_find_credentials_iterator (ccs_ccache_t in_ccache, 417 cci_identifier_t in_identifier, 418 ccs_credentials_iterator_t *out_credentials_iterator) 419 { 420 cc_int32 err = ccNoError; 421 422 if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } 423 if (!in_identifier ) { err = cci_check_error (ccErrBadParam); } 424 if (!out_credentials_iterator) { err = cci_check_error (ccErrBadParam); } 425 426 if (!err) { 427 err = ccs_credentials_list_find_iterator (in_ccache->credentials, 428 in_identifier, 429 out_credentials_iterator); 430 } 431 432 // Don't report ccErrInvalidCredentials to the log file. Non-fatal. 433 return (err == ccErrInvalidCredentials) ? err : cci_check_error (err); 434 } 435 436 #ifdef TARGET_OS_MAC 437 #pragma mark - 438 #endif 439 440 /* ------------------------------------------------------------------------ */ 441 442 cc_int32 ccs_ccache_write (ccs_ccache_t in_ccache, 443 k5_ipc_stream io_stream) 444 { 445 cc_int32 err = ccNoError; 446 447 if (!in_ccache) { err = cci_check_error (ccErrBadParam); } 448 if (!io_stream) { err = cci_check_error (ccErrBadParam); } 449 450 if (!err) { 451 err = cci_identifier_write (in_ccache->identifier, io_stream); 452 } 453 454 return cci_check_error (err); 455 } 456 457 458 /* ------------------------------------------------------------------------ */ 459 460 cc_int32 ccs_ccache_write_name (ccs_ccache_t in_ccache, 461 k5_ipc_stream io_stream) 462 { 463 cc_int32 err = ccNoError; 464 465 if (!in_ccache) { err = cci_check_error (ccErrBadParam); } 466 if (!io_stream) { err = cci_check_error (ccErrBadParam); } 467 468 if (!err) { 469 err = krb5int_ipc_stream_write_string (io_stream, in_ccache->name); 470 } 471 472 return cci_check_error (err); 473 } 474 475 #ifdef TARGET_OS_MAC 476 #pragma mark - 477 #pragma mark -- IPC Messages -- 478 #endif 479 480 /* ------------------------------------------------------------------------ */ 481 482 static cc_int32 ccs_ccache_destroy (ccs_ccache_t io_ccache, 483 ccs_cache_collection_t io_cache_collection, 484 k5_ipc_stream in_request_data, 485 k5_ipc_stream io_reply_data) 486 { 487 cc_int32 err = ccNoError; 488 489 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 490 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 491 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 492 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 493 494 if (!err) { 495 err = ccs_cache_collection_destroy_ccache (io_cache_collection, 496 io_ccache->identifier); 497 } 498 499 if (!err) { 500 /* ccache has been destroyed so just mark the cache collection */ 501 err = ccs_cache_collection_changed (io_cache_collection); 502 } 503 504 return cci_check_error (err); 505 } 506 507 /* ------------------------------------------------------------------------ */ 508 509 static cc_int32 ccs_ccache_set_default (ccs_ccache_t io_ccache, 510 ccs_cache_collection_t io_cache_collection, 511 k5_ipc_stream in_request_data, 512 k5_ipc_stream io_reply_data) 513 { 514 cc_int32 err = ccNoError; 515 516 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 517 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 518 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 519 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 520 521 if (!err) { 522 err = ccs_cache_collection_set_default_ccache (io_cache_collection, 523 io_ccache->identifier); 524 } 525 526 return cci_check_error (err); 527 } 528 529 /* ------------------------------------------------------------------------ */ 530 531 static cc_int32 ccs_ccache_get_credentials_version (ccs_ccache_t io_ccache, 532 ccs_cache_collection_t io_cache_collection, 533 k5_ipc_stream in_request_data, 534 k5_ipc_stream io_reply_data) 535 { 536 cc_int32 err = ccNoError; 537 538 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 539 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 540 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 541 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 542 543 if (!err) { 544 err = krb5int_ipc_stream_write_uint32 (io_reply_data, io_ccache->creds_version); 545 } 546 547 return cci_check_error (err); 548 } 549 550 /* ------------------------------------------------------------------------ */ 551 552 static cc_int32 ccs_ccache_get_name (ccs_ccache_t io_ccache, 553 ccs_cache_collection_t io_cache_collection, 554 k5_ipc_stream in_request_data, 555 k5_ipc_stream io_reply_data) 556 { 557 cc_int32 err = ccNoError; 558 559 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 560 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 561 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 562 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 563 564 if (!err) { 565 err = krb5int_ipc_stream_write_string (io_reply_data, io_ccache->name); 566 } 567 568 return cci_check_error (err); 569 } 570 571 /* ------------------------------------------------------------------------ */ 572 573 static cc_int32 ccs_ccache_get_principal (ccs_ccache_t io_ccache, 574 ccs_cache_collection_t io_cache_collection, 575 k5_ipc_stream in_request_data, 576 k5_ipc_stream io_reply_data) 577 { 578 cc_int32 err = ccNoError; 579 cc_uint32 version = 0; 580 581 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 582 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 583 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 584 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 585 586 if (!err) { 587 err = krb5int_ipc_stream_read_uint32 (in_request_data, &version); 588 } 589 590 if (!err) { 591 if (version == cc_credentials_v5) { 592 err = krb5int_ipc_stream_write_string (io_reply_data, io_ccache->v5_principal); 593 594 } else { 595 err = cci_check_error (ccErrBadCredentialsVersion); 596 } 597 } 598 599 return cci_check_error (err); 600 } 601 602 /* ------------------------------------------------------------------------ */ 603 604 static cc_int32 ccs_ccache_set_principal (ccs_ccache_t io_ccache, 605 ccs_cache_collection_t io_cache_collection, 606 k5_ipc_stream in_request_data, 607 k5_ipc_stream io_reply_data) 608 { 609 cc_int32 err = ccNoError; 610 cc_uint32 version = 0; 611 char *principal = NULL; 612 613 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 614 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 615 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 616 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 617 618 if (!err) { 619 err = krb5int_ipc_stream_read_uint32 (in_request_data, &version); 620 } 621 622 if (!err) { 623 err = krb5int_ipc_stream_read_string (in_request_data, &principal); 624 } 625 626 if (!err) { 627 /* reset KDC time offsets because they are per-KDC */ 628 if (version == cc_credentials_v5) { 629 io_ccache->kdc_time_offset_v5 = 0; 630 io_ccache->kdc_time_offset_v5_valid = 0; 631 632 if (io_ccache->v5_principal) { free (io_ccache->v5_principal); } 633 io_ccache->v5_principal = principal; 634 principal = NULL; /* take ownership */ 635 636 } else { 637 err = cci_check_error (ccErrBadCredentialsVersion); 638 } 639 } 640 641 if (!err) { 642 io_ccache->creds_version |= version; 643 644 err = ccs_ccache_changed (io_ccache, io_cache_collection); 645 } 646 647 krb5int_ipc_stream_free_string (principal); 648 649 return cci_check_error (err); 650 } 651 652 /* ------------------------------------------------------------------------ */ 653 654 static cc_int32 ccs_ccache_store_credentials (ccs_ccache_t io_ccache, 655 ccs_cache_collection_t io_cache_collection, 656 k5_ipc_stream in_request_data, 657 k5_ipc_stream io_reply_data) 658 { 659 cc_int32 err = ccNoError; 660 ccs_credentials_t credentials = NULL; 661 662 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 663 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 664 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 665 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 666 667 if (!err) { 668 err = ccs_credentials_new (&credentials, in_request_data, 669 io_ccache->creds_version, 670 io_ccache->credentials); 671 } 672 673 if (!err) { 674 err = ccs_ccache_changed (io_ccache, io_cache_collection); 675 } 676 677 678 return cci_check_error (err); 679 } 680 681 /* ------------------------------------------------------------------------ */ 682 683 static cc_int32 ccs_ccache_remove_credentials (ccs_ccache_t io_ccache, 684 ccs_cache_collection_t io_cache_collection, 685 k5_ipc_stream in_request_data, 686 k5_ipc_stream io_reply_data) 687 { 688 cc_int32 err = ccNoError; 689 cci_identifier_t credentials_identifier = NULL; 690 691 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 692 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 693 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 694 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 695 696 if (!err) { 697 err = cci_identifier_read (&credentials_identifier, in_request_data); 698 } 699 700 if (!err) { 701 err = ccs_credentials_list_remove (io_ccache->credentials, credentials_identifier); 702 } 703 704 if (!err) { 705 err = ccs_ccache_changed (io_ccache, io_cache_collection); 706 } 707 708 cci_identifier_release (credentials_identifier); 709 710 return cci_check_error (err); 711 } 712 713 /* ------------------------------------------------------------------------ */ 714 715 static cc_int32 ccs_ccache_new_credentials_iterator (ccs_ccache_t io_ccache, 716 ccs_cache_collection_t io_cache_collection, 717 ccs_pipe_t in_client_pipe, 718 k5_ipc_stream in_request_data, 719 k5_ipc_stream io_reply_data) 720 { 721 cc_int32 err = ccNoError; 722 ccs_credentials_iterator_t credentials_iterator = NULL; 723 724 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 725 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 726 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 727 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 728 729 if (!err) { 730 err = ccs_credentials_list_new_iterator (io_ccache->credentials, 731 in_client_pipe, 732 &credentials_iterator); 733 } 734 735 if (!err) { 736 err = ccs_credentials_list_iterator_write (credentials_iterator, io_reply_data); 737 } 738 739 return cci_check_error (err); 740 } 741 742 /* ------------------------------------------------------------------------ */ 743 744 static cc_int32 ccs_ccache_move (ccs_ccache_t io_ccache, 745 ccs_cache_collection_t io_cache_collection, 746 k5_ipc_stream in_request_data, 747 k5_ipc_stream io_reply_data) 748 { 749 cc_int32 err = ccNoError; 750 cci_identifier_t source_identifier = NULL; 751 752 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 753 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 754 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 755 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 756 757 if (!err) { 758 /* Note: message is sent as the destination ccache to avoid */ 759 /* extra work on the server when deleting it the source ccache. */ 760 err = cci_identifier_read (&source_identifier, in_request_data); 761 } 762 763 if (!err) { 764 err = ccs_ccache_collection_move_ccache (io_cache_collection, 765 source_identifier, 766 io_ccache); 767 } 768 769 if (!err) { 770 err = ccs_ccache_changed (io_ccache, io_cache_collection); 771 } 772 773 cci_identifier_release (source_identifier); 774 775 return cci_check_error (err); 776 } 777 778 /* ------------------------------------------------------------------------ */ 779 780 static cc_int32 ccs_ccache_lock (ccs_pipe_t in_client_pipe, 781 ccs_pipe_t in_reply_pipe, 782 ccs_ccache_t io_ccache, 783 ccs_cache_collection_t io_cache_collection, 784 k5_ipc_stream in_request_data, 785 cc_uint32 *out_will_block, 786 k5_ipc_stream io_reply_data) 787 { 788 cc_int32 err = ccNoError; 789 cc_uint32 lock_type; 790 cc_uint32 block; 791 792 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 793 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 794 if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); } 795 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 796 if (!out_will_block ) { err = cci_check_error (ccErrBadParam); } 797 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 798 799 if (!err) { 800 err = krb5int_ipc_stream_read_uint32 (in_request_data, &lock_type); 801 } 802 803 if (!err) { 804 err = krb5int_ipc_stream_read_uint32 (in_request_data, &block); 805 } 806 807 if (!err) { 808 err = ccs_lock_state_add (io_ccache->lock_state, 809 in_client_pipe, in_reply_pipe, 810 lock_type, block, out_will_block); 811 } 812 813 return cci_check_error (err); 814 } 815 816 /* ------------------------------------------------------------------------ */ 817 818 static cc_int32 ccs_ccache_unlock (ccs_pipe_t in_client_pipe, 819 ccs_ccache_t io_ccache, 820 ccs_cache_collection_t io_cache_collection, 821 k5_ipc_stream in_request_data, 822 k5_ipc_stream io_reply_data) 823 { 824 cc_int32 err = ccNoError; 825 826 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 827 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 828 if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); } 829 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 830 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 831 832 if (!err) { 833 err = ccs_lock_state_remove (io_ccache->lock_state, in_client_pipe); 834 } 835 836 return cci_check_error (err); 837 } 838 839 /* ------------------------------------------------------------------------ */ 840 841 static cc_int32 ccs_ccache_get_last_default_time (ccs_ccache_t io_ccache, 842 ccs_cache_collection_t io_cache_collection, 843 k5_ipc_stream in_request_data, 844 k5_ipc_stream io_reply_data) 845 { 846 cc_int32 err = ccNoError; 847 848 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 849 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 850 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 851 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 852 853 if (!err && io_ccache->last_default_time == 0) { 854 err = cci_check_error (ccErrNeverDefault); 855 } 856 857 if (!err) { 858 err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_default_time); 859 } 860 861 return cci_check_error (err); 862 } 863 864 /* ------------------------------------------------------------------------ */ 865 866 static cc_int32 ccs_ccache_get_change_time (ccs_ccache_t io_ccache, 867 ccs_cache_collection_t io_cache_collection, 868 k5_ipc_stream in_request_data, 869 k5_ipc_stream io_reply_data) 870 { 871 cc_int32 err = ccNoError; 872 873 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 874 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 875 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 876 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 877 878 if (!err) { 879 err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_changed_time); 880 } 881 882 return cci_check_error (err); 883 } 884 885 /* ------------------------------------------------------------------------ */ 886 887 static cc_int32 ccs_ccache_wait_for_change (ccs_pipe_t in_client_pipe, 888 ccs_pipe_t in_reply_pipe, 889 ccs_ccache_t io_ccache, 890 ccs_cache_collection_t io_cache_collection, 891 k5_ipc_stream in_request_data, 892 k5_ipc_stream io_reply_data, 893 cc_uint32 *out_will_block) 894 { 895 cc_int32 err = ccNoError; 896 cc_time_t last_wait_for_change_time = 0; 897 cc_uint32 will_block = 0; 898 899 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 900 if (!ccs_pipe_valid (in_reply_pipe )) { err = cci_check_error (ccErrBadParam); } 901 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 902 if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); } 903 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 904 if (!out_will_block ) { err = cci_check_error (ccErrBadParam); } 905 906 if (!err) { 907 err = krb5int_ipc_stream_read_time (in_request_data, &last_wait_for_change_time); 908 } 909 910 if (!err) { 911 if (last_wait_for_change_time < io_ccache->last_changed_time) { 912 cci_debug_printf ("%s returning immediately", __FUNCTION__); 913 err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_changed_time); 914 915 } else { 916 ccs_callback_t callback = NULL; 917 918 err = ccs_callback_new (&callback, 919 ccErrInvalidCCache, 920 in_client_pipe, 921 in_reply_pipe, 922 (ccs_callback_owner_t) io_ccache, 923 ccs_ccache_invalidate_change_callback); 924 925 if (!err) { 926 err = ccs_callback_array_insert (io_ccache->change_callbacks, callback, 927 ccs_callback_array_count (io_ccache->change_callbacks)); 928 if (!err) { callback = NULL; /* take ownership */ } 929 930 cci_debug_printf ("%s blocking", __FUNCTION__); 931 will_block = 1; 932 } 933 934 ccs_callback_release (callback); 935 } 936 } 937 938 if (!err) { 939 *out_will_block = will_block; 940 } 941 942 return cci_check_error (err); 943 } 944 945 /* ------------------------------------------------------------------------ */ 946 947 static cc_int32 ccs_ccache_get_kdc_time_offset (ccs_ccache_t io_ccache, 948 ccs_cache_collection_t io_cache_collection, 949 k5_ipc_stream in_request_data, 950 k5_ipc_stream io_reply_data) 951 { 952 cc_int32 err = ccNoError; 953 cc_uint32 cred_vers = 0; 954 955 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 956 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 957 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 958 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 959 960 if (!err) { 961 err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers); 962 } 963 964 if (!err) { 965 if (cred_vers == cc_credentials_v5) { 966 if (io_ccache->kdc_time_offset_v5_valid) { 967 err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->kdc_time_offset_v5); 968 } else { 969 err = cci_check_error (ccErrTimeOffsetNotSet); 970 } 971 972 } else { 973 err = cci_check_error (ccErrBadCredentialsVersion); 974 } 975 } 976 977 return cci_check_error (err); 978 } 979 980 /* ------------------------------------------------------------------------ */ 981 982 static cc_int32 ccs_ccache_set_kdc_time_offset (ccs_ccache_t io_ccache, 983 ccs_cache_collection_t io_cache_collection, 984 k5_ipc_stream in_request_data, 985 k5_ipc_stream io_reply_data) 986 { 987 cc_int32 err = ccNoError; 988 cc_uint32 cred_vers = 0; 989 990 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 991 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 992 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 993 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 994 995 if (!err) { 996 err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers); 997 } 998 999 if (!err) { 1000 if (cred_vers == cc_credentials_v5) { 1001 err = krb5int_ipc_stream_read_time (in_request_data, &io_ccache->kdc_time_offset_v5); 1002 1003 if (!err) { 1004 io_ccache->kdc_time_offset_v5_valid = 1; 1005 } 1006 } else { 1007 err = cci_check_error (ccErrBadCredentialsVersion); 1008 } 1009 } 1010 1011 if (!err) { 1012 err = ccs_ccache_changed (io_ccache, io_cache_collection); 1013 } 1014 1015 return cci_check_error (err); 1016 } 1017 1018 /* ------------------------------------------------------------------------ */ 1019 1020 static cc_int32 ccs_ccache_clear_kdc_time_offset (ccs_ccache_t io_ccache, 1021 ccs_cache_collection_t io_cache_collection, 1022 k5_ipc_stream in_request_data, 1023 k5_ipc_stream io_reply_data) 1024 { 1025 cc_int32 err = ccNoError; 1026 cc_uint32 cred_vers = 0; 1027 1028 if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } 1029 if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); } 1030 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 1031 if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); } 1032 1033 if (!err) { 1034 err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers); 1035 } 1036 1037 if (!err) { 1038 if (cred_vers == cc_credentials_v5) { 1039 io_ccache->kdc_time_offset_v5 = 0; 1040 io_ccache->kdc_time_offset_v5_valid = 0; 1041 1042 } else { 1043 err = cci_check_error (ccErrBadCredentialsVersion); 1044 } 1045 } 1046 1047 if (!err) { 1048 err = ccs_ccache_changed (io_ccache, io_cache_collection); 1049 } 1050 1051 return cci_check_error (err); 1052 } 1053 1054 #ifdef TARGET_OS_MAC 1055 #pragma mark - 1056 #endif 1057 1058 /* ------------------------------------------------------------------------ */ 1059 1060 cc_int32 ccs_ccache_handle_message (ccs_pipe_t in_client_pipe, 1061 ccs_pipe_t in_reply_pipe, 1062 ccs_ccache_t io_ccache, 1063 ccs_cache_collection_t io_cache_collection, 1064 enum cci_msg_id_t in_request_name, 1065 k5_ipc_stream in_request_data, 1066 cc_uint32 *out_will_block, 1067 k5_ipc_stream *out_reply_data) 1068 { 1069 cc_int32 err = ccNoError; 1070 cc_uint32 will_block = 0; 1071 k5_ipc_stream reply_data = NULL; 1072 1073 if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); } 1074 if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); } 1075 if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); } 1076 if (!in_request_data ) { err = cci_check_error (ccErrBadParam); } 1077 if (!out_will_block ) { err = cci_check_error (ccErrBadParam); } 1078 if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); } 1079 1080 if (!err) { 1081 err = krb5int_ipc_stream_new (&reply_data); 1082 } 1083 1084 if (!err) { 1085 if (in_request_name == cci_ccache_destroy_msg_id) { 1086 err = ccs_ccache_destroy (io_ccache, io_cache_collection, 1087 in_request_data, reply_data); 1088 1089 } else if (in_request_name == cci_ccache_set_default_msg_id) { 1090 err = ccs_ccache_set_default (io_ccache, io_cache_collection, 1091 in_request_data, reply_data); 1092 1093 } else if (in_request_name == cci_ccache_get_credentials_version_msg_id) { 1094 err = ccs_ccache_get_credentials_version (io_ccache, io_cache_collection, 1095 in_request_data, reply_data); 1096 1097 } else if (in_request_name == cci_ccache_get_name_msg_id) { 1098 err = ccs_ccache_get_name (io_ccache, io_cache_collection, 1099 in_request_data, reply_data); 1100 1101 } else if (in_request_name == cci_ccache_get_principal_msg_id) { 1102 err = ccs_ccache_get_principal (io_ccache, io_cache_collection, 1103 in_request_data, reply_data); 1104 1105 } else if (in_request_name == cci_ccache_set_principal_msg_id) { 1106 err = ccs_ccache_set_principal (io_ccache, io_cache_collection, 1107 in_request_data, reply_data); 1108 1109 } else if (in_request_name == cci_ccache_store_credentials_msg_id) { 1110 err = ccs_ccache_store_credentials (io_ccache, io_cache_collection, 1111 in_request_data, reply_data); 1112 1113 } else if (in_request_name == cci_ccache_remove_credentials_msg_id) { 1114 err = ccs_ccache_remove_credentials (io_ccache, io_cache_collection, 1115 in_request_data, reply_data); 1116 1117 } else if (in_request_name == cci_ccache_new_credentials_iterator_msg_id) { 1118 err = ccs_ccache_new_credentials_iterator (io_ccache, 1119 io_cache_collection, 1120 in_client_pipe, 1121 in_request_data, 1122 reply_data); 1123 1124 } else if (in_request_name == cci_ccache_move_msg_id) { 1125 err = ccs_ccache_move (io_ccache, io_cache_collection, 1126 in_request_data, reply_data); 1127 1128 } else if (in_request_name == cci_ccache_lock_msg_id) { 1129 err = ccs_ccache_lock (in_client_pipe, in_reply_pipe, 1130 io_ccache, io_cache_collection, 1131 in_request_data, 1132 &will_block, reply_data); 1133 1134 } else if (in_request_name == cci_ccache_unlock_msg_id) { 1135 err = ccs_ccache_unlock (in_client_pipe, 1136 io_ccache, io_cache_collection, 1137 in_request_data, reply_data); 1138 1139 } else if (in_request_name == cci_ccache_get_last_default_time_msg_id) { 1140 err = ccs_ccache_get_last_default_time (io_ccache, io_cache_collection, 1141 in_request_data, reply_data); 1142 1143 } else if (in_request_name == cci_ccache_get_change_time_msg_id) { 1144 err = ccs_ccache_get_change_time (io_ccache, io_cache_collection, 1145 in_request_data, reply_data); 1146 1147 } else if (in_request_name == cci_ccache_wait_for_change_msg_id) { 1148 err = ccs_ccache_wait_for_change (in_client_pipe, in_reply_pipe, 1149 io_ccache, io_cache_collection, 1150 in_request_data, reply_data, 1151 &will_block); 1152 1153 } else if (in_request_name == cci_ccache_get_kdc_time_offset_msg_id) { 1154 err = ccs_ccache_get_kdc_time_offset (io_ccache, io_cache_collection, 1155 in_request_data, reply_data); 1156 1157 } else if (in_request_name == cci_ccache_set_kdc_time_offset_msg_id) { 1158 err = ccs_ccache_set_kdc_time_offset (io_ccache, io_cache_collection, 1159 in_request_data, reply_data); 1160 1161 } else if (in_request_name == cci_ccache_clear_kdc_time_offset_msg_id) { 1162 err = ccs_ccache_clear_kdc_time_offset (io_ccache, io_cache_collection, 1163 in_request_data, reply_data); 1164 1165 } else { 1166 err = ccErrBadInternalMessage; 1167 } 1168 } 1169 1170 if (!err) { 1171 *out_will_block = will_block; 1172 if (!will_block) { 1173 *out_reply_data = reply_data; 1174 reply_data = NULL; /* take ownership */ 1175 } else { 1176 *out_reply_data = NULL; 1177 } 1178 } 1179 1180 krb5int_ipc_stream_release (reply_data); 1181 1182 return cci_check_error (err); 1183 } 1184