1 /* 2 * Copyright (c) 2005, PADL Software Pty Ltd. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * 3. Neither the name of PADL Software nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include "kcm_locl.h" 34 35 RCSID("$Id: protocol.c 22112 2007-12-03 19:34:33Z lha $"); 36 37 static krb5_error_code 38 kcm_op_noop(krb5_context context, 39 kcm_client *client, 40 kcm_operation opcode, 41 krb5_storage *request, 42 krb5_storage *response) 43 { 44 KCM_LOG_REQUEST(context, client, opcode); 45 46 return 0; 47 } 48 49 /* 50 * Request: 51 * NameZ 52 * Response: 53 * NameZ 54 * 55 */ 56 static krb5_error_code 57 kcm_op_get_name(krb5_context context, 58 kcm_client *client, 59 kcm_operation opcode, 60 krb5_storage *request, 61 krb5_storage *response) 62 63 { 64 krb5_error_code ret; 65 char *name = NULL; 66 kcm_ccache ccache; 67 68 ret = krb5_ret_stringz(request, &name); 69 if (ret) 70 return ret; 71 72 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 73 74 ret = kcm_ccache_resolve_client(context, client, opcode, 75 name, &ccache); 76 if (ret) { 77 free(name); 78 return ret; 79 } 80 81 ret = krb5_store_stringz(response, ccache->name); 82 if (ret) { 83 kcm_release_ccache(context, &ccache); 84 free(name); 85 return ret; 86 } 87 88 free(name); 89 kcm_release_ccache(context, &ccache); 90 return 0; 91 } 92 93 /* 94 * Request: 95 * 96 * Response: 97 * NameZ 98 */ 99 static krb5_error_code 100 kcm_op_gen_new(krb5_context context, 101 kcm_client *client, 102 kcm_operation opcode, 103 krb5_storage *request, 104 krb5_storage *response) 105 { 106 krb5_error_code ret; 107 char *name; 108 109 KCM_LOG_REQUEST(context, client, opcode); 110 111 name = kcm_ccache_nextid(client->pid, client->uid, client->gid); 112 if (name == NULL) { 113 return KRB5_CC_NOMEM; 114 } 115 116 ret = krb5_store_stringz(response, name); 117 free(name); 118 119 return ret; 120 } 121 122 /* 123 * Request: 124 * NameZ 125 * Principal 126 * 127 * Response: 128 * 129 */ 130 static krb5_error_code 131 kcm_op_initialize(krb5_context context, 132 kcm_client *client, 133 kcm_operation opcode, 134 krb5_storage *request, 135 krb5_storage *response) 136 { 137 kcm_ccache ccache; 138 krb5_principal principal; 139 krb5_error_code ret; 140 char *name; 141 #if 0 142 kcm_event event; 143 #endif 144 145 KCM_LOG_REQUEST(context, client, opcode); 146 147 ret = krb5_ret_stringz(request, &name); 148 if (ret) 149 return ret; 150 151 ret = krb5_ret_principal(request, &principal); 152 if (ret) { 153 free(name); 154 return ret; 155 } 156 157 ret = kcm_ccache_new_client(context, client, name, &ccache); 158 if (ret) { 159 free(name); 160 krb5_free_principal(context, principal); 161 return ret; 162 } 163 164 ccache->client = principal; 165 166 free(name); 167 168 #if 0 169 /* 170 * Create a new credentials cache. To mitigate DoS attacks we will 171 * expire it in 30 minutes unless it has some credentials added 172 * to it 173 */ 174 175 event.fire_time = 30 * 60; 176 event.expire_time = 0; 177 event.backoff_time = 0; 178 event.action = KCM_EVENT_DESTROY_EMPTY_CACHE; 179 event.ccache = ccache; 180 181 ret = kcm_enqueue_event_relative(context, &event); 182 #endif 183 184 kcm_release_ccache(context, &ccache); 185 186 return ret; 187 } 188 189 /* 190 * Request: 191 * NameZ 192 * 193 * Response: 194 * 195 */ 196 static krb5_error_code 197 kcm_op_destroy(krb5_context context, 198 kcm_client *client, 199 kcm_operation opcode, 200 krb5_storage *request, 201 krb5_storage *response) 202 { 203 krb5_error_code ret; 204 char *name; 205 206 ret = krb5_ret_stringz(request, &name); 207 if (ret) 208 return ret; 209 210 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 211 212 ret = kcm_ccache_destroy_client(context, client, name); 213 214 free(name); 215 216 return ret; 217 } 218 219 /* 220 * Request: 221 * NameZ 222 * Creds 223 * 224 * Response: 225 * 226 */ 227 static krb5_error_code 228 kcm_op_store(krb5_context context, 229 kcm_client *client, 230 kcm_operation opcode, 231 krb5_storage *request, 232 krb5_storage *response) 233 { 234 krb5_creds creds; 235 krb5_error_code ret; 236 kcm_ccache ccache; 237 char *name; 238 239 ret = krb5_ret_stringz(request, &name); 240 if (ret) 241 return ret; 242 243 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 244 245 ret = krb5_ret_creds(request, &creds); 246 if (ret) { 247 free(name); 248 return ret; 249 } 250 251 ret = kcm_ccache_resolve_client(context, client, opcode, 252 name, &ccache); 253 if (ret) { 254 free(name); 255 krb5_free_cred_contents(context, &creds); 256 return ret; 257 } 258 259 ret = kcm_ccache_store_cred(context, ccache, &creds, 0); 260 if (ret) { 261 free(name); 262 krb5_free_cred_contents(context, &creds); 263 kcm_release_ccache(context, &ccache); 264 return ret; 265 } 266 267 kcm_ccache_enqueue_default(context, ccache, &creds); 268 269 free(name); 270 kcm_release_ccache(context, &ccache); 271 272 return 0; 273 } 274 275 /* 276 * Request: 277 * NameZ 278 * WhichFields 279 * MatchCreds 280 * 281 * Response: 282 * Creds 283 * 284 */ 285 static krb5_error_code 286 kcm_op_retrieve(krb5_context context, 287 kcm_client *client, 288 kcm_operation opcode, 289 krb5_storage *request, 290 krb5_storage *response) 291 { 292 uint32_t flags; 293 krb5_creds mcreds; 294 krb5_error_code ret; 295 kcm_ccache ccache; 296 char *name; 297 krb5_creds *credp; 298 int free_creds = 0; 299 300 ret = krb5_ret_stringz(request, &name); 301 if (ret) 302 return ret; 303 304 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 305 306 ret = krb5_ret_uint32(request, &flags); 307 if (ret) { 308 free(name); 309 return ret; 310 } 311 312 ret = krb5_ret_creds_tag(request, &mcreds); 313 if (ret) { 314 free(name); 315 return ret; 316 } 317 318 if (disallow_getting_krbtgt && 319 mcreds.server->name.name_string.len == 2 && 320 strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0) 321 { 322 free(name); 323 krb5_free_cred_contents(context, &mcreds); 324 return KRB5_FCC_PERM; 325 } 326 327 ret = kcm_ccache_resolve_client(context, client, opcode, 328 name, &ccache); 329 if (ret) { 330 free(name); 331 krb5_free_cred_contents(context, &mcreds); 332 return ret; 333 } 334 335 ret = kcm_ccache_retrieve_cred(context, ccache, flags, 336 &mcreds, &credp); 337 if (ret && ((flags & KRB5_GC_CACHED) == 0)) { 338 krb5_ccache_data ccdata; 339 340 /* try and acquire */ 341 HEIMDAL_MUTEX_lock(&ccache->mutex); 342 343 /* Fake up an internal ccache */ 344 kcm_internal_ccache(context, ccache, &ccdata); 345 346 /* glue cc layer will store creds */ 347 ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp); 348 if (ret == 0) 349 free_creds = 1; 350 351 HEIMDAL_MUTEX_unlock(&ccache->mutex); 352 } 353 354 if (ret == 0) { 355 ret = krb5_store_creds(response, credp); 356 } 357 358 free(name); 359 krb5_free_cred_contents(context, &mcreds); 360 kcm_release_ccache(context, &ccache); 361 362 if (free_creds) 363 krb5_free_cred_contents(context, credp); 364 365 return ret; 366 } 367 368 /* 369 * Request: 370 * NameZ 371 * 372 * Response: 373 * Principal 374 */ 375 static krb5_error_code 376 kcm_op_get_principal(krb5_context context, 377 kcm_client *client, 378 kcm_operation opcode, 379 krb5_storage *request, 380 krb5_storage *response) 381 { 382 krb5_error_code ret; 383 kcm_ccache ccache; 384 char *name; 385 386 ret = krb5_ret_stringz(request, &name); 387 if (ret) 388 return ret; 389 390 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 391 392 ret = kcm_ccache_resolve_client(context, client, opcode, 393 name, &ccache); 394 if (ret) { 395 free(name); 396 return ret; 397 } 398 399 if (ccache->client == NULL) 400 ret = KRB5_CC_NOTFOUND; 401 else 402 ret = krb5_store_principal(response, ccache->client); 403 404 free(name); 405 kcm_release_ccache(context, &ccache); 406 407 return 0; 408 } 409 410 /* 411 * Request: 412 * NameZ 413 * 414 * Response: 415 * Cursor 416 * 417 */ 418 static krb5_error_code 419 kcm_op_get_first(krb5_context context, 420 kcm_client *client, 421 kcm_operation opcode, 422 krb5_storage *request, 423 krb5_storage *response) 424 { 425 krb5_error_code ret; 426 kcm_ccache ccache; 427 uint32_t cursor; 428 char *name; 429 430 ret = krb5_ret_stringz(request, &name); 431 if (ret) 432 return ret; 433 434 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 435 436 ret = kcm_ccache_resolve_client(context, client, opcode, 437 name, &ccache); 438 if (ret) { 439 free(name); 440 return ret; 441 } 442 443 ret = kcm_cursor_new(context, client->pid, ccache, &cursor); 444 if (ret) { 445 kcm_release_ccache(context, &ccache); 446 free(name); 447 return ret; 448 } 449 450 ret = krb5_store_int32(response, cursor); 451 452 free(name); 453 kcm_release_ccache(context, &ccache); 454 455 return ret; 456 } 457 458 /* 459 * Request: 460 * NameZ 461 * Cursor 462 * 463 * Response: 464 * Creds 465 */ 466 static krb5_error_code 467 kcm_op_get_next(krb5_context context, 468 kcm_client *client, 469 kcm_operation opcode, 470 krb5_storage *request, 471 krb5_storage *response) 472 { 473 krb5_error_code ret; 474 kcm_ccache ccache; 475 char *name; 476 uint32_t cursor; 477 kcm_cursor *c; 478 479 ret = krb5_ret_stringz(request, &name); 480 if (ret) 481 return ret; 482 483 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 484 485 ret = krb5_ret_uint32(request, &cursor); 486 if (ret) { 487 free(name); 488 return ret; 489 } 490 491 ret = kcm_ccache_resolve_client(context, client, opcode, 492 name, &ccache); 493 if (ret) { 494 free(name); 495 return ret; 496 } 497 498 ret = kcm_cursor_find(context, client->pid, ccache, cursor, &c); 499 if (ret) { 500 kcm_release_ccache(context, &ccache); 501 free(name); 502 return ret; 503 } 504 505 HEIMDAL_MUTEX_lock(&ccache->mutex); 506 if (c->credp == NULL) { 507 ret = KRB5_CC_END; 508 } else { 509 ret = krb5_store_creds(response, &c->credp->cred); 510 c->credp = c->credp->next; 511 } 512 HEIMDAL_MUTEX_unlock(&ccache->mutex); 513 514 free(name); 515 kcm_release_ccache(context, &ccache); 516 517 return ret; 518 } 519 520 /* 521 * Request: 522 * NameZ 523 * Cursor 524 * 525 * Response: 526 * 527 */ 528 static krb5_error_code 529 kcm_op_end_get(krb5_context context, 530 kcm_client *client, 531 kcm_operation opcode, 532 krb5_storage *request, 533 krb5_storage *response) 534 { 535 krb5_error_code ret; 536 kcm_ccache ccache; 537 uint32_t cursor; 538 char *name; 539 540 ret = krb5_ret_stringz(request, &name); 541 if (ret) 542 return ret; 543 544 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 545 546 ret = krb5_ret_uint32(request, &cursor); 547 if (ret) { 548 free(name); 549 return ret; 550 } 551 552 ret = kcm_ccache_resolve_client(context, client, opcode, 553 name, &ccache); 554 if (ret) { 555 free(name); 556 return ret; 557 } 558 559 ret = kcm_cursor_delete(context, client->pid, ccache, cursor); 560 561 free(name); 562 kcm_release_ccache(context, &ccache); 563 564 return ret; 565 } 566 567 /* 568 * Request: 569 * NameZ 570 * WhichFields 571 * MatchCreds 572 * 573 * Response: 574 * 575 */ 576 static krb5_error_code 577 kcm_op_remove_cred(krb5_context context, 578 kcm_client *client, 579 kcm_operation opcode, 580 krb5_storage *request, 581 krb5_storage *response) 582 { 583 uint32_t whichfields; 584 krb5_creds mcreds; 585 krb5_error_code ret; 586 kcm_ccache ccache; 587 char *name; 588 589 ret = krb5_ret_stringz(request, &name); 590 if (ret) 591 return ret; 592 593 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 594 595 ret = krb5_ret_uint32(request, &whichfields); 596 if (ret) { 597 free(name); 598 return ret; 599 } 600 601 ret = krb5_ret_creds_tag(request, &mcreds); 602 if (ret) { 603 free(name); 604 return ret; 605 } 606 607 ret = kcm_ccache_resolve_client(context, client, opcode, 608 name, &ccache); 609 if (ret) { 610 free(name); 611 krb5_free_cred_contents(context, &mcreds); 612 return ret; 613 } 614 615 ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds); 616 617 /* XXX need to remove any events that match */ 618 619 free(name); 620 krb5_free_cred_contents(context, &mcreds); 621 kcm_release_ccache(context, &ccache); 622 623 return ret; 624 } 625 626 /* 627 * Request: 628 * NameZ 629 * Flags 630 * 631 * Response: 632 * 633 */ 634 static krb5_error_code 635 kcm_op_set_flags(krb5_context context, 636 kcm_client *client, 637 kcm_operation opcode, 638 krb5_storage *request, 639 krb5_storage *response) 640 { 641 uint32_t flags; 642 krb5_error_code ret; 643 kcm_ccache ccache; 644 char *name; 645 646 ret = krb5_ret_stringz(request, &name); 647 if (ret) 648 return ret; 649 650 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 651 652 ret = krb5_ret_uint32(request, &flags); 653 if (ret) { 654 free(name); 655 return ret; 656 } 657 658 ret = kcm_ccache_resolve_client(context, client, opcode, 659 name, &ccache); 660 if (ret) { 661 free(name); 662 return ret; 663 } 664 665 /* we don't really support any flags yet */ 666 free(name); 667 kcm_release_ccache(context, &ccache); 668 669 return 0; 670 } 671 672 /* 673 * Request: 674 * NameZ 675 * UID 676 * GID 677 * 678 * Response: 679 * 680 */ 681 static krb5_error_code 682 kcm_op_chown(krb5_context context, 683 kcm_client *client, 684 kcm_operation opcode, 685 krb5_storage *request, 686 krb5_storage *response) 687 { 688 uint32_t uid; 689 uint32_t gid; 690 krb5_error_code ret; 691 kcm_ccache ccache; 692 char *name; 693 694 ret = krb5_ret_stringz(request, &name); 695 if (ret) 696 return ret; 697 698 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 699 700 ret = krb5_ret_uint32(request, &uid); 701 if (ret) { 702 free(name); 703 return ret; 704 } 705 706 ret = krb5_ret_uint32(request, &gid); 707 if (ret) { 708 free(name); 709 return ret; 710 } 711 712 ret = kcm_ccache_resolve_client(context, client, opcode, 713 name, &ccache); 714 if (ret) { 715 free(name); 716 return ret; 717 } 718 719 ret = kcm_chown(context, client, ccache, uid, gid); 720 721 free(name); 722 kcm_release_ccache(context, &ccache); 723 724 return ret; 725 } 726 727 /* 728 * Request: 729 * NameZ 730 * Mode 731 * 732 * Response: 733 * 734 */ 735 static krb5_error_code 736 kcm_op_chmod(krb5_context context, 737 kcm_client *client, 738 kcm_operation opcode, 739 krb5_storage *request, 740 krb5_storage *response) 741 { 742 uint16_t mode; 743 krb5_error_code ret; 744 kcm_ccache ccache; 745 char *name; 746 747 ret = krb5_ret_stringz(request, &name); 748 if (ret) 749 return ret; 750 751 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 752 753 ret = krb5_ret_uint16(request, &mode); 754 if (ret) { 755 free(name); 756 return ret; 757 } 758 759 ret = kcm_ccache_resolve_client(context, client, opcode, 760 name, &ccache); 761 if (ret) { 762 free(name); 763 return ret; 764 } 765 766 ret = kcm_chmod(context, client, ccache, mode); 767 768 free(name); 769 kcm_release_ccache(context, &ccache); 770 771 return ret; 772 } 773 774 /* 775 * Protocol extensions for moving ticket acquisition responsibility 776 * from client to KCM follow. 777 */ 778 779 /* 780 * Request: 781 * NameZ 782 * ServerPrincipalPresent 783 * ServerPrincipal OPTIONAL 784 * Key 785 * 786 * Repsonse: 787 * 788 */ 789 static krb5_error_code 790 kcm_op_get_initial_ticket(krb5_context context, 791 kcm_client *client, 792 kcm_operation opcode, 793 krb5_storage *request, 794 krb5_storage *response) 795 { 796 krb5_error_code ret; 797 kcm_ccache ccache; 798 char *name; 799 int8_t not_tgt = 0; 800 krb5_principal server = NULL; 801 krb5_keyblock key; 802 803 krb5_keyblock_zero(&key); 804 805 ret = krb5_ret_stringz(request, &name); 806 if (ret) 807 return ret; 808 809 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 810 811 ret = krb5_ret_int8(request, ¬_tgt); 812 if (ret) { 813 free(name); 814 return ret; 815 } 816 817 if (not_tgt) { 818 ret = krb5_ret_principal(request, &server); 819 if (ret) { 820 free(name); 821 return ret; 822 } 823 } 824 825 ret = krb5_ret_keyblock(request, &key); 826 if (ret) { 827 free(name); 828 if (server != NULL) 829 krb5_free_principal(context, server); 830 return ret; 831 } 832 833 ret = kcm_ccache_resolve_client(context, client, opcode, 834 name, &ccache); 835 if (ret == 0) { 836 HEIMDAL_MUTEX_lock(&ccache->mutex); 837 838 if (ccache->server != NULL) { 839 krb5_free_principal(context, ccache->server); 840 ccache->server = NULL; 841 } 842 843 krb5_free_keyblock(context, &ccache->key.keyblock); 844 845 ccache->server = server; 846 ccache->key.keyblock = key; 847 ccache->flags |= KCM_FLAGS_USE_CACHED_KEY; 848 849 ret = kcm_ccache_enqueue_default(context, ccache, NULL); 850 if (ret) { 851 ccache->server = NULL; 852 krb5_keyblock_zero(&ccache->key.keyblock); 853 ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY); 854 } 855 856 HEIMDAL_MUTEX_unlock(&ccache->mutex); 857 } 858 859 free(name); 860 861 if (ret != 0) { 862 krb5_free_principal(context, server); 863 krb5_free_keyblock(context, &key); 864 } 865 866 kcm_release_ccache(context, &ccache); 867 868 return ret; 869 } 870 871 /* 872 * Request: 873 * NameZ 874 * ServerPrincipal 875 * KDCFlags 876 * EncryptionType 877 * 878 * Repsonse: 879 * 880 */ 881 static krb5_error_code 882 kcm_op_get_ticket(krb5_context context, 883 kcm_client *client, 884 kcm_operation opcode, 885 krb5_storage *request, 886 krb5_storage *response) 887 { 888 krb5_error_code ret; 889 kcm_ccache ccache; 890 char *name; 891 krb5_principal server = NULL; 892 krb5_ccache_data ccdata; 893 krb5_creds in, *out; 894 krb5_kdc_flags flags; 895 896 memset(&in, 0, sizeof(in)); 897 898 ret = krb5_ret_stringz(request, &name); 899 if (ret) 900 return ret; 901 902 KCM_LOG_REQUEST_NAME(context, client, opcode, name); 903 904 ret = krb5_ret_uint32(request, &flags.i); 905 if (ret) { 906 free(name); 907 return ret; 908 } 909 910 ret = krb5_ret_int32(request, &in.session.keytype); 911 if (ret) { 912 free(name); 913 return ret; 914 } 915 916 ret = krb5_ret_principal(request, &server); 917 if (ret) { 918 free(name); 919 return ret; 920 } 921 922 ret = kcm_ccache_resolve_client(context, client, opcode, 923 name, &ccache); 924 if (ret) { 925 krb5_free_principal(context, server); 926 free(name); 927 return ret; 928 } 929 930 HEIMDAL_MUTEX_lock(&ccache->mutex); 931 932 /* Fake up an internal ccache */ 933 kcm_internal_ccache(context, ccache, &ccdata); 934 935 in.client = ccache->client; 936 in.server = server; 937 in.times.endtime = 0; 938 939 /* glue cc layer will store creds */ 940 ret = krb5_get_credentials_with_flags(context, 0, flags, 941 &ccdata, &in, &out); 942 943 HEIMDAL_MUTEX_unlock(&ccache->mutex); 944 945 if (ret == 0) 946 krb5_free_cred_contents(context, out); 947 948 free(name); 949 950 return ret; 951 } 952 953 static struct kcm_op kcm_ops[] = { 954 { "NOOP", kcm_op_noop }, 955 { "GET_NAME", kcm_op_get_name }, 956 { "RESOLVE", kcm_op_noop }, 957 { "GEN_NEW", kcm_op_gen_new }, 958 { "INITIALIZE", kcm_op_initialize }, 959 { "DESTROY", kcm_op_destroy }, 960 { "STORE", kcm_op_store }, 961 { "RETRIEVE", kcm_op_retrieve }, 962 { "GET_PRINCIPAL", kcm_op_get_principal }, 963 { "GET_FIRST", kcm_op_get_first }, 964 { "GET_NEXT", kcm_op_get_next }, 965 { "END_GET", kcm_op_end_get }, 966 { "REMOVE_CRED", kcm_op_remove_cred }, 967 { "SET_FLAGS", kcm_op_set_flags }, 968 { "CHOWN", kcm_op_chown }, 969 { "CHMOD", kcm_op_chmod }, 970 { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket }, 971 { "GET_TICKET", kcm_op_get_ticket } 972 }; 973 974 975 const char *kcm_op2string(kcm_operation opcode) 976 { 977 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) 978 return "Unknown operation"; 979 980 return kcm_ops[opcode].name; 981 } 982 983 krb5_error_code 984 kcm_dispatch(krb5_context context, 985 kcm_client *client, 986 krb5_data *req_data, 987 krb5_data *resp_data) 988 { 989 krb5_error_code ret; 990 kcm_method method; 991 krb5_storage *req_sp = NULL; 992 krb5_storage *resp_sp = NULL; 993 uint16_t opcode; 994 995 resp_sp = krb5_storage_emem(); 996 if (resp_sp == NULL) { 997 return ENOMEM; 998 } 999 1000 if (client->pid == -1) { 1001 kcm_log(0, "Client had invalid process number"); 1002 ret = KRB5_FCC_INTERNAL; 1003 goto out; 1004 } 1005 1006 req_sp = krb5_storage_from_data(req_data); 1007 if (req_sp == NULL) { 1008 kcm_log(0, "Process %d: failed to initialize storage from data", 1009 client->pid); 1010 ret = KRB5_CC_IO; 1011 goto out; 1012 } 1013 1014 ret = krb5_ret_uint16(req_sp, &opcode); 1015 if (ret) { 1016 kcm_log(0, "Process %d: didn't send a message", client->pid); 1017 goto out; 1018 } 1019 1020 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) { 1021 kcm_log(0, "Process %d: invalid operation code %d", 1022 client->pid, opcode); 1023 ret = KRB5_FCC_INTERNAL; 1024 goto out; 1025 } 1026 method = kcm_ops[opcode].method; 1027 1028 /* seek past place for status code */ 1029 krb5_storage_seek(resp_sp, 4, SEEK_SET); 1030 1031 ret = (*method)(context, client, opcode, req_sp, resp_sp); 1032 1033 out: 1034 if (req_sp != NULL) { 1035 krb5_storage_free(req_sp); 1036 } 1037 1038 krb5_storage_seek(resp_sp, 0, SEEK_SET); 1039 krb5_store_int32(resp_sp, ret); 1040 1041 ret = krb5_storage_to_data(resp_sp, resp_data); 1042 krb5_storage_free(resp_sp); 1043 1044 return ret; 1045 } 1046 1047