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