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
try_door(krb5_context context,const krb5_kcmcache * k,krb5_data * request_data,krb5_data * response_data)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
try_unix_socket(krb5_context context,const krb5_kcmcache * k,krb5_data * request_data,krb5_data * response_data)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
kcm_send_request(krb5_context context,krb5_kcmcache * k,krb5_storage * request,krb5_data * response_data)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
kcm_storage_request(krb5_context context,kcm_operation opcode,krb5_storage ** storage_p)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
kcm_alloc(krb5_context context,const char * name,krb5_ccache * id)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
kcm_call(krb5_context context,krb5_kcmcache * k,krb5_storage * request,krb5_storage ** response_p,krb5_data * response_data_p)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
kcm_free(krb5_context context,krb5_ccache * id)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 *
kcm_get_name(krb5_context context,krb5_ccache id)311 kcm_get_name(krb5_context context,
312 krb5_ccache id)
313 {
314 return CACHENAME(id);
315 }
316
317 static krb5_error_code
kcm_resolve(krb5_context context,krb5_ccache * id,const char * res)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
kcm_gen_new(krb5_context context,krb5_ccache * id)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
kcm_initialize(krb5_context context,krb5_ccache id,krb5_principal primary_principal)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
kcm_close(krb5_context context,krb5_ccache id)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
kcm_destroy(krb5_context context,krb5_ccache id)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
kcm_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)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
kcm_retrieve(krb5_context context,krb5_ccache id,krb5_flags which,const krb5_creds * mcred,krb5_creds * creds)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
kcm_get_principal(krb5_context context,krb5_ccache id,krb5_principal * principal)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
kcm_get_first(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)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
kcm_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)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
kcm_end_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)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
kcm_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * cred)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
kcm_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)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
kcm_get_version(krb5_context context,krb5_ccache id)826 kcm_get_version(krb5_context context,
827 krb5_ccache id)
828 {
829 return 0;
830 }
831
832 static krb5_error_code
kcm_move(krb5_context context,krb5_ccache from,krb5_ccache to)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
kcm_default_name(krb5_context context,char ** str)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
_krb5_kcm_is_running(krb5_context context)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
_krb5_kcm_noop(krb5_context context,krb5_ccache id)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
_krb5_kcm_chmod(krb5_context context,krb5_ccache id,uint16_t mode)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
_krb5_kcm_chown(krb5_context context,krb5_ccache id,uint32_t uid,uint32_t gid)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
_krb5_kcm_get_initial_ticket(krb5_context context,krb5_ccache id,krb5_principal server,krb5_keyblock * key)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
_krb5_kcm_get_ticket(krb5_context context,krb5_ccache id,krb5_kdc_flags flags,krb5_enctype enctype,krb5_principal server)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