etc/services - sync with NetBSD-8
[minix.git] / crypto / external / bsd / heimdal / dist / lib / krb5 / kcm.c
blob4f3740a26347111bae82d096aa274517c3090d84
1 /* $NetBSD: kcm.c,v 1.1.1.2 2014/04/24 12:45:50 pettai Exp $ */
3 /*
4 * Copyright (c) 2005, PADL Software Pty Ltd.
5 * All rights reserved.
7 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of PADL Software nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
37 #include "krb5_locl.h"
39 #ifdef HAVE_KCM
41 * Client library for Kerberos Credentials Manager (KCM) daemon
44 #include <krb5/kcm.h>
45 #include <heim-ipc.h>
47 static krb5_error_code
48 kcm_set_kdc_offset(krb5_context, krb5_ccache, krb5_deltat);
50 static const char *kcm_ipc_name = "ANY:org.h5l.kcm";
52 typedef struct krb5_kcmcache {
53 char *name;
54 } krb5_kcmcache;
56 typedef struct krb5_kcm_cursor {
57 unsigned long offset;
58 unsigned long length;
59 kcmuuid_t *uuids;
60 } *krb5_kcm_cursor;
63 #define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data)
64 #define CACHENAME(X) (KCMCACHE(X)->name)
65 #define KCMCURSOR(C) ((krb5_kcm_cursor)(C))
67 static HEIMDAL_MUTEX kcm_mutex = HEIMDAL_MUTEX_INITIALIZER;
68 static heim_ipc kcm_ipc = NULL;
70 static krb5_error_code
71 kcm_send_request(krb5_context context,
72 krb5_storage *request,
73 krb5_data *response_data)
75 krb5_error_code ret = 0;
76 krb5_data request_data;
78 HEIMDAL_MUTEX_lock(&kcm_mutex);
79 if (kcm_ipc == NULL)
80 ret = heim_ipc_init_context(kcm_ipc_name, &kcm_ipc);
81 HEIMDAL_MUTEX_unlock(&kcm_mutex);
82 if (ret)
83 return KRB5_CC_NOSUPP;
85 ret = krb5_storage_to_data(request, &request_data);
86 if (ret) {
87 krb5_clear_error_message(context);
88 return KRB5_CC_NOMEM;
91 ret = heim_ipc_call(kcm_ipc, &request_data, response_data, NULL);
92 krb5_data_free(&request_data);
94 if (ret) {
95 krb5_clear_error_message(context);
96 ret = KRB5_CC_NOSUPP;
99 return ret;
102 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
103 krb5_kcm_storage_request(krb5_context context,
104 uint16_t opcode,
105 krb5_storage **storage_p)
107 krb5_storage *sp;
108 krb5_error_code ret;
110 *storage_p = NULL;
112 sp = krb5_storage_emem();
113 if (sp == NULL) {
114 krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", ""));
115 return KRB5_CC_NOMEM;
118 /* Send MAJOR | VERSION | OPCODE */
119 ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR);
120 if (ret)
121 goto fail;
122 ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR);
123 if (ret)
124 goto fail;
125 ret = krb5_store_int16(sp, opcode);
126 if (ret)
127 goto fail;
129 *storage_p = sp;
130 fail:
131 if (ret) {
132 krb5_set_error_message(context, ret,
133 N_("Failed to encode KCM request", ""));
134 krb5_storage_free(sp);
137 return ret;
140 static krb5_error_code
141 kcm_alloc(krb5_context context, const char *name, 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(k, 0, sizeof(*k));
230 krb5_data_free(&(*id)->data);
234 static const char *
235 kcm_get_name(krb5_context context,
236 krb5_ccache id)
238 return CACHENAME(id);
241 static krb5_error_code
242 kcm_resolve(krb5_context context, krb5_ccache *id, const char *res)
244 return kcm_alloc(context, res, id);
248 * Request:
250 * Response:
251 * NameZ
253 static krb5_error_code
254 kcm_gen_new(krb5_context context, krb5_ccache *id)
256 krb5_kcmcache *k;
257 krb5_error_code ret;
258 krb5_storage *request, *response;
259 krb5_data response_data;
261 ret = kcm_alloc(context, NULL, id);
262 if (ret)
263 return ret;
265 k = KCMCACHE(*id);
267 ret = krb5_kcm_storage_request(context, KCM_OP_GEN_NEW, &request);
268 if (ret) {
269 kcm_free(context, id);
270 return ret;
273 ret = krb5_kcm_call(context, request, &response, &response_data);
274 if (ret) {
275 krb5_storage_free(request);
276 kcm_free(context, id);
277 return ret;
280 ret = krb5_ret_stringz(response, &k->name);
281 if (ret)
282 ret = KRB5_CC_IO;
284 krb5_storage_free(request);
285 krb5_storage_free(response);
286 krb5_data_free(&response_data);
288 if (ret)
289 kcm_free(context, id);
291 return ret;
295 * Request:
296 * NameZ
297 * Principal
299 * Response:
302 static krb5_error_code
303 kcm_initialize(krb5_context context,
304 krb5_ccache id,
305 krb5_principal primary_principal)
307 krb5_error_code ret;
308 krb5_kcmcache *k = KCMCACHE(id);
309 krb5_storage *request;
311 ret = krb5_kcm_storage_request(context, KCM_OP_INITIALIZE, &request);
312 if (ret)
313 return ret;
315 ret = krb5_store_stringz(request, k->name);
316 if (ret) {
317 krb5_storage_free(request);
318 return ret;
321 ret = krb5_store_principal(request, primary_principal);
322 if (ret) {
323 krb5_storage_free(request);
324 return ret;
327 ret = krb5_kcm_call(context, request, NULL, NULL);
329 krb5_storage_free(request);
331 if (context->kdc_sec_offset)
332 kcm_set_kdc_offset(context, id, context->kdc_sec_offset);
334 return ret;
337 static krb5_error_code
338 kcm_close(krb5_context context,
339 krb5_ccache id)
341 kcm_free(context, &id);
342 return 0;
346 * Request:
347 * NameZ
349 * Response:
352 static krb5_error_code
353 kcm_destroy(krb5_context context,
354 krb5_ccache id)
356 krb5_error_code ret;
357 krb5_kcmcache *k = KCMCACHE(id);
358 krb5_storage *request;
360 ret = krb5_kcm_storage_request(context, KCM_OP_DESTROY, &request);
361 if (ret)
362 return ret;
364 ret = krb5_store_stringz(request, k->name);
365 if (ret) {
366 krb5_storage_free(request);
367 return ret;
370 ret = krb5_kcm_call(context, request, NULL, NULL);
372 krb5_storage_free(request);
373 return ret;
377 * Request:
378 * NameZ
379 * Creds
381 * Response:
384 static krb5_error_code
385 kcm_store_cred(krb5_context context,
386 krb5_ccache id,
387 krb5_creds *creds)
389 krb5_error_code ret;
390 krb5_kcmcache *k = KCMCACHE(id);
391 krb5_storage *request;
393 ret = krb5_kcm_storage_request(context, KCM_OP_STORE, &request);
394 if (ret)
395 return ret;
397 ret = krb5_store_stringz(request, k->name);
398 if (ret) {
399 krb5_storage_free(request);
400 return ret;
403 ret = krb5_store_creds(request, creds);
404 if (ret) {
405 krb5_storage_free(request);
406 return ret;
409 ret = krb5_kcm_call(context, request, NULL, NULL);
411 krb5_storage_free(request);
412 return ret;
415 #if 0
417 * Request:
418 * NameZ
419 * WhichFields
420 * MatchCreds
422 * Response:
423 * Creds
426 static krb5_error_code
427 kcm_retrieve(krb5_context context,
428 krb5_ccache id,
429 krb5_flags which,
430 const krb5_creds *mcred,
431 krb5_creds *creds)
433 krb5_error_code ret;
434 krb5_kcmcache *k = KCMCACHE(id);
435 krb5_storage *request, *response;
436 krb5_data response_data;
438 ret = krb5_kcm_storage_request(context, KCM_OP_RETRIEVE, &request);
439 if (ret)
440 return ret;
442 ret = krb5_store_stringz(request, k->name);
443 if (ret) {
444 krb5_storage_free(request);
445 return ret;
448 ret = krb5_store_int32(request, which);
449 if (ret) {
450 krb5_storage_free(request);
451 return ret;
454 ret = krb5_store_creds_tag(request, rk_UNCONST(mcred));
455 if (ret) {
456 krb5_storage_free(request);
457 return ret;
460 ret = krb5_kcm_call(context, request, &response, &response_data);
461 if (ret) {
462 krb5_storage_free(request);
463 return ret;
466 ret = krb5_ret_creds(response, creds);
467 if (ret)
468 ret = KRB5_CC_IO;
470 krb5_storage_free(request);
471 krb5_storage_free(response);
472 krb5_data_free(&response_data);
474 return ret;
476 #endif
479 * Request:
480 * NameZ
482 * Response:
483 * Principal
485 static krb5_error_code
486 kcm_get_principal(krb5_context context,
487 krb5_ccache id,
488 krb5_principal *principal)
490 krb5_error_code ret;
491 krb5_kcmcache *k = KCMCACHE(id);
492 krb5_storage *request, *response;
493 krb5_data response_data;
495 ret = krb5_kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request);
496 if (ret)
497 return ret;
499 ret = krb5_store_stringz(request, k->name);
500 if (ret) {
501 krb5_storage_free(request);
502 return ret;
505 ret = krb5_kcm_call(context, request, &response, &response_data);
506 if (ret) {
507 krb5_storage_free(request);
508 return ret;
511 ret = krb5_ret_principal(response, principal);
512 if (ret)
513 ret = KRB5_CC_IO;
515 krb5_storage_free(request);
516 krb5_storage_free(response);
517 krb5_data_free(&response_data);
519 return ret;
523 * Request:
524 * NameZ
526 * Response:
527 * Cursor
530 static krb5_error_code
531 kcm_get_first (krb5_context context,
532 krb5_ccache id,
533 krb5_cc_cursor *cursor)
535 krb5_error_code ret;
536 krb5_kcm_cursor c;
537 krb5_kcmcache *k = KCMCACHE(id);
538 krb5_storage *request, *response;
539 krb5_data response_data;
541 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_UUID_LIST, &request);
542 if (ret)
543 return ret;
545 ret = krb5_store_stringz(request, k->name);
546 if (ret) {
547 krb5_storage_free(request);
548 return ret;
551 ret = krb5_kcm_call(context, request, &response, &response_data);
552 krb5_storage_free(request);
553 if (ret)
554 return ret;
556 c = calloc(1, sizeof(*c));
557 if (c == NULL) {
558 ret = ENOMEM;
559 krb5_set_error_message(context, ret,
560 N_("malloc: out of memory", ""));
561 return ret;
564 while (1) {
565 ssize_t sret;
566 kcmuuid_t uuid;
567 void *ptr;
569 sret = krb5_storage_read(response, &uuid, sizeof(uuid));
570 if (sret == 0) {
571 ret = 0;
572 break;
573 } else if (sret != sizeof(uuid)) {
574 ret = EINVAL;
575 break;
578 ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
579 if (ptr == NULL) {
580 free(c->uuids);
581 free(c);
582 krb5_set_error_message(context, ENOMEM,
583 N_("malloc: out of memory", ""));
584 return ENOMEM;
586 c->uuids = ptr;
588 memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
589 c->length += 1;
592 krb5_storage_free(response);
593 krb5_data_free(&response_data);
595 if (ret) {
596 free(c->uuids);
597 free(c);
598 return ret;
601 *cursor = c;
603 return 0;
607 * Request:
608 * NameZ
609 * Cursor
611 * Response:
612 * Creds
614 static krb5_error_code
615 kcm_get_next (krb5_context context,
616 krb5_ccache id,
617 krb5_cc_cursor *cursor,
618 krb5_creds *creds)
620 krb5_error_code ret;
621 krb5_kcmcache *k = KCMCACHE(id);
622 krb5_kcm_cursor c = KCMCURSOR(*cursor);
623 krb5_storage *request, *response;
624 krb5_data response_data;
625 ssize_t sret;
627 again:
629 if (c->offset >= c->length)
630 return KRB5_CC_END;
632 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_BY_UUID, &request);
633 if (ret)
634 return ret;
636 ret = krb5_store_stringz(request, k->name);
637 if (ret) {
638 krb5_storage_free(request);
639 return ret;
642 sret = krb5_storage_write(request,
643 &c->uuids[c->offset],
644 sizeof(c->uuids[c->offset]));
645 c->offset++;
646 if (sret != sizeof(c->uuids[c->offset])) {
647 krb5_storage_free(request);
648 krb5_clear_error_message(context);
649 return ENOMEM;
652 ret = krb5_kcm_call(context, request, &response, &response_data);
653 krb5_storage_free(request);
654 if (ret == KRB5_CC_END) {
655 goto again;
658 ret = krb5_ret_creds(response, creds);
659 if (ret)
660 ret = KRB5_CC_IO;
662 krb5_storage_free(response);
663 krb5_data_free(&response_data);
665 return ret;
669 * Request:
670 * NameZ
671 * Cursor
673 * Response:
676 static krb5_error_code
677 kcm_end_get (krb5_context context,
678 krb5_ccache id,
679 krb5_cc_cursor *cursor)
681 krb5_kcm_cursor c = KCMCURSOR(*cursor);
683 free(c->uuids);
684 free(c);
686 *cursor = NULL;
688 return 0;
692 * Request:
693 * NameZ
694 * WhichFields
695 * MatchCreds
697 * Response:
700 static krb5_error_code
701 kcm_remove_cred(krb5_context context,
702 krb5_ccache id,
703 krb5_flags which,
704 krb5_creds *cred)
706 krb5_error_code ret;
707 krb5_kcmcache *k = KCMCACHE(id);
708 krb5_storage *request;
710 ret = krb5_kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request);
711 if (ret)
712 return ret;
714 ret = krb5_store_stringz(request, k->name);
715 if (ret) {
716 krb5_storage_free(request);
717 return ret;
720 ret = krb5_store_int32(request, which);
721 if (ret) {
722 krb5_storage_free(request);
723 return ret;
726 ret = krb5_store_creds_tag(request, cred);
727 if (ret) {
728 krb5_storage_free(request);
729 return ret;
732 ret = krb5_kcm_call(context, request, NULL, NULL);
734 krb5_storage_free(request);
735 return ret;
738 static krb5_error_code
739 kcm_set_flags(krb5_context context,
740 krb5_ccache id,
741 krb5_flags flags)
743 krb5_error_code ret;
744 krb5_kcmcache *k = KCMCACHE(id);
745 krb5_storage *request;
747 ret = krb5_kcm_storage_request(context, KCM_OP_SET_FLAGS, &request);
748 if (ret)
749 return ret;
751 ret = krb5_store_stringz(request, k->name);
752 if (ret) {
753 krb5_storage_free(request);
754 return ret;
757 ret = krb5_store_int32(request, flags);
758 if (ret) {
759 krb5_storage_free(request);
760 return ret;
763 ret = krb5_kcm_call(context, request, NULL, NULL);
765 krb5_storage_free(request);
766 return ret;
769 static int
770 kcm_get_version(krb5_context context,
771 krb5_ccache id)
773 return 0;
777 * Send nothing
778 * get back list of uuids
781 static krb5_error_code
782 kcm_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
784 krb5_error_code ret;
785 krb5_kcm_cursor c;
786 krb5_storage *request, *response;
787 krb5_data response_data;
789 *cursor = NULL;
791 c = calloc(1, sizeof(*c));
792 if (c == NULL) {
793 ret = ENOMEM;
794 krb5_set_error_message(context, ret,
795 N_("malloc: out of memory", ""));
796 goto out;
799 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_UUID_LIST, &request);
800 if (ret)
801 goto out;
803 ret = krb5_kcm_call(context, request, &response, &response_data);
804 krb5_storage_free(request);
805 if (ret)
806 goto out;
808 while (1) {
809 ssize_t sret;
810 kcmuuid_t uuid;
811 void *ptr;
813 sret = krb5_storage_read(response, &uuid, sizeof(uuid));
814 if (sret == 0) {
815 ret = 0;
816 break;
817 } else if (sret != sizeof(uuid)) {
818 ret = EINVAL;
819 goto out;
822 ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
823 if (ptr == NULL) {
824 ret = ENOMEM;
825 krb5_set_error_message(context, ret,
826 N_("malloc: out of memory", ""));
827 goto out;
829 c->uuids = ptr;
831 memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
832 c->length += 1;
835 krb5_storage_free(response);
836 krb5_data_free(&response_data);
838 out:
839 if (ret && c) {
840 free(c->uuids);
841 free(c);
842 } else
843 *cursor = c;
845 return ret;
849 * Send uuid
850 * Recv cache name
853 static krb5_error_code
854 kcm_get_cache_next(krb5_context context, krb5_cc_cursor cursor, const krb5_cc_ops *ops, krb5_ccache *id)
856 krb5_error_code ret;
857 krb5_kcm_cursor c = KCMCURSOR(cursor);
858 krb5_storage *request, *response;
859 krb5_data response_data;
860 ssize_t sret;
861 char *name;
863 *id = NULL;
865 again:
867 if (c->offset >= c->length)
868 return KRB5_CC_END;
870 ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_BY_UUID, &request);
871 if (ret)
872 return ret;
874 sret = krb5_storage_write(request,
875 &c->uuids[c->offset],
876 sizeof(c->uuids[c->offset]));
877 c->offset++;
878 if (sret != sizeof(c->uuids[c->offset])) {
879 krb5_storage_free(request);
880 krb5_clear_error_message(context);
881 return ENOMEM;
884 ret = krb5_kcm_call(context, request, &response, &response_data);
885 krb5_storage_free(request);
886 if (ret == KRB5_CC_END)
887 goto again;
889 ret = krb5_ret_stringz(response, &name);
890 krb5_storage_free(response);
891 krb5_data_free(&response_data);
893 if (ret == 0) {
894 ret = _krb5_cc_allocate(context, ops, id);
895 if (ret == 0)
896 ret = kcm_alloc(context, name, id);
897 krb5_xfree(name);
900 return ret;
903 static krb5_error_code
904 kcm_get_cache_next_kcm(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
906 #ifndef KCM_IS_API_CACHE
907 return kcm_get_cache_next(context, cursor, &krb5_kcm_ops, id);
908 #else
909 return KRB5_CC_END;
910 #endif
913 static krb5_error_code
914 kcm_get_cache_next_api(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
916 return kcm_get_cache_next(context, cursor, &krb5_akcm_ops, id);
920 static krb5_error_code
921 kcm_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
923 krb5_kcm_cursor c = KCMCURSOR(cursor);
925 free(c->uuids);
926 free(c);
927 return 0;
931 static krb5_error_code
932 kcm_move(krb5_context context, krb5_ccache from, krb5_ccache to)
934 krb5_error_code ret;
935 krb5_kcmcache *oldk = KCMCACHE(from);
936 krb5_kcmcache *newk = KCMCACHE(to);
937 krb5_storage *request;
939 ret = krb5_kcm_storage_request(context, KCM_OP_MOVE_CACHE, &request);
940 if (ret)
941 return ret;
943 ret = krb5_store_stringz(request, oldk->name);
944 if (ret) {
945 krb5_storage_free(request);
946 return ret;
949 ret = krb5_store_stringz(request, newk->name);
950 if (ret) {
951 krb5_storage_free(request);
952 return ret;
954 ret = krb5_kcm_call(context, request, NULL, NULL);
956 krb5_storage_free(request);
957 return ret;
960 static krb5_error_code
961 kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops,
962 const char *defstr, char **str)
964 krb5_error_code ret;
965 krb5_storage *request, *response;
966 krb5_data response_data;
967 char *name;
969 *str = NULL;
971 ret = krb5_kcm_storage_request(context, KCM_OP_GET_DEFAULT_CACHE, &request);
972 if (ret)
973 return ret;
975 ret = krb5_kcm_call(context, request, &response, &response_data);
976 krb5_storage_free(request);
977 if (ret)
978 return _krb5_expand_default_cc_name(context, defstr, str);
980 ret = krb5_ret_stringz(response, &name);
981 krb5_storage_free(response);
982 krb5_data_free(&response_data);
983 if (ret)
984 return ret;
986 asprintf(str, "%s:%s", ops->prefix, name);
987 free(name);
988 if (str == NULL)
989 return ENOMEM;
991 return 0;
994 static krb5_error_code
995 kcm_get_default_name_api(krb5_context context, char **str)
997 return kcm_get_default_name(context, &krb5_akcm_ops,
998 KRB5_DEFAULT_CCNAME_KCM_API, str);
1001 static krb5_error_code
1002 kcm_get_default_name_kcm(krb5_context context, char **str)
1004 return kcm_get_default_name(context, &krb5_kcm_ops,
1005 KRB5_DEFAULT_CCNAME_KCM_KCM, str);
1008 static krb5_error_code
1009 kcm_set_default(krb5_context context, krb5_ccache id)
1011 krb5_error_code ret;
1012 krb5_storage *request;
1013 krb5_kcmcache *k = KCMCACHE(id);
1015 ret = krb5_kcm_storage_request(context, KCM_OP_SET_DEFAULT_CACHE, &request);
1016 if (ret)
1017 return ret;
1019 ret = krb5_store_stringz(request, k->name);
1020 if (ret) {
1021 krb5_storage_free(request);
1022 return ret;
1025 ret = krb5_kcm_call(context, request, NULL, NULL);
1026 krb5_storage_free(request);
1028 return ret;
1031 static krb5_error_code
1032 kcm_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
1034 *mtime = time(NULL);
1035 return 0;
1038 static krb5_error_code
1039 kcm_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
1041 krb5_kcmcache *k = KCMCACHE(id);
1042 krb5_error_code ret;
1043 krb5_storage *request;
1045 ret = krb5_kcm_storage_request(context, KCM_OP_SET_KDC_OFFSET, &request);
1046 if (ret)
1047 return ret;
1049 ret = krb5_store_stringz(request, k->name);
1050 if (ret) {
1051 krb5_storage_free(request);
1052 return ret;
1054 ret = krb5_store_int32(request, kdc_offset);
1055 if (ret) {
1056 krb5_storage_free(request);
1057 return ret;
1060 ret = krb5_kcm_call(context, request, NULL, NULL);
1061 krb5_storage_free(request);
1063 return ret;
1066 static krb5_error_code
1067 kcm_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
1069 krb5_kcmcache *k = KCMCACHE(id);
1070 krb5_error_code ret;
1071 krb5_storage *request, *response;
1072 krb5_data response_data;
1073 int32_t offset;
1075 ret = krb5_kcm_storage_request(context, KCM_OP_GET_KDC_OFFSET, &request);
1076 if (ret)
1077 return ret;
1079 ret = krb5_store_stringz(request, k->name);
1080 if (ret) {
1081 krb5_storage_free(request);
1082 return ret;
1085 ret = krb5_kcm_call(context, request, &response, &response_data);
1086 krb5_storage_free(request);
1087 if (ret)
1088 return ret;
1090 ret = krb5_ret_int32(response, &offset);
1091 krb5_storage_free(response);
1092 krb5_data_free(&response_data);
1093 if (ret)
1094 return ret;
1096 *kdc_offset = offset;
1098 return 0;
1102 * Variable containing the KCM based credential cache implemention.
1104 * @ingroup krb5_ccache
1107 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = {
1108 KRB5_CC_OPS_VERSION,
1109 "KCM",
1110 kcm_get_name,
1111 kcm_resolve,
1112 kcm_gen_new,
1113 kcm_initialize,
1114 kcm_destroy,
1115 kcm_close,
1116 kcm_store_cred,
1117 NULL /* kcm_retrieve */,
1118 kcm_get_principal,
1119 kcm_get_first,
1120 kcm_get_next,
1121 kcm_end_get,
1122 kcm_remove_cred,
1123 kcm_set_flags,
1124 kcm_get_version,
1125 kcm_get_cache_first,
1126 kcm_get_cache_next_kcm,
1127 kcm_end_cache_get,
1128 kcm_move,
1129 kcm_get_default_name_kcm,
1130 kcm_set_default,
1131 kcm_lastchange,
1132 kcm_set_kdc_offset,
1133 kcm_get_kdc_offset
1136 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = {
1137 KRB5_CC_OPS_VERSION,
1138 "API",
1139 kcm_get_name,
1140 kcm_resolve,
1141 kcm_gen_new,
1142 kcm_initialize,
1143 kcm_destroy,
1144 kcm_close,
1145 kcm_store_cred,
1146 NULL /* kcm_retrieve */,
1147 kcm_get_principal,
1148 kcm_get_first,
1149 kcm_get_next,
1150 kcm_end_get,
1151 kcm_remove_cred,
1152 kcm_set_flags,
1153 kcm_get_version,
1154 kcm_get_cache_first,
1155 kcm_get_cache_next_api,
1156 kcm_end_cache_get,
1157 kcm_move,
1158 kcm_get_default_name_api,
1159 kcm_set_default,
1160 kcm_lastchange,
1161 NULL,
1162 NULL
1166 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1167 _krb5_kcm_is_running(krb5_context context)
1169 krb5_error_code ret;
1170 krb5_ccache_data ccdata;
1171 krb5_ccache id = &ccdata;
1172 krb5_boolean running;
1174 ret = kcm_alloc(context, NULL, &id);
1175 if (ret)
1176 return 0;
1178 running = (_krb5_kcm_noop(context, id) == 0);
1180 kcm_free(context, &id);
1182 return running;
1186 * Request:
1188 * Response:
1191 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1192 _krb5_kcm_noop(krb5_context context,
1193 krb5_ccache id)
1195 krb5_error_code ret;
1196 krb5_storage *request;
1198 ret = krb5_kcm_storage_request(context, KCM_OP_NOOP, &request);
1199 if (ret)
1200 return ret;
1202 ret = krb5_kcm_call(context, request, NULL, NULL);
1204 krb5_storage_free(request);
1205 return ret;
1210 * Request:
1211 * NameZ
1212 * ServerPrincipalPresent
1213 * ServerPrincipal OPTIONAL
1214 * Key
1216 * Repsonse:
1219 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1220 _krb5_kcm_get_initial_ticket(krb5_context context,
1221 krb5_ccache id,
1222 krb5_principal server,
1223 krb5_keyblock *key)
1225 krb5_kcmcache *k = KCMCACHE(id);
1226 krb5_error_code ret;
1227 krb5_storage *request;
1229 ret = krb5_kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request);
1230 if (ret)
1231 return ret;
1233 ret = krb5_store_stringz(request, k->name);
1234 if (ret) {
1235 krb5_storage_free(request);
1236 return ret;
1239 ret = krb5_store_int8(request, (server == NULL) ? 0 : 1);
1240 if (ret) {
1241 krb5_storage_free(request);
1242 return ret;
1245 if (server != NULL) {
1246 ret = krb5_store_principal(request, server);
1247 if (ret) {
1248 krb5_storage_free(request);
1249 return ret;
1253 ret = krb5_store_keyblock(request, *key);
1254 if (ret) {
1255 krb5_storage_free(request);
1256 return ret;
1259 ret = krb5_kcm_call(context, request, NULL, NULL);
1261 krb5_storage_free(request);
1262 return ret;
1267 * Request:
1268 * NameZ
1269 * KDCFlags
1270 * EncryptionType
1271 * ServerPrincipal
1273 * Repsonse:
1276 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1277 _krb5_kcm_get_ticket(krb5_context context,
1278 krb5_ccache id,
1279 krb5_kdc_flags flags,
1280 krb5_enctype enctype,
1281 krb5_principal server)
1283 krb5_error_code ret;
1284 krb5_kcmcache *k = KCMCACHE(id);
1285 krb5_storage *request;
1287 ret = krb5_kcm_storage_request(context, KCM_OP_GET_TICKET, &request);
1288 if (ret)
1289 return ret;
1291 ret = krb5_store_stringz(request, k->name);
1292 if (ret) {
1293 krb5_storage_free(request);
1294 return ret;
1297 ret = krb5_store_int32(request, flags.i);
1298 if (ret) {
1299 krb5_storage_free(request);
1300 return ret;
1303 ret = krb5_store_int32(request, enctype);
1304 if (ret) {
1305 krb5_storage_free(request);
1306 return ret;
1309 ret = krb5_store_principal(request, server);
1310 if (ret) {
1311 krb5_storage_free(request);
1312 return ret;
1315 ret = krb5_kcm_call(context, request, NULL, NULL);
1317 krb5_storage_free(request);
1318 return ret;
1321 #endif /* HAVE_KCM */