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 "krb5_locl.h" 34 35 #ifdef HAVE_KCM 36 /* 37 * Client library for Kerberos Credentials Manager (KCM) daemon 38 */ 39 40 #ifdef HAVE_SYS_UN_H 41 #include <sys/un.h> 42 #endif 43 44 #include "kcm.h" 45 46 RCSID("$Id: kcm.c 22108 2007-12-03 17:23:53Z lha $"); 47 48 typedef struct krb5_kcmcache { 49 char *name; 50 struct sockaddr_un path; 51 char *door_path; 52 } krb5_kcmcache; 53 54 #define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data) 55 #define CACHENAME(X) (KCMCACHE(X)->name) 56 #define KCMCURSOR(C) (*(uint32_t *)(C)) 57 58 static krb5_error_code 59 try_door(krb5_context context, const krb5_kcmcache *k, 60 krb5_data *request_data, 61 krb5_data *response_data) 62 { 63 #ifdef HAVE_DOOR_CREATE 64 door_arg_t arg; 65 int fd; 66 int ret; 67 68 memset(&arg, 0, sizeof(arg)); 69 70 fd = open(k->door_path, O_RDWR); 71 if (fd < 0) 72 return KRB5_CC_IO; 73 74 arg.data_ptr = request_data->data; 75 arg.data_size = request_data->length; 76 arg.desc_ptr = NULL; 77 arg.desc_num = 0; 78 arg.rbuf = NULL; 79 arg.rsize = 0; 80 81 ret = door_call(fd, &arg); 82 close(fd); 83 if (ret != 0) 84 return KRB5_CC_IO; 85 86 ret = krb5_data_copy(response_data, arg.rbuf, arg.rsize); 87 munmap(arg.rbuf, arg.rsize); 88 if (ret) 89 return ret; 90 91 return 0; 92 #else 93 return KRB5_CC_IO; 94 #endif 95 } 96 97 static krb5_error_code 98 try_unix_socket(krb5_context context, const krb5_kcmcache *k, 99 krb5_data *request_data, 100 krb5_data *response_data) 101 { 102 krb5_error_code ret; 103 int fd; 104 105 fd = socket(AF_UNIX, SOCK_STREAM, 0); 106 if (fd < 0) 107 return KRB5_CC_IO; 108 109 if (connect(fd, rk_UNCONST(&k->path), sizeof(k->path)) != 0) { 110 close(fd); 111 return KRB5_CC_IO; 112 } 113 114 ret = _krb5_send_and_recv_tcp(fd, context->kdc_timeout, 115 request_data, response_data); 116 close(fd); 117 return ret; 118 } 119 120 static krb5_error_code 121 kcm_send_request(krb5_context context, 122 krb5_kcmcache *k, 123 krb5_storage *request, 124 krb5_data *response_data) 125 { 126 krb5_error_code ret; 127 krb5_data request_data; 128 int i; 129 130 response_data->data = NULL; 131 response_data->length = 0; 132 133 ret = krb5_storage_to_data(request, &request_data); 134 if (ret) { 135 krb5_clear_error_string(context); 136 return KRB5_CC_NOMEM; 137 } 138 139 ret = KRB5_CC_IO; 140 141 for (i = 0; i < context->max_retries; i++) { 142 ret = try_door(context, k, &request_data, response_data); 143 if (ret == 0 && response_data->length != 0) 144 break; 145 ret = try_unix_socket(context, k, &request_data, response_data); 146 if (ret == 0 && response_data->length != 0) 147 break; 148 } 149 150 krb5_data_free(&request_data); 151 152 if (ret) { 153 krb5_clear_error_string(context); 154 ret = KRB5_CC_IO; 155 } 156 157 return ret; 158 } 159 160 static krb5_error_code 161 kcm_storage_request(krb5_context context, 162 kcm_operation opcode, 163 krb5_storage **storage_p) 164 { 165 krb5_storage *sp; 166 krb5_error_code ret; 167 168 *storage_p = NULL; 169 170 sp = krb5_storage_emem(); 171 if (sp == NULL) { 172 krb5_set_error_string(context, "malloc: out of memory"); 173 return KRB5_CC_NOMEM; 174 } 175 176 /* Send MAJOR | VERSION | OPCODE */ 177 ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR); 178 if (ret) 179 goto fail; 180 ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR); 181 if (ret) 182 goto fail; 183 ret = krb5_store_int16(sp, opcode); 184 if (ret) 185 goto fail; 186 187 *storage_p = sp; 188 fail: 189 if (ret) { 190 krb5_set_error_string(context, "Failed to encode request"); 191 krb5_storage_free(sp); 192 } 193 194 return ret; 195 } 196 197 static krb5_error_code 198 kcm_alloc(krb5_context context, const char *name, krb5_ccache *id) 199 { 200 krb5_kcmcache *k; 201 const char *path; 202 203 k = malloc(sizeof(*k)); 204 if (k == NULL) { 205 krb5_set_error_string(context, "malloc: out of memory"); 206 return KRB5_CC_NOMEM; 207 } 208 209 if (name != NULL) { 210 k->name = strdup(name); 211 if (k->name == NULL) { 212 free(k); 213 krb5_set_error_string(context, "malloc: out of memory"); 214 return KRB5_CC_NOMEM; 215 } 216 } else 217 k->name = NULL; 218 219 path = krb5_config_get_string_default(context, NULL, 220 _PATH_KCM_SOCKET, 221 "libdefaults", 222 "kcm_socket", 223 NULL); 224 225 k->path.sun_family = AF_UNIX; 226 strlcpy(k->path.sun_path, path, sizeof(k->path.sun_path)); 227 228 path = krb5_config_get_string_default(context, NULL, 229 _PATH_KCM_DOOR, 230 "libdefaults", 231 "kcm_door", 232 NULL); 233 k->door_path = strdup(path); 234 235 (*id)->data.data = k; 236 (*id)->data.length = sizeof(*k); 237 238 return 0; 239 } 240 241 static krb5_error_code 242 kcm_call(krb5_context context, 243 krb5_kcmcache *k, 244 krb5_storage *request, 245 krb5_storage **response_p, 246 krb5_data *response_data_p) 247 { 248 krb5_data response_data; 249 krb5_error_code ret; 250 int32_t status; 251 krb5_storage *response; 252 253 if (response_p != NULL) 254 *response_p = NULL; 255 256 ret = kcm_send_request(context, k, request, &response_data); 257 if (ret) { 258 return ret; 259 } 260 261 response = krb5_storage_from_data(&response_data); 262 if (response == NULL) { 263 krb5_data_free(&response_data); 264 return KRB5_CC_IO; 265 } 266 267 ret = krb5_ret_int32(response, &status); 268 if (ret) { 269 krb5_storage_free(response); 270 krb5_data_free(&response_data); 271 return KRB5_CC_FORMAT; 272 } 273 274 if (status) { 275 krb5_storage_free(response); 276 krb5_data_free(&response_data); 277 return status; 278 } 279 280 if (response_p != NULL) { 281 *response_data_p = response_data; 282 *response_p = response; 283 284 return 0; 285 } 286 287 krb5_storage_free(response); 288 krb5_data_free(&response_data); 289 290 return 0; 291 } 292 293 static void 294 kcm_free(krb5_context context, krb5_ccache *id) 295 { 296 krb5_kcmcache *k = KCMCACHE(*id); 297 298 if (k != NULL) { 299 if (k->name != NULL) 300 free(k->name); 301 if (k->door_path) 302 free(k->door_path); 303 memset(k, 0, sizeof(*k)); 304 krb5_data_free(&(*id)->data); 305 } 306 307 *id = NULL; 308 } 309 310 static const char * 311 kcm_get_name(krb5_context context, 312 krb5_ccache id) 313 { 314 return CACHENAME(id); 315 } 316 317 static krb5_error_code 318 kcm_resolve(krb5_context context, krb5_ccache *id, const char *res) 319 { 320 return kcm_alloc(context, res, id); 321 } 322 323 /* 324 * Request: 325 * 326 * Response: 327 * NameZ 328 */ 329 static krb5_error_code 330 kcm_gen_new(krb5_context context, krb5_ccache *id) 331 { 332 krb5_kcmcache *k; 333 krb5_error_code ret; 334 krb5_storage *request, *response; 335 krb5_data response_data; 336 337 ret = kcm_alloc(context, NULL, id); 338 if (ret) 339 return ret; 340 341 k = KCMCACHE(*id); 342 343 ret = kcm_storage_request(context, KCM_OP_GEN_NEW, &request); 344 if (ret) { 345 kcm_free(context, id); 346 return ret; 347 } 348 349 ret = kcm_call(context, k, request, &response, &response_data); 350 if (ret) { 351 krb5_storage_free(request); 352 kcm_free(context, id); 353 return ret; 354 } 355 356 ret = krb5_ret_stringz(response, &k->name); 357 if (ret) 358 ret = KRB5_CC_IO; 359 360 krb5_storage_free(request); 361 krb5_storage_free(response); 362 krb5_data_free(&response_data); 363 364 if (ret) 365 kcm_free(context, id); 366 367 return ret; 368 } 369 370 /* 371 * Request: 372 * NameZ 373 * Principal 374 * 375 * Response: 376 * 377 */ 378 static krb5_error_code 379 kcm_initialize(krb5_context context, 380 krb5_ccache id, 381 krb5_principal primary_principal) 382 { 383 krb5_error_code ret; 384 krb5_kcmcache *k = KCMCACHE(id); 385 krb5_storage *request; 386 387 ret = kcm_storage_request(context, KCM_OP_INITIALIZE, &request); 388 if (ret) 389 return ret; 390 391 ret = krb5_store_stringz(request, k->name); 392 if (ret) { 393 krb5_storage_free(request); 394 return ret; 395 } 396 397 ret = krb5_store_principal(request, primary_principal); 398 if (ret) { 399 krb5_storage_free(request); 400 return ret; 401 } 402 403 ret = kcm_call(context, k, request, NULL, NULL); 404 405 krb5_storage_free(request); 406 return ret; 407 } 408 409 static krb5_error_code 410 kcm_close(krb5_context context, 411 krb5_ccache id) 412 { 413 kcm_free(context, &id); 414 return 0; 415 } 416 417 /* 418 * Request: 419 * NameZ 420 * 421 * Response: 422 * 423 */ 424 static krb5_error_code 425 kcm_destroy(krb5_context context, 426 krb5_ccache id) 427 { 428 krb5_error_code ret; 429 krb5_kcmcache *k = KCMCACHE(id); 430 krb5_storage *request; 431 432 ret = kcm_storage_request(context, KCM_OP_DESTROY, &request); 433 if (ret) 434 return ret; 435 436 ret = krb5_store_stringz(request, k->name); 437 if (ret) { 438 krb5_storage_free(request); 439 return ret; 440 } 441 442 ret = kcm_call(context, k, request, NULL, NULL); 443 444 krb5_storage_free(request); 445 return ret; 446 } 447 448 /* 449 * Request: 450 * NameZ 451 * Creds 452 * 453 * Response: 454 * 455 */ 456 static krb5_error_code 457 kcm_store_cred(krb5_context context, 458 krb5_ccache id, 459 krb5_creds *creds) 460 { 461 krb5_error_code ret; 462 krb5_kcmcache *k = KCMCACHE(id); 463 krb5_storage *request; 464 465 ret = kcm_storage_request(context, KCM_OP_STORE, &request); 466 if (ret) 467 return ret; 468 469 ret = krb5_store_stringz(request, k->name); 470 if (ret) { 471 krb5_storage_free(request); 472 return ret; 473 } 474 475 ret = krb5_store_creds(request, creds); 476 if (ret) { 477 krb5_storage_free(request); 478 return ret; 479 } 480 481 ret = kcm_call(context, k, request, NULL, NULL); 482 483 krb5_storage_free(request); 484 return ret; 485 } 486 487 /* 488 * Request: 489 * NameZ 490 * WhichFields 491 * MatchCreds 492 * 493 * Response: 494 * Creds 495 * 496 */ 497 static krb5_error_code 498 kcm_retrieve(krb5_context context, 499 krb5_ccache id, 500 krb5_flags which, 501 const krb5_creds *mcred, 502 krb5_creds *creds) 503 { 504 krb5_error_code ret; 505 krb5_kcmcache *k = KCMCACHE(id); 506 krb5_storage *request, *response; 507 krb5_data response_data; 508 509 ret = kcm_storage_request(context, KCM_OP_RETRIEVE, &request); 510 if (ret) 511 return ret; 512 513 ret = krb5_store_stringz(request, k->name); 514 if (ret) { 515 krb5_storage_free(request); 516 return ret; 517 } 518 519 ret = krb5_store_int32(request, which); 520 if (ret) { 521 krb5_storage_free(request); 522 return ret; 523 } 524 525 ret = krb5_store_creds_tag(request, rk_UNCONST(mcred)); 526 if (ret) { 527 krb5_storage_free(request); 528 return ret; 529 } 530 531 ret = kcm_call(context, k, request, &response, &response_data); 532 if (ret) { 533 krb5_storage_free(request); 534 return ret; 535 } 536 537 ret = krb5_ret_creds(response, creds); 538 if (ret) 539 ret = KRB5_CC_IO; 540 541 krb5_storage_free(request); 542 krb5_storage_free(response); 543 krb5_data_free(&response_data); 544 545 return ret; 546 } 547 548 /* 549 * Request: 550 * NameZ 551 * 552 * Response: 553 * Principal 554 */ 555 static krb5_error_code 556 kcm_get_principal(krb5_context context, 557 krb5_ccache id, 558 krb5_principal *principal) 559 { 560 krb5_error_code ret; 561 krb5_kcmcache *k = KCMCACHE(id); 562 krb5_storage *request, *response; 563 krb5_data response_data; 564 565 ret = kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request); 566 if (ret) 567 return ret; 568 569 ret = krb5_store_stringz(request, k->name); 570 if (ret) { 571 krb5_storage_free(request); 572 return ret; 573 } 574 575 ret = kcm_call(context, k, request, &response, &response_data); 576 if (ret) { 577 krb5_storage_free(request); 578 return ret; 579 } 580 581 ret = krb5_ret_principal(response, principal); 582 if (ret) 583 ret = KRB5_CC_IO; 584 585 krb5_storage_free(request); 586 krb5_storage_free(response); 587 krb5_data_free(&response_data); 588 589 return ret; 590 } 591 592 /* 593 * Request: 594 * NameZ 595 * 596 * Response: 597 * Cursor 598 * 599 */ 600 static krb5_error_code 601 kcm_get_first (krb5_context context, 602 krb5_ccache id, 603 krb5_cc_cursor *cursor) 604 { 605 krb5_error_code ret; 606 krb5_kcmcache *k = KCMCACHE(id); 607 krb5_storage *request, *response; 608 krb5_data response_data; 609 int32_t tmp; 610 611 ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request); 612 if (ret) 613 return ret; 614 615 ret = krb5_store_stringz(request, k->name); 616 if (ret) { 617 krb5_storage_free(request); 618 return ret; 619 } 620 621 ret = kcm_call(context, k, request, &response, &response_data); 622 if (ret) { 623 krb5_storage_free(request); 624 return ret; 625 } 626 627 ret = krb5_ret_int32(response, &tmp); 628 if (ret || tmp < 0) 629 ret = KRB5_CC_IO; 630 631 krb5_storage_free(request); 632 krb5_storage_free(response); 633 krb5_data_free(&response_data); 634 635 if (ret) 636 return ret; 637 638 *cursor = malloc(sizeof(tmp)); 639 if (*cursor == NULL) 640 return KRB5_CC_NOMEM; 641 642 KCMCURSOR(*cursor) = tmp; 643 644 return 0; 645 } 646 647 /* 648 * Request: 649 * NameZ 650 * Cursor 651 * 652 * Response: 653 * Creds 654 */ 655 static krb5_error_code 656 kcm_get_next (krb5_context context, 657 krb5_ccache id, 658 krb5_cc_cursor *cursor, 659 krb5_creds *creds) 660 { 661 krb5_error_code ret; 662 krb5_kcmcache *k = KCMCACHE(id); 663 krb5_storage *request, *response; 664 krb5_data response_data; 665 666 ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request); 667 if (ret) 668 return ret; 669 670 ret = krb5_store_stringz(request, k->name); 671 if (ret) { 672 krb5_storage_free(request); 673 return ret; 674 } 675 676 ret = krb5_store_int32(request, KCMCURSOR(*cursor)); 677 if (ret) { 678 krb5_storage_free(request); 679 return ret; 680 } 681 682 ret = kcm_call(context, k, request, &response, &response_data); 683 if (ret) { 684 krb5_storage_free(request); 685 return ret; 686 } 687 688 ret = krb5_ret_creds(response, creds); 689 if (ret) 690 ret = KRB5_CC_IO; 691 692 krb5_storage_free(request); 693 krb5_storage_free(response); 694 krb5_data_free(&response_data); 695 696 return ret; 697 } 698 699 /* 700 * Request: 701 * NameZ 702 * Cursor 703 * 704 * Response: 705 * 706 */ 707 static krb5_error_code 708 kcm_end_get (krb5_context context, 709 krb5_ccache id, 710 krb5_cc_cursor *cursor) 711 { 712 krb5_error_code ret; 713 krb5_kcmcache *k = KCMCACHE(id); 714 krb5_storage *request; 715 716 ret = kcm_storage_request(context, KCM_OP_END_GET, &request); 717 if (ret) 718 return ret; 719 720 ret = krb5_store_stringz(request, k->name); 721 if (ret) { 722 krb5_storage_free(request); 723 return ret; 724 } 725 726 ret = krb5_store_int32(request, KCMCURSOR(*cursor)); 727 if (ret) { 728 krb5_storage_free(request); 729 return ret; 730 } 731 732 ret = kcm_call(context, k, request, NULL, NULL); 733 if (ret) { 734 krb5_storage_free(request); 735 return ret; 736 } 737 738 krb5_storage_free(request); 739 740 KCMCURSOR(*cursor) = 0; 741 free(*cursor); 742 *cursor = NULL; 743 744 return ret; 745 } 746 747 /* 748 * Request: 749 * NameZ 750 * WhichFields 751 * MatchCreds 752 * 753 * Response: 754 * 755 */ 756 static krb5_error_code 757 kcm_remove_cred(krb5_context context, 758 krb5_ccache id, 759 krb5_flags which, 760 krb5_creds *cred) 761 { 762 krb5_error_code ret; 763 krb5_kcmcache *k = KCMCACHE(id); 764 krb5_storage *request; 765 766 ret = kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request); 767 if (ret) 768 return ret; 769 770 ret = krb5_store_stringz(request, k->name); 771 if (ret) { 772 krb5_storage_free(request); 773 return ret; 774 } 775 776 ret = krb5_store_int32(request, which); 777 if (ret) { 778 krb5_storage_free(request); 779 return ret; 780 } 781 782 ret = krb5_store_creds_tag(request, cred); 783 if (ret) { 784 krb5_storage_free(request); 785 return ret; 786 } 787 788 ret = kcm_call(context, k, request, NULL, NULL); 789 790 krb5_storage_free(request); 791 return ret; 792 } 793 794 static krb5_error_code 795 kcm_set_flags(krb5_context context, 796 krb5_ccache id, 797 krb5_flags flags) 798 { 799 krb5_error_code ret; 800 krb5_kcmcache *k = KCMCACHE(id); 801 krb5_storage *request; 802 803 ret = kcm_storage_request(context, KCM_OP_SET_FLAGS, &request); 804 if (ret) 805 return ret; 806 807 ret = krb5_store_stringz(request, k->name); 808 if (ret) { 809 krb5_storage_free(request); 810 return ret; 811 } 812 813 ret = krb5_store_int32(request, flags); 814 if (ret) { 815 krb5_storage_free(request); 816 return ret; 817 } 818 819 ret = kcm_call(context, k, request, NULL, NULL); 820 821 krb5_storage_free(request); 822 return ret; 823 } 824 825 static krb5_error_code 826 kcm_get_version(krb5_context context, 827 krb5_ccache id) 828 { 829 return 0; 830 } 831 832 static krb5_error_code 833 kcm_move(krb5_context context, krb5_ccache from, krb5_ccache to) 834 { 835 krb5_set_error_string(context, "kcm_move not implemented"); 836 return EINVAL; 837 } 838 839 static krb5_error_code 840 kcm_default_name(krb5_context context, char **str) 841 { 842 return _krb5_expand_default_cc_name(context, 843 KRB5_DEFAULT_CCNAME_KCM, 844 str); 845 } 846 847 /** 848 * Variable containing the KCM based credential cache implemention. 849 * 850 * @ingroup krb5_ccache 851 */ 852 853 const krb5_cc_ops krb5_kcm_ops = { 854 "KCM", 855 kcm_get_name, 856 kcm_resolve, 857 kcm_gen_new, 858 kcm_initialize, 859 kcm_destroy, 860 kcm_close, 861 kcm_store_cred, 862 kcm_retrieve, 863 kcm_get_principal, 864 kcm_get_first, 865 kcm_get_next, 866 kcm_end_get, 867 kcm_remove_cred, 868 kcm_set_flags, 869 kcm_get_version, 870 NULL, 871 NULL, 872 NULL, 873 kcm_move, 874 kcm_default_name 875 }; 876 877 krb5_boolean 878 _krb5_kcm_is_running(krb5_context context) 879 { 880 krb5_error_code ret; 881 krb5_ccache_data ccdata; 882 krb5_ccache id = &ccdata; 883 krb5_boolean running; 884 885 ret = kcm_alloc(context, NULL, &id); 886 if (ret) 887 return 0; 888 889 running = (_krb5_kcm_noop(context, id) == 0); 890 891 kcm_free(context, &id); 892 893 return running; 894 } 895 896 /* 897 * Request: 898 * 899 * Response: 900 * 901 */ 902 krb5_error_code 903 _krb5_kcm_noop(krb5_context context, 904 krb5_ccache id) 905 { 906 krb5_error_code ret; 907 krb5_kcmcache *k = KCMCACHE(id); 908 krb5_storage *request; 909 910 ret = kcm_storage_request(context, KCM_OP_NOOP, &request); 911 if (ret) 912 return ret; 913 914 ret = kcm_call(context, k, request, NULL, NULL); 915 916 krb5_storage_free(request); 917 return ret; 918 } 919 920 921 /* 922 * Request: 923 * NameZ 924 * Mode 925 * 926 * Response: 927 * 928 */ 929 krb5_error_code 930 _krb5_kcm_chmod(krb5_context context, 931 krb5_ccache id, 932 uint16_t mode) 933 { 934 krb5_error_code ret; 935 krb5_kcmcache *k = KCMCACHE(id); 936 krb5_storage *request; 937 938 ret = kcm_storage_request(context, KCM_OP_CHMOD, &request); 939 if (ret) 940 return ret; 941 942 ret = krb5_store_stringz(request, k->name); 943 if (ret) { 944 krb5_storage_free(request); 945 return ret; 946 } 947 948 ret = krb5_store_int16(request, mode); 949 if (ret) { 950 krb5_storage_free(request); 951 return ret; 952 } 953 954 ret = kcm_call(context, k, request, NULL, NULL); 955 956 krb5_storage_free(request); 957 return ret; 958 } 959 960 961 /* 962 * Request: 963 * NameZ 964 * UID 965 * GID 966 * 967 * Response: 968 * 969 */ 970 krb5_error_code 971 _krb5_kcm_chown(krb5_context context, 972 krb5_ccache id, 973 uint32_t uid, 974 uint32_t gid) 975 { 976 krb5_error_code ret; 977 krb5_kcmcache *k = KCMCACHE(id); 978 krb5_storage *request; 979 980 ret = kcm_storage_request(context, KCM_OP_CHOWN, &request); 981 if (ret) 982 return ret; 983 984 ret = krb5_store_stringz(request, k->name); 985 if (ret) { 986 krb5_storage_free(request); 987 return ret; 988 } 989 990 ret = krb5_store_int32(request, uid); 991 if (ret) { 992 krb5_storage_free(request); 993 return ret; 994 } 995 996 ret = krb5_store_int32(request, gid); 997 if (ret) { 998 krb5_storage_free(request); 999 return ret; 1000 } 1001 1002 ret = kcm_call(context, k, request, NULL, NULL); 1003 1004 krb5_storage_free(request); 1005 return ret; 1006 } 1007 1008 1009 /* 1010 * Request: 1011 * NameZ 1012 * ServerPrincipalPresent 1013 * ServerPrincipal OPTIONAL 1014 * Key 1015 * 1016 * Repsonse: 1017 * 1018 */ 1019 krb5_error_code 1020 _krb5_kcm_get_initial_ticket(krb5_context context, 1021 krb5_ccache id, 1022 krb5_principal server, 1023 krb5_keyblock *key) 1024 { 1025 krb5_error_code ret; 1026 krb5_kcmcache *k = KCMCACHE(id); 1027 krb5_storage *request; 1028 1029 ret = kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request); 1030 if (ret) 1031 return ret; 1032 1033 ret = krb5_store_stringz(request, k->name); 1034 if (ret) { 1035 krb5_storage_free(request); 1036 return ret; 1037 } 1038 1039 ret = krb5_store_int8(request, (server == NULL) ? 0 : 1); 1040 if (ret) { 1041 krb5_storage_free(request); 1042 return ret; 1043 } 1044 1045 if (server != NULL) { 1046 ret = krb5_store_principal(request, server); 1047 if (ret) { 1048 krb5_storage_free(request); 1049 return ret; 1050 } 1051 } 1052 1053 ret = krb5_store_keyblock(request, *key); 1054 if (ret) { 1055 krb5_storage_free(request); 1056 return ret; 1057 } 1058 1059 ret = kcm_call(context, k, request, NULL, NULL); 1060 1061 krb5_storage_free(request); 1062 return ret; 1063 } 1064 1065 1066 /* 1067 * Request: 1068 * NameZ 1069 * KDCFlags 1070 * EncryptionType 1071 * ServerPrincipal 1072 * 1073 * Repsonse: 1074 * 1075 */ 1076 krb5_error_code 1077 _krb5_kcm_get_ticket(krb5_context context, 1078 krb5_ccache id, 1079 krb5_kdc_flags flags, 1080 krb5_enctype enctype, 1081 krb5_principal server) 1082 { 1083 krb5_error_code ret; 1084 krb5_kcmcache *k = KCMCACHE(id); 1085 krb5_storage *request; 1086 1087 ret = kcm_storage_request(context, KCM_OP_GET_TICKET, &request); 1088 if (ret) 1089 return ret; 1090 1091 ret = krb5_store_stringz(request, k->name); 1092 if (ret) { 1093 krb5_storage_free(request); 1094 return ret; 1095 } 1096 1097 ret = krb5_store_int32(request, flags.i); 1098 if (ret) { 1099 krb5_storage_free(request); 1100 return ret; 1101 } 1102 1103 ret = krb5_store_int32(request, enctype); 1104 if (ret) { 1105 krb5_storage_free(request); 1106 return ret; 1107 } 1108 1109 ret = krb5_store_principal(request, server); 1110 if (ret) { 1111 krb5_storage_free(request); 1112 return ret; 1113 } 1114 1115 ret = kcm_call(context, k, request, NULL, NULL); 1116 1117 krb5_storage_free(request); 1118 return ret; 1119 } 1120 1121 1122 #endif /* HAVE_KCM */ 1123