s4:torture: Adapt KDC canon test to Heimdal upstream changes
[Samba.git] / source4 / heimdal / lib / krb5 / kcm.c
blob760abf5c59dd39f741b9bd6d1a2a4580fed9f782
1 /*
2 * Copyright (c) 2005, PADL Software Pty Ltd.
3 * All rights reserved.
5 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of PADL Software nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include "krb5_locl.h"
37 #ifdef HAVE_KCM
39 * Client library for Kerberos Credentials Manager (KCM) daemon
42 #include "kcm.h"
43 #include <heim-ipc.h>
45 static krb5_error_code
46 kcm_set_kdc_offset(krb5_context, krb5_ccache, krb5_deltat);
48 static const char *kcm_ipc_name = "ANY:org.h5l.kcm";
50 typedef struct krb5_kcmcache {
51 char *name;
52 } krb5_kcmcache;
54 typedef struct krb5_kcm_cursor {
55 unsigned long offset;
56 unsigned long length;
57 kcmuuid_t *uuids;
58 } *krb5_kcm_cursor;
61 #define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data)
62 #define CACHENAME(X) (KCMCACHE(X)->name)
63 #define KCMCURSOR(C) ((krb5_kcm_cursor)(C))
65 static HEIMDAL_MUTEX kcm_mutex = HEIMDAL_MUTEX_INITIALIZER;
66 static heim_ipc kcm_ipc = NULL;
68 static krb5_error_code
69 kcm_send_request(krb5_context context,
70 krb5_storage *request,
71 krb5_data *response_data)
73 krb5_error_code ret = 0;
74 krb5_data request_data;
76 HEIMDAL_MUTEX_lock(&kcm_mutex);
77 if (kcm_ipc == NULL)
78 ret = heim_ipc_init_context(kcm_ipc_name, &kcm_ipc);
79 HEIMDAL_MUTEX_unlock(&kcm_mutex);
80 if (ret)
81 return KRB5_CC_NOSUPP;
83 ret = krb5_storage_to_data(request, &request_data);
84 if (ret) {
85 krb5_clear_error_message(context);
86 return KRB5_CC_NOMEM;
89 ret = heim_ipc_call(kcm_ipc, &request_data, response_data, NULL);
90 krb5_data_free(&request_data);
92 if (ret) {
93 krb5_clear_error_message(context);
94 ret = KRB5_CC_NOSUPP;
97 return ret;
100 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
101 krb5_kcm_storage_request(krb5_context context,
102 uint16_t opcode,
103 krb5_storage **storage_p)
105 krb5_storage *sp;
106 krb5_error_code ret;
108 *storage_p = NULL;
110 sp = krb5_storage_emem();
111 if (sp == NULL) {
112 krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", ""));
113 return KRB5_CC_NOMEM;
116 /* Send MAJOR | VERSION | OPCODE */
117 ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR);
118 if (ret)
119 goto fail;
120 ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR);
121 if (ret)
122 goto fail;
123 ret = krb5_store_int16(sp, opcode);
124 if (ret)
125 goto fail;
127 *storage_p = sp;
128 fail:
129 if (ret) {
130 krb5_set_error_message(context, ret,
131 N_("Failed to encode KCM request", ""));
132 krb5_storage_free(sp);
135 return ret;
138 static krb5_error_code
139 kcm_alloc(krb5_context context,
140 const char *name,
141 krb5_ccache *id)
143 krb5_kcmcache *k;
145 k = malloc(sizeof(*k));
146 if (k == NULL) {
147 krb5_set_error_message(context, KRB5_CC_NOMEM,
148 N_("malloc: out of memory", ""));
149 return KRB5_CC_NOMEM;
152 if (name != NULL) {
153 k->name = strdup(name);
154 if (k->name == NULL) {
155 free(k);
156 krb5_set_error_message(context, KRB5_CC_NOMEM,
157 N_("malloc: out of memory", ""));
158 return KRB5_CC_NOMEM;
160 } else
161 k->name = NULL;
163 (*id)->data.data = k;
164 (*id)->data.length = sizeof(*k);
166 return 0;
169 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
170 krb5_kcm_call(krb5_context context,
171 krb5_storage *request,
172 krb5_storage **response_p,
173 krb5_data *response_data_p)
175 krb5_data response_data;
176 krb5_error_code ret;
177 int32_t status;
178 krb5_storage *response;
180 if (response_p != NULL)
181 *response_p = NULL;
183 krb5_data_zero(&response_data);
185 ret = kcm_send_request(context, request, &response_data);
186 if (ret)
187 return ret;
189 response = krb5_storage_from_data(&response_data);
190 if (response == NULL) {
191 krb5_data_free(&response_data);
192 return KRB5_CC_IO;
195 ret = krb5_ret_int32(response, &status);
196 if (ret) {
197 krb5_storage_free(response);
198 krb5_data_free(&response_data);
199 return KRB5_CC_FORMAT;
202 if (status) {
203 krb5_storage_free(response);
204 krb5_data_free(&response_data);
205 return status;
208 if (response_p != NULL) {
209 *response_data_p = response_data;
210 *response_p = response;
212 return 0;
215 krb5_storage_free(response);
216 krb5_data_free(&response_data);
218 return 0;
221 static void
222 kcm_free(krb5_context context, krb5_ccache *id)
224 krb5_kcmcache *k = KCMCACHE(*id);
226 if (k != NULL) {
227 if (k->name != NULL)
228 free(k->name);
229 memset_s(k, sizeof(*k), 0, sizeof(*k));
230 krb5_data_free(&(*id)->data);
234 static krb5_error_code KRB5_CALLCONV
235 kcm_get_name_2(krb5_context context,
236 krb5_ccache id,
237 const char **name,
238 const char **col,
239 const char **sub)
242 * TODO:
244 * - name should be <IPC-name>:<cache-name>
245 * - col should be <IPC-name>
246 * - sub should be <cache-name>
248 if (name)
249 *name = CACHENAME(id);
250 if (col)
251 *col = NULL;
252 if (sub)
253 *sub = CACHENAME(id);
254 return 0;
257 static krb5_error_code
258 kcm_resolve_2(krb5_context context,
259 krb5_ccache *id,
260 const char *res,
261 const char *sub)
264 * For now, for KCM the `res' is the `sub'.
266 * TODO: We should use `res' as the IPC name instead of the one currently
267 * hard-coded in `kcm_ipc_name'.
269 return kcm_alloc(context, sub && *sub ? sub : res, id);
273 * Request:
275 * Response:
276 * NameZ
278 static krb5_error_code
279 kcm_gen_new(krb5_context context, krb5_ccache *id)
281 krb5_kcmcache *k;
282 krb5_error_code ret;
283 krb5_storage *request, *response;
284 krb5_data response_data;
286 ret = kcm_alloc(context, NULL, id);
287 if (ret)
288 return ret;
290 k = KCMCACHE(*id);
292 ret = krb5_kcm_storage_request(context, KCM_OP_GEN_NEW, &request);
293 if (ret) {
294 kcm_free(context, id);
295 return ret;
298 ret = krb5_kcm_call(context, request, &response, &response_data);
299 if (ret) {
300 krb5_storage_free(request);
301 kcm_free(context, id);
302 return ret;
305 ret = krb5_ret_stringz(response, &k->name);
306 if (ret)
307 ret = KRB5_CC_IO;
309 krb5_storage_free(request);
310 krb5_storage_free(response);
311 krb5_data_free(&response_data);
313 if (ret)
314 kcm_free(context, id);
316 return ret;
320 * Request:
321 * NameZ
322 * Principal
324 * Response:
327 static krb5_error_code
328 kcm_initialize(krb5_context context,
329 krb5_ccache id,
330 krb5_principal primary_principal)
332 krb5_error_code ret;
333 krb5_kcmcache *k = KCMCACHE(id);
334 krb5_storage *request;
336 ret = krb5_kcm_storage_request(context, KCM_OP_INITIALIZE, &request);
337 if (ret)
338 return ret;
340 ret = krb5_store_stringz(request, k->name);
341 if (ret) {
342 krb5_storage_free(request);
343 return ret;
346 ret = krb5_store_principal(request, primary_principal);
347 if (ret) {
348 krb5_storage_free(request);
349 return ret;
352 ret = krb5_kcm_call(context, request, NULL, NULL);
354 krb5_storage_free(request);
356 if (context->kdc_sec_offset)
357 kcm_set_kdc_offset(context, id, context->kdc_sec_offset);
359 return ret;
362 static krb5_error_code
363 kcm_close(krb5_context context,
364 krb5_ccache id)
366 kcm_free(context, &id);
367 return 0;
371 * Request:
372 * NameZ
374 * Response:
377 static krb5_error_code
378 kcm_destroy(krb5_context context,
379 krb5_ccache id)
381 krb5_error_code ret;
382 krb5_kcmcache *k = KCMCACHE(id);
383 krb5_storage *request;
385 ret = krb5_kcm_storage_request(context, KCM_OP_DESTROY, &request);
386 if (ret)
387 return ret;
389 ret = krb5_store_stringz(request, k->name);
390 if (ret) {
391 krb5_storage_free(request);
392 return ret;
395 ret = krb5_kcm_call(context, request, NULL, NULL);
397 krb5_storage_free(request);
398 return ret;
402 * Request:
403 * NameZ
404 * Creds
406 * Response:
409 static krb5_error_code
410 kcm_store_cred(krb5_context context,
411 krb5_ccache id,
412 krb5_creds *creds)
414 krb5_error_code ret;
415 krb5_kcmcache *k = KCMCACHE(id);
416 krb5_storage *request;
418 ret = krb5_kcm_storage_request(context, KCM_OP_STORE, &request);
419 if (ret)
420 return ret;
422 ret = krb5_store_stringz(request, k->name);
423 if (ret) {
424 krb5_storage_free(request);
425 return ret;
428 ret = krb5_store_creds(request, creds);
429 if (ret) {
430 krb5_storage_free(request);
431 return ret;
434 ret = krb5_kcm_call(context, request, NULL, NULL);
436 krb5_storage_free(request);
437 return ret;
440 #if 0
442 * Request:
443 * NameZ
444 * WhichFields
445 * MatchCreds
447 * Response:
448 * Creds
451 static krb5_error_code
452 kcm_retrieve(krb5_context context,
453 krb5_ccache id,
454 krb5_flags which,
455 const krb5_creds *mcred,
456 krb5_creds *creds)
458 krb5_error_code ret;
459 krb5_kcmcache *k = KCMCACHE(id);
460 krb5_storage *request, *response;
461 krb5_data response_data;
463 ret = krb5_kcm_storage_request(context, KCM_OP_RETRIEVE, &request);
464 if (ret)
465 return ret;
467 ret = krb5_store_stringz(request, k->name);
468 if (ret) {
469 krb5_storage_free(request);
470 return ret;
473 ret = krb5_store_int32(request, which);
474 if (ret) {
475 krb5_storage_free(request);
476 return ret;
479 ret = krb5_store_creds_tag(request, rk_UNCONST(mcred));
480 if (ret) {
481 krb5_storage_free(request);
482 return ret;
485 ret = krb5_kcm_call(context, request, &response, &response_data);
486 if (ret) {
487 krb5_storage_free(request);
488 return ret;
491 ret = krb5_ret_creds(response, creds);
492 if (ret)
493 ret = KRB5_CC_IO;
495 krb5_storage_free(request);
496 krb5_storage_free(response);
497 krb5_data_free(&response_data);
499 return ret;
501 #endif
504 * Request:
505 * NameZ
507 * Response:
508 * Principal
510 static krb5_error_code
511 kcm_get_principal(krb5_context context,
512 krb5_ccache id,
513 krb5_principal *principal)
515 krb5_error_code ret;
516 krb5_kcmcache *k = KCMCACHE(id);
517 krb5_storage *request, *response;
518 krb5_data response_data;
520 ret = krb5_kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request);
521 if (ret)
522 return ret;
524 ret = krb5_store_stringz(request, k->name);
525 if (ret) {
526 krb5_storage_free(request);
527 return ret;
530 ret = krb5_kcm_call(context, request, &response, &response_data);
531 if (ret) {
532 krb5_storage_free(request);
533 return ret;
536 ret = krb5_ret_principal(response, principal);
537 if (ret)
538 ret = KRB5_CC_IO;
540 krb5_storage_free(request);
541 krb5_storage_free(response);
542 krb5_data_free(&response_data);
544 return ret;
548 * Request:
549 * NameZ
551 * Response:
552 * Cursor
555 static krb5_error_code
556 kcm_get_first (krb5_context context,
557 krb5_ccache id,
558 krb5_cc_cursor *cursor)
560 krb5_error_code ret;
561 krb5_kcm_cursor c;
562 krb5_kcmcache *k = KCMCACHE(id);
563 krb5_storage *request, *response;
564 krb5_data response_data;
566 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_UUID_LIST, &request);
567 if (ret)
568 return ret;
570 ret = krb5_store_stringz(request, k->name);
571 if (ret) {
572 krb5_storage_free(request);
573 return ret;
576 ret = krb5_kcm_call(context, request, &response, &response_data);
577 krb5_storage_free(request);
578 if (ret)
579 return ret;
581 c = calloc(1, sizeof(*c));
582 if (c == NULL) {
583 ret = krb5_enomem(context);
584 return ret;
587 while (1) {
588 ssize_t sret;
589 kcmuuid_t uuid;
590 void *ptr;
592 sret = krb5_storage_read(response, &uuid, sizeof(uuid));
593 if (sret == 0) {
594 ret = 0;
595 break;
596 } else if (sret != sizeof(uuid)) {
597 ret = EINVAL;
598 break;
601 ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
602 if (ptr == NULL) {
603 free(c->uuids);
604 free(c);
605 return krb5_enomem(context);
607 c->uuids = ptr;
609 memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
610 c->length += 1;
613 krb5_storage_free(response);
614 krb5_data_free(&response_data);
616 if (ret) {
617 free(c->uuids);
618 free(c);
619 return ret;
622 *cursor = c;
624 return 0;
628 * Request:
629 * NameZ
630 * Cursor
632 * Response:
633 * Creds
635 static krb5_error_code
636 kcm_get_next (krb5_context context,
637 krb5_ccache id,
638 krb5_cc_cursor *cursor,
639 krb5_creds *creds)
641 krb5_error_code ret;
642 krb5_kcmcache *k = KCMCACHE(id);
643 krb5_kcm_cursor c = KCMCURSOR(*cursor);
644 krb5_storage *request, *response;
645 krb5_data response_data;
646 ssize_t sret;
648 again:
650 if (c->offset >= c->length)
651 return KRB5_CC_END;
653 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_BY_UUID, &request);
654 if (ret)
655 return ret;
657 ret = krb5_store_stringz(request, k->name);
658 if (ret) {
659 krb5_storage_free(request);
660 return ret;
663 sret = krb5_storage_write(request,
664 &c->uuids[c->offset],
665 sizeof(c->uuids[c->offset]));
666 c->offset++;
667 if (sret != sizeof(c->uuids[c->offset])) {
668 krb5_storage_free(request);
669 krb5_clear_error_message(context);
670 return ENOMEM;
673 ret = krb5_kcm_call(context, request, &response, &response_data);
674 krb5_storage_free(request);
675 if (ret == KRB5_CC_END) {
676 goto again;
677 } else if (ret)
678 return ret;
680 ret = krb5_ret_creds(response, creds);
681 if (ret)
682 ret = KRB5_CC_IO;
684 krb5_storage_free(response);
685 krb5_data_free(&response_data);
687 return ret;
691 * Request:
692 * NameZ
693 * Cursor
695 * Response:
698 static krb5_error_code
699 kcm_end_get (krb5_context context,
700 krb5_ccache id,
701 krb5_cc_cursor *cursor)
703 krb5_kcm_cursor c = KCMCURSOR(*cursor);
705 free(c->uuids);
706 free(c);
708 *cursor = NULL;
710 return 0;
714 * Request:
715 * NameZ
716 * WhichFields
717 * MatchCreds
719 * Response:
722 static krb5_error_code
723 kcm_remove_cred(krb5_context context,
724 krb5_ccache id,
725 krb5_flags which,
726 krb5_creds *cred)
728 krb5_error_code ret;
729 krb5_kcmcache *k = KCMCACHE(id);
730 krb5_storage *request;
732 ret = krb5_kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request);
733 if (ret)
734 return ret;
736 ret = krb5_store_stringz(request, k->name);
737 if (ret) {
738 krb5_storage_free(request);
739 return ret;
742 ret = krb5_store_int32(request, which);
743 if (ret) {
744 krb5_storage_free(request);
745 return ret;
748 ret = krb5_store_creds_tag(request, cred);
749 if (ret) {
750 krb5_storage_free(request);
751 return ret;
754 ret = krb5_kcm_call(context, request, NULL, NULL);
756 krb5_storage_free(request);
757 return ret;
760 static krb5_error_code
761 kcm_set_flags(krb5_context context,
762 krb5_ccache id,
763 krb5_flags flags)
765 krb5_error_code ret;
766 krb5_kcmcache *k = KCMCACHE(id);
767 krb5_storage *request;
769 ret = krb5_kcm_storage_request(context, KCM_OP_SET_FLAGS, &request);
770 if (ret)
771 return ret;
773 ret = krb5_store_stringz(request, k->name);
774 if (ret) {
775 krb5_storage_free(request);
776 return ret;
779 ret = krb5_store_int32(request, flags);
780 if (ret) {
781 krb5_storage_free(request);
782 return ret;
785 ret = krb5_kcm_call(context, request, NULL, NULL);
787 krb5_storage_free(request);
788 return ret;
791 static int
792 kcm_get_version(krb5_context context,
793 krb5_ccache id)
795 return 0;
799 * Send nothing
800 * get back list of uuids
803 static krb5_error_code
804 kcm_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
806 krb5_error_code ret;
807 krb5_kcm_cursor c;
808 krb5_storage *request, *response;
809 krb5_data response_data;
811 *cursor = NULL;
813 c = calloc(1, sizeof(*c));
814 if (c == NULL) {
815 ret = krb5_enomem(context);
816 goto out;
819 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_UUID_LIST, &request);
820 if (ret)
821 goto out;
823 ret = krb5_kcm_call(context, request, &response, &response_data);
824 krb5_storage_free(request);
825 if (ret)
826 goto out;
828 while (1) {
829 ssize_t sret;
830 kcmuuid_t uuid;
831 void *ptr;
833 sret = krb5_storage_read(response, &uuid, sizeof(uuid));
834 if (sret == 0) {
835 ret = 0;
836 break;
837 } else if (sret != sizeof(uuid)) {
838 ret = EINVAL;
839 goto out;
842 ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
843 if (ptr == NULL) {
844 ret = krb5_enomem(context);
845 goto out;
847 c->uuids = ptr;
849 memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
850 c->length += 1;
853 krb5_storage_free(response);
854 krb5_data_free(&response_data);
856 out:
857 if (ret && c) {
858 free(c->uuids);
859 free(c);
860 } else
861 *cursor = c;
863 return ret;
867 * Send uuid
868 * Recv cache name
871 static krb5_error_code
872 kcm_get_cache_next(krb5_context context, krb5_cc_cursor cursor, const krb5_cc_ops *ops, krb5_ccache *id)
874 krb5_error_code ret;
875 krb5_kcm_cursor c = KCMCURSOR(cursor);
876 krb5_storage *request, *response;
877 krb5_data response_data;
878 ssize_t sret;
879 char *name;
881 *id = NULL;
883 again:
885 if (c->offset >= c->length)
886 return KRB5_CC_END;
888 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_BY_UUID, &request);
889 if (ret)
890 return ret;
892 sret = krb5_storage_write(request,
893 &c->uuids[c->offset],
894 sizeof(c->uuids[c->offset]));
895 c->offset++;
896 if (sret != sizeof(c->uuids[c->offset])) {
897 krb5_storage_free(request);
898 krb5_clear_error_message(context);
899 return ENOMEM;
902 ret = krb5_kcm_call(context, request, &response, &response_data);
903 krb5_storage_free(request);
904 if (ret == KRB5_CC_END)
905 goto again;
906 else if (ret)
907 return ret;
909 ret = krb5_ret_stringz(response, &name);
910 krb5_storage_free(response);
911 krb5_data_free(&response_data);
913 if (ret == 0) {
914 ret = _krb5_cc_allocate(context, ops, id);
915 if (ret == 0)
916 ret = kcm_alloc(context, name, id);
917 krb5_xfree(name);
920 return ret;
923 static krb5_error_code
924 kcm_get_cache_next_kcm(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
926 #ifndef KCM_IS_API_CACHE
927 return kcm_get_cache_next(context, cursor, &krb5_kcm_ops, id);
928 #else
929 return KRB5_CC_END;
930 #endif
933 static krb5_error_code
934 kcm_get_cache_next_api(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
936 return kcm_get_cache_next(context, cursor, &krb5_akcm_ops, id);
940 static krb5_error_code
941 kcm_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
943 krb5_kcm_cursor c = KCMCURSOR(cursor);
945 free(c->uuids);
946 free(c);
947 return 0;
951 static krb5_error_code
952 kcm_move(krb5_context context, krb5_ccache from, krb5_ccache to)
954 krb5_error_code ret;
955 krb5_kcmcache *oldk = KCMCACHE(from);
956 krb5_kcmcache *newk = KCMCACHE(to);
957 krb5_storage *request;
959 ret = krb5_kcm_storage_request(context, KCM_OP_MOVE_CACHE, &request);
960 if (ret)
961 return ret;
963 ret = krb5_store_stringz(request, oldk->name);
964 if (ret) {
965 krb5_storage_free(request);
966 return ret;
969 ret = krb5_store_stringz(request, newk->name);
970 if (ret) {
971 krb5_storage_free(request);
972 return ret;
974 ret = krb5_kcm_call(context, request, NULL, NULL);
976 krb5_storage_free(request);
978 if (ret == 0)
979 krb5_cc_destroy(context, from);
980 return ret;
983 static krb5_error_code
984 kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops,
985 const char *defstr, char **str)
987 krb5_error_code ret;
988 krb5_storage *request, *response;
989 krb5_data response_data;
990 char *name;
991 int aret;
993 *str = NULL;
995 ret = krb5_kcm_storage_request(context, KCM_OP_GET_DEFAULT_CACHE, &request);
996 if (ret)
997 return ret;
999 ret = krb5_kcm_call(context, request, &response, &response_data);
1000 krb5_storage_free(request);
1001 if (ret)
1002 return _krb5_expand_default_cc_name(context, defstr, str);
1004 ret = krb5_ret_stringz(response, &name);
1005 krb5_storage_free(response);
1006 krb5_data_free(&response_data);
1007 if (ret)
1008 return ret;
1010 aret = asprintf(str, "%s:%s", ops->prefix, name);
1011 free(name);
1012 if (aret == -1 || str == NULL)
1013 return ENOMEM;
1015 return 0;
1018 static krb5_error_code
1019 kcm_get_default_name_api(krb5_context context, char **str)
1021 return kcm_get_default_name(context, &krb5_akcm_ops,
1022 KRB5_DEFAULT_CCNAME_KCM_API, str);
1025 static krb5_error_code
1026 kcm_get_default_name_kcm(krb5_context context, char **str)
1028 return kcm_get_default_name(context, &krb5_kcm_ops,
1029 KRB5_DEFAULT_CCNAME_KCM_KCM, str);
1032 static krb5_error_code
1033 kcm_set_default(krb5_context context, krb5_ccache id)
1035 krb5_error_code ret;
1036 krb5_storage *request;
1037 krb5_kcmcache *k = KCMCACHE(id);
1039 ret = krb5_kcm_storage_request(context, KCM_OP_SET_DEFAULT_CACHE, &request);
1040 if (ret)
1041 return ret;
1043 ret = krb5_store_stringz(request, k->name);
1044 if (ret) {
1045 krb5_storage_free(request);
1046 return ret;
1049 ret = krb5_kcm_call(context, request, NULL, NULL);
1050 krb5_storage_free(request);
1052 return ret;
1055 static krb5_error_code
1056 kcm_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
1058 *mtime = time(NULL);
1059 return 0;
1062 static krb5_error_code
1063 kcm_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
1065 krb5_kcmcache *k = KCMCACHE(id);
1066 krb5_error_code ret;
1067 krb5_storage *request;
1069 ret = krb5_kcm_storage_request(context, KCM_OP_SET_KDC_OFFSET, &request);
1070 if (ret)
1071 return ret;
1073 ret = krb5_store_stringz(request, k->name);
1074 if (ret) {
1075 krb5_storage_free(request);
1076 return ret;
1078 ret = krb5_store_int32(request, kdc_offset);
1079 if (ret) {
1080 krb5_storage_free(request);
1081 return ret;
1084 ret = krb5_kcm_call(context, request, NULL, NULL);
1085 krb5_storage_free(request);
1087 return ret;
1090 static krb5_error_code
1091 kcm_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
1093 krb5_kcmcache *k = KCMCACHE(id);
1094 krb5_error_code ret;
1095 krb5_storage *request, *response;
1096 krb5_data response_data;
1097 int32_t offset;
1099 ret = krb5_kcm_storage_request(context, KCM_OP_GET_KDC_OFFSET, &request);
1100 if (ret)
1101 return ret;
1103 ret = krb5_store_stringz(request, k->name);
1104 if (ret) {
1105 krb5_storage_free(request);
1106 return ret;
1109 ret = krb5_kcm_call(context, request, &response, &response_data);
1110 krb5_storage_free(request);
1111 if (ret)
1112 return ret;
1114 ret = krb5_ret_int32(response, &offset);
1115 krb5_storage_free(response);
1116 krb5_data_free(&response_data);
1117 if (ret)
1118 return ret;
1120 *kdc_offset = offset;
1122 return 0;
1126 * Variable containing the KCM based credential cache implemention.
1128 * @ingroup krb5_ccache
1131 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = {
1132 KRB5_CC_OPS_VERSION_5,
1133 "KCM",
1134 NULL,
1135 NULL,
1136 kcm_gen_new,
1137 kcm_initialize,
1138 kcm_destroy,
1139 kcm_close,
1140 kcm_store_cred,
1141 NULL /* kcm_retrieve */,
1142 kcm_get_principal,
1143 kcm_get_first,
1144 kcm_get_next,
1145 kcm_end_get,
1146 kcm_remove_cred,
1147 kcm_set_flags,
1148 kcm_get_version,
1149 kcm_get_cache_first,
1150 kcm_get_cache_next_kcm,
1151 kcm_end_cache_get,
1152 kcm_move,
1153 kcm_get_default_name_kcm,
1154 kcm_set_default,
1155 kcm_lastchange,
1156 kcm_set_kdc_offset,
1157 kcm_get_kdc_offset,
1158 kcm_get_name_2,
1159 kcm_resolve_2
1162 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = {
1163 KRB5_CC_OPS_VERSION_5,
1164 "API",
1165 NULL,
1166 NULL,
1167 kcm_gen_new,
1168 kcm_initialize,
1169 kcm_destroy,
1170 kcm_close,
1171 kcm_store_cred,
1172 NULL /* kcm_retrieve */,
1173 kcm_get_principal,
1174 kcm_get_first,
1175 kcm_get_next,
1176 kcm_end_get,
1177 kcm_remove_cred,
1178 kcm_set_flags,
1179 kcm_get_version,
1180 kcm_get_cache_first,
1181 kcm_get_cache_next_api,
1182 kcm_end_cache_get,
1183 kcm_move,
1184 kcm_get_default_name_api,
1185 kcm_set_default,
1186 kcm_lastchange,
1187 NULL,
1188 NULL,
1189 kcm_get_name_2,
1190 kcm_resolve_2
1194 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1195 _krb5_kcm_is_running(krb5_context context)
1197 krb5_error_code ret;
1198 krb5_ccache_data ccdata;
1199 krb5_ccache id = &ccdata;
1200 krb5_boolean running;
1202 ret = kcm_alloc(context, NULL, &id);
1203 if (ret)
1204 return 0;
1206 running = (_krb5_kcm_noop(context, id) == 0);
1208 kcm_free(context, &id);
1210 return running;
1214 * Request:
1216 * Response:
1219 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1220 _krb5_kcm_noop(krb5_context context,
1221 krb5_ccache id)
1223 krb5_error_code ret;
1224 krb5_storage *request;
1226 ret = krb5_kcm_storage_request(context, KCM_OP_NOOP, &request);
1227 if (ret)
1228 return ret;
1230 ret = krb5_kcm_call(context, request, NULL, NULL);
1232 krb5_storage_free(request);
1233 return ret;
1238 * Request:
1239 * NameZ
1240 * ServerPrincipalPresent
1241 * ServerPrincipal OPTIONAL
1242 * Key
1244 * Repsonse:
1247 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1248 _krb5_kcm_get_initial_ticket(krb5_context context,
1249 krb5_ccache id,
1250 krb5_principal server,
1251 krb5_keyblock *key)
1253 krb5_kcmcache *k = KCMCACHE(id);
1254 krb5_error_code ret;
1255 krb5_storage *request;
1257 ret = krb5_kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request);
1258 if (ret)
1259 return ret;
1261 ret = krb5_store_stringz(request, k->name);
1262 if (ret) {
1263 krb5_storage_free(request);
1264 return ret;
1267 ret = krb5_store_int8(request, (server == NULL) ? 0 : 1);
1268 if (ret) {
1269 krb5_storage_free(request);
1270 return ret;
1273 if (server != NULL) {
1274 ret = krb5_store_principal(request, server);
1275 if (ret) {
1276 krb5_storage_free(request);
1277 return ret;
1281 ret = krb5_store_keyblock(request, *key);
1282 if (ret) {
1283 krb5_storage_free(request);
1284 return ret;
1287 ret = krb5_kcm_call(context, request, NULL, NULL);
1289 krb5_storage_free(request);
1290 return ret;
1295 * Request:
1296 * NameZ
1297 * KDCFlags
1298 * EncryptionType
1299 * ServerPrincipal
1301 * Repsonse:
1304 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1305 _krb5_kcm_get_ticket(krb5_context context,
1306 krb5_ccache id,
1307 krb5_kdc_flags flags,
1308 krb5_enctype enctype,
1309 krb5_principal server)
1311 krb5_error_code ret;
1312 krb5_kcmcache *k = KCMCACHE(id);
1313 krb5_storage *request;
1315 ret = krb5_kcm_storage_request(context, KCM_OP_GET_TICKET, &request);
1316 if (ret)
1317 return ret;
1319 ret = krb5_store_stringz(request, k->name);
1320 if (ret) {
1321 krb5_storage_free(request);
1322 return ret;
1325 ret = krb5_store_int32(request, flags.i);
1326 if (ret) {
1327 krb5_storage_free(request);
1328 return ret;
1331 ret = krb5_store_int32(request, enctype);
1332 if (ret) {
1333 krb5_storage_free(request);
1334 return ret;
1337 ret = krb5_store_principal(request, server);
1338 if (ret) {
1339 krb5_storage_free(request);
1340 return ret;
1343 ret = krb5_kcm_call(context, request, NULL, NULL);
1345 krb5_storage_free(request);
1346 return ret;
1349 #endif /* HAVE_KCM */