1*25a02804Schristos /*	$NetBSD: kcm.c,v 1.3 2019/12/15 22:50:50 christos Exp $	*/
2f59d82ffSelric 
3f59d82ffSelric /*
4f59d82ffSelric  * Copyright (c) 2005, PADL Software Pty Ltd.
5f59d82ffSelric  * All rights reserved.
6f59d82ffSelric  *
7f59d82ffSelric  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8f59d82ffSelric  *
9f59d82ffSelric  * Redistribution and use in source and binary forms, with or without
10f59d82ffSelric  * modification, are permitted provided that the following conditions
11f59d82ffSelric  * are met:
12f59d82ffSelric  *
13f59d82ffSelric  * 1. Redistributions of source code must retain the above copyright
14f59d82ffSelric  *    notice, this list of conditions and the following disclaimer.
15f59d82ffSelric  *
16f59d82ffSelric  * 2. Redistributions in binary form must reproduce the above copyright
17f59d82ffSelric  *    notice, this list of conditions and the following disclaimer in the
18f59d82ffSelric  *    documentation and/or other materials provided with the distribution.
19f59d82ffSelric  *
20f59d82ffSelric  * 3. Neither the name of PADL Software nor the names of its contributors
21f59d82ffSelric  *    may be used to endorse or promote products derived from this software
22f59d82ffSelric  *    without specific prior written permission.
23f59d82ffSelric  *
24f59d82ffSelric  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
25f59d82ffSelric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26f59d82ffSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27f59d82ffSelric  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
28f59d82ffSelric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29f59d82ffSelric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30f59d82ffSelric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31f59d82ffSelric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32f59d82ffSelric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33f59d82ffSelric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34f59d82ffSelric  * SUCH DAMAGE.
35f59d82ffSelric  */
36f59d82ffSelric 
37f59d82ffSelric #include "krb5_locl.h"
38f59d82ffSelric 
39f59d82ffSelric #ifdef HAVE_KCM
40f59d82ffSelric /*
41f59d82ffSelric  * Client library for Kerberos Credentials Manager (KCM) daemon
42f59d82ffSelric  */
43f59d82ffSelric 
44f59d82ffSelric #include <krb5/kcm.h>
45f59d82ffSelric #include <heim-ipc.h>
46f59d82ffSelric 
47f59d82ffSelric static krb5_error_code
48f59d82ffSelric kcm_set_kdc_offset(krb5_context, krb5_ccache, krb5_deltat);
49f59d82ffSelric 
50f59d82ffSelric static const char *kcm_ipc_name = "ANY:org.h5l.kcm";
51f59d82ffSelric 
52f59d82ffSelric typedef struct krb5_kcmcache {
53f59d82ffSelric     char *name;
54f59d82ffSelric } krb5_kcmcache;
55f59d82ffSelric 
56f59d82ffSelric typedef struct krb5_kcm_cursor {
57f59d82ffSelric     unsigned long offset;
58f59d82ffSelric     unsigned long length;
59f59d82ffSelric     kcmuuid_t *uuids;
60f59d82ffSelric } *krb5_kcm_cursor;
61f59d82ffSelric 
62f59d82ffSelric 
63f59d82ffSelric #define KCMCACHE(X)	((krb5_kcmcache *)(X)->data.data)
64f59d82ffSelric #define CACHENAME(X)	(KCMCACHE(X)->name)
65f59d82ffSelric #define KCMCURSOR(C)	((krb5_kcm_cursor)(C))
66f59d82ffSelric 
67f59d82ffSelric static HEIMDAL_MUTEX kcm_mutex = HEIMDAL_MUTEX_INITIALIZER;
68f59d82ffSelric static heim_ipc kcm_ipc = NULL;
69f59d82ffSelric 
70f59d82ffSelric static krb5_error_code
kcm_send_request(krb5_context context,krb5_storage * request,krb5_data * response_data)71f59d82ffSelric kcm_send_request(krb5_context context,
72f59d82ffSelric 		 krb5_storage *request,
73f59d82ffSelric 		 krb5_data *response_data)
74f59d82ffSelric {
75f59d82ffSelric     krb5_error_code ret = 0;
76f59d82ffSelric     krb5_data request_data;
77f59d82ffSelric 
78f59d82ffSelric     HEIMDAL_MUTEX_lock(&kcm_mutex);
79f59d82ffSelric     if (kcm_ipc == NULL)
80f59d82ffSelric 	ret = heim_ipc_init_context(kcm_ipc_name, &kcm_ipc);
81f59d82ffSelric     HEIMDAL_MUTEX_unlock(&kcm_mutex);
82f59d82ffSelric     if (ret)
83f59d82ffSelric 	return KRB5_CC_NOSUPP;
84f59d82ffSelric 
85f59d82ffSelric     ret = krb5_storage_to_data(request, &request_data);
86f59d82ffSelric     if (ret) {
87f59d82ffSelric 	krb5_clear_error_message(context);
88f59d82ffSelric 	return KRB5_CC_NOMEM;
89f59d82ffSelric     }
90f59d82ffSelric 
91f59d82ffSelric     ret = heim_ipc_call(kcm_ipc, &request_data, response_data, NULL);
92f59d82ffSelric     krb5_data_free(&request_data);
93f59d82ffSelric 
94f59d82ffSelric     if (ret) {
95f59d82ffSelric 	krb5_clear_error_message(context);
96f59d82ffSelric 	ret = KRB5_CC_NOSUPP;
97f59d82ffSelric     }
98f59d82ffSelric 
99f59d82ffSelric     return ret;
100f59d82ffSelric }
101f59d82ffSelric 
102f59d82ffSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_kcm_storage_request(krb5_context context,uint16_t opcode,krb5_storage ** storage_p)103f59d82ffSelric krb5_kcm_storage_request(krb5_context context,
104f59d82ffSelric 			 uint16_t opcode,
105f59d82ffSelric 			 krb5_storage **storage_p)
106f59d82ffSelric {
107f59d82ffSelric     krb5_storage *sp;
108f59d82ffSelric     krb5_error_code ret;
109f59d82ffSelric 
110f59d82ffSelric     *storage_p = NULL;
111f59d82ffSelric 
112f59d82ffSelric     sp = krb5_storage_emem();
113f59d82ffSelric     if (sp == NULL) {
114f59d82ffSelric 	krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", ""));
115f59d82ffSelric 	return KRB5_CC_NOMEM;
116f59d82ffSelric     }
117f59d82ffSelric 
118f59d82ffSelric     /* Send MAJOR | VERSION | OPCODE */
119f59d82ffSelric     ret  = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR);
120f59d82ffSelric     if (ret)
121f59d82ffSelric 	goto fail;
122f59d82ffSelric     ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR);
123f59d82ffSelric     if (ret)
124f59d82ffSelric 	goto fail;
125f59d82ffSelric     ret = krb5_store_int16(sp, opcode);
126f59d82ffSelric     if (ret)
127f59d82ffSelric 	goto fail;
128f59d82ffSelric 
129f59d82ffSelric     *storage_p = sp;
130f59d82ffSelric  fail:
131f59d82ffSelric     if (ret) {
132f59d82ffSelric 	krb5_set_error_message(context, ret,
133f59d82ffSelric 			       N_("Failed to encode KCM request", ""));
134f59d82ffSelric 	krb5_storage_free(sp);
135f59d82ffSelric     }
136f59d82ffSelric 
137f59d82ffSelric     return ret;
138f59d82ffSelric }
139f59d82ffSelric 
140f59d82ffSelric static krb5_error_code
kcm_alloc(krb5_context context,const char * name,krb5_ccache * id)141f59d82ffSelric kcm_alloc(krb5_context context, const char *name, krb5_ccache *id)
142f59d82ffSelric {
143f59d82ffSelric     krb5_kcmcache *k;
144f59d82ffSelric 
145f59d82ffSelric     k = malloc(sizeof(*k));
146f59d82ffSelric     if (k == NULL) {
147f59d82ffSelric 	krb5_set_error_message(context, KRB5_CC_NOMEM,
148f59d82ffSelric 			       N_("malloc: out of memory", ""));
149f59d82ffSelric 	return KRB5_CC_NOMEM;
150f59d82ffSelric     }
151f59d82ffSelric 
152f59d82ffSelric     if (name != NULL) {
153f59d82ffSelric 	k->name = strdup(name);
154f59d82ffSelric 	if (k->name == NULL) {
155f59d82ffSelric 	    free(k);
156f59d82ffSelric 	    krb5_set_error_message(context, KRB5_CC_NOMEM,
157f59d82ffSelric 				   N_("malloc: out of memory", ""));
158f59d82ffSelric 	    return KRB5_CC_NOMEM;
159f59d82ffSelric 	}
160f59d82ffSelric     } else
161f59d82ffSelric 	k->name = NULL;
162f59d82ffSelric 
163f59d82ffSelric     (*id)->data.data = k;
164f59d82ffSelric     (*id)->data.length = sizeof(*k);
165f59d82ffSelric 
166f59d82ffSelric     return 0;
167f59d82ffSelric }
168f59d82ffSelric 
169f59d82ffSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_kcm_call(krb5_context context,krb5_storage * request,krb5_storage ** response_p,krb5_data * response_data_p)170f59d82ffSelric krb5_kcm_call(krb5_context context,
171f59d82ffSelric 	      krb5_storage *request,
172f59d82ffSelric 	      krb5_storage **response_p,
173f59d82ffSelric 	      krb5_data *response_data_p)
174f59d82ffSelric {
175f59d82ffSelric     krb5_data response_data;
176f59d82ffSelric     krb5_error_code ret;
177f59d82ffSelric     int32_t status;
178f59d82ffSelric     krb5_storage *response;
179f59d82ffSelric 
180f59d82ffSelric     if (response_p != NULL)
181f59d82ffSelric 	*response_p = NULL;
182f59d82ffSelric 
183f59d82ffSelric     krb5_data_zero(&response_data);
184f59d82ffSelric 
185f59d82ffSelric     ret = kcm_send_request(context, request, &response_data);
186f59d82ffSelric     if (ret)
187f59d82ffSelric 	return ret;
188f59d82ffSelric 
189f59d82ffSelric     response = krb5_storage_from_data(&response_data);
190f59d82ffSelric     if (response == NULL) {
191f59d82ffSelric 	krb5_data_free(&response_data);
192f59d82ffSelric 	return KRB5_CC_IO;
193f59d82ffSelric     }
194f59d82ffSelric 
195f59d82ffSelric     ret = krb5_ret_int32(response, &status);
196f59d82ffSelric     if (ret) {
197f59d82ffSelric 	krb5_storage_free(response);
198f59d82ffSelric 	krb5_data_free(&response_data);
199f59d82ffSelric 	return KRB5_CC_FORMAT;
200f59d82ffSelric     }
201f59d82ffSelric 
202f59d82ffSelric     if (status) {
203f59d82ffSelric 	krb5_storage_free(response);
204f59d82ffSelric 	krb5_data_free(&response_data);
205f59d82ffSelric 	return status;
206f59d82ffSelric     }
207f59d82ffSelric 
208f59d82ffSelric     if (response_p != NULL) {
209f59d82ffSelric 	*response_data_p = response_data;
210f59d82ffSelric 	*response_p = response;
211f59d82ffSelric 
212f59d82ffSelric 	return 0;
213f59d82ffSelric     }
214f59d82ffSelric 
215f59d82ffSelric     krb5_storage_free(response);
216f59d82ffSelric     krb5_data_free(&response_data);
217f59d82ffSelric 
218f59d82ffSelric     return 0;
219f59d82ffSelric }
220f59d82ffSelric 
221f59d82ffSelric static void
kcm_free(krb5_context context,krb5_ccache * id)222f59d82ffSelric kcm_free(krb5_context context, krb5_ccache *id)
223f59d82ffSelric {
224f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(*id);
225f59d82ffSelric 
226f59d82ffSelric     if (k != NULL) {
227f59d82ffSelric 	if (k->name != NULL)
228f59d82ffSelric 	    free(k->name);
229*25a02804Schristos 	memset_s(k, sizeof(*k), 0, sizeof(*k));
230f59d82ffSelric 	krb5_data_free(&(*id)->data);
231f59d82ffSelric     }
232f59d82ffSelric }
233f59d82ffSelric 
234f59d82ffSelric static const char *
kcm_get_name(krb5_context context,krb5_ccache id)235f59d82ffSelric kcm_get_name(krb5_context context,
236f59d82ffSelric 	     krb5_ccache id)
237f59d82ffSelric {
238f59d82ffSelric     return CACHENAME(id);
239f59d82ffSelric }
240f59d82ffSelric 
241f59d82ffSelric static krb5_error_code
kcm_resolve(krb5_context context,krb5_ccache * id,const char * res)242f59d82ffSelric kcm_resolve(krb5_context context, krb5_ccache *id, const char *res)
243f59d82ffSelric {
244f59d82ffSelric     return kcm_alloc(context, res, id);
245f59d82ffSelric }
246f59d82ffSelric 
247f59d82ffSelric /*
248f59d82ffSelric  * Request:
249f59d82ffSelric  *
250f59d82ffSelric  * Response:
251f59d82ffSelric  *      NameZ
252f59d82ffSelric  */
253f59d82ffSelric static krb5_error_code
kcm_gen_new(krb5_context context,krb5_ccache * id)254f59d82ffSelric kcm_gen_new(krb5_context context, krb5_ccache *id)
255f59d82ffSelric {
256f59d82ffSelric     krb5_kcmcache *k;
257f59d82ffSelric     krb5_error_code ret;
258f59d82ffSelric     krb5_storage *request, *response;
259f59d82ffSelric     krb5_data response_data;
260f59d82ffSelric 
261f59d82ffSelric     ret = kcm_alloc(context, NULL, id);
262f59d82ffSelric     if (ret)
263f59d82ffSelric 	return ret;
264f59d82ffSelric 
265f59d82ffSelric     k = KCMCACHE(*id);
266f59d82ffSelric 
267f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GEN_NEW, &request);
268f59d82ffSelric     if (ret) {
269f59d82ffSelric 	kcm_free(context, id);
270f59d82ffSelric 	return ret;
271f59d82ffSelric     }
272f59d82ffSelric 
273f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
274f59d82ffSelric     if (ret) {
275f59d82ffSelric 	krb5_storage_free(request);
276f59d82ffSelric 	kcm_free(context, id);
277f59d82ffSelric 	return ret;
278f59d82ffSelric     }
279f59d82ffSelric 
280f59d82ffSelric     ret = krb5_ret_stringz(response, &k->name);
281f59d82ffSelric     if (ret)
282f59d82ffSelric 	ret = KRB5_CC_IO;
283f59d82ffSelric 
284f59d82ffSelric     krb5_storage_free(request);
285f59d82ffSelric     krb5_storage_free(response);
286f59d82ffSelric     krb5_data_free(&response_data);
287f59d82ffSelric 
288f59d82ffSelric     if (ret)
289f59d82ffSelric 	kcm_free(context, id);
290f59d82ffSelric 
291f59d82ffSelric     return ret;
292f59d82ffSelric }
293f59d82ffSelric 
294f59d82ffSelric /*
295f59d82ffSelric  * Request:
296f59d82ffSelric  *      NameZ
297f59d82ffSelric  *      Principal
298f59d82ffSelric  *
299f59d82ffSelric  * Response:
300f59d82ffSelric  *
301f59d82ffSelric  */
302f59d82ffSelric static krb5_error_code
kcm_initialize(krb5_context context,krb5_ccache id,krb5_principal primary_principal)303f59d82ffSelric kcm_initialize(krb5_context context,
304f59d82ffSelric 	       krb5_ccache id,
305f59d82ffSelric 	       krb5_principal primary_principal)
306f59d82ffSelric {
307f59d82ffSelric     krb5_error_code ret;
308f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
309f59d82ffSelric     krb5_storage *request;
310f59d82ffSelric 
311f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_INITIALIZE, &request);
312f59d82ffSelric     if (ret)
313f59d82ffSelric 	return ret;
314f59d82ffSelric 
315f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
316f59d82ffSelric     if (ret) {
317f59d82ffSelric 	krb5_storage_free(request);
318f59d82ffSelric 	return ret;
319f59d82ffSelric     }
320f59d82ffSelric 
321f59d82ffSelric     ret = krb5_store_principal(request, primary_principal);
322f59d82ffSelric     if (ret) {
323f59d82ffSelric 	krb5_storage_free(request);
324f59d82ffSelric 	return ret;
325f59d82ffSelric     }
326f59d82ffSelric 
327f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
328f59d82ffSelric 
329f59d82ffSelric     krb5_storage_free(request);
330f59d82ffSelric 
331f59d82ffSelric     if (context->kdc_sec_offset)
332f59d82ffSelric 	kcm_set_kdc_offset(context, id, context->kdc_sec_offset);
333f59d82ffSelric 
334f59d82ffSelric     return ret;
335f59d82ffSelric }
336f59d82ffSelric 
337f59d82ffSelric static krb5_error_code
kcm_close(krb5_context context,krb5_ccache id)338f59d82ffSelric kcm_close(krb5_context context,
339f59d82ffSelric 	  krb5_ccache id)
340f59d82ffSelric {
341f59d82ffSelric     kcm_free(context, &id);
342f59d82ffSelric     return 0;
343f59d82ffSelric }
344f59d82ffSelric 
345f59d82ffSelric /*
346f59d82ffSelric  * Request:
347f59d82ffSelric  *      NameZ
348f59d82ffSelric  *
349f59d82ffSelric  * Response:
350f59d82ffSelric  *
351f59d82ffSelric  */
352f59d82ffSelric static krb5_error_code
kcm_destroy(krb5_context context,krb5_ccache id)353f59d82ffSelric kcm_destroy(krb5_context context,
354f59d82ffSelric 	    krb5_ccache id)
355f59d82ffSelric {
356f59d82ffSelric     krb5_error_code ret;
357f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
358f59d82ffSelric     krb5_storage *request;
359f59d82ffSelric 
360f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_DESTROY, &request);
361f59d82ffSelric     if (ret)
362f59d82ffSelric 	return ret;
363f59d82ffSelric 
364f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
365f59d82ffSelric     if (ret) {
366f59d82ffSelric 	krb5_storage_free(request);
367f59d82ffSelric 	return ret;
368f59d82ffSelric     }
369f59d82ffSelric 
370f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
371f59d82ffSelric 
372f59d82ffSelric     krb5_storage_free(request);
373f59d82ffSelric     return ret;
374f59d82ffSelric }
375f59d82ffSelric 
376f59d82ffSelric /*
377f59d82ffSelric  * Request:
378f59d82ffSelric  *      NameZ
379f59d82ffSelric  *      Creds
380f59d82ffSelric  *
381f59d82ffSelric  * Response:
382f59d82ffSelric  *
383f59d82ffSelric  */
384f59d82ffSelric static krb5_error_code
kcm_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)385f59d82ffSelric kcm_store_cred(krb5_context context,
386f59d82ffSelric 	       krb5_ccache id,
387f59d82ffSelric 	       krb5_creds *creds)
388f59d82ffSelric {
389f59d82ffSelric     krb5_error_code ret;
390f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
391f59d82ffSelric     krb5_storage *request;
392f59d82ffSelric 
393f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_STORE, &request);
394f59d82ffSelric     if (ret)
395f59d82ffSelric 	return ret;
396f59d82ffSelric 
397f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
398f59d82ffSelric     if (ret) {
399f59d82ffSelric 	krb5_storage_free(request);
400f59d82ffSelric 	return ret;
401f59d82ffSelric     }
402f59d82ffSelric 
403f59d82ffSelric     ret = krb5_store_creds(request, creds);
404f59d82ffSelric     if (ret) {
405f59d82ffSelric 	krb5_storage_free(request);
406f59d82ffSelric 	return ret;
407f59d82ffSelric     }
408f59d82ffSelric 
409f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
410f59d82ffSelric 
411f59d82ffSelric     krb5_storage_free(request);
412f59d82ffSelric     return ret;
413f59d82ffSelric }
414f59d82ffSelric 
415f59d82ffSelric #if 0
416f59d82ffSelric /*
417f59d82ffSelric  * Request:
418f59d82ffSelric  *      NameZ
419f59d82ffSelric  *      WhichFields
420f59d82ffSelric  *      MatchCreds
421f59d82ffSelric  *
422f59d82ffSelric  * Response:
423f59d82ffSelric  *      Creds
424f59d82ffSelric  *
425f59d82ffSelric  */
426f59d82ffSelric static krb5_error_code
427f59d82ffSelric kcm_retrieve(krb5_context context,
428f59d82ffSelric 	     krb5_ccache id,
429f59d82ffSelric 	     krb5_flags which,
430f59d82ffSelric 	     const krb5_creds *mcred,
431f59d82ffSelric 	     krb5_creds *creds)
432f59d82ffSelric {
433f59d82ffSelric     krb5_error_code ret;
434f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
435f59d82ffSelric     krb5_storage *request, *response;
436f59d82ffSelric     krb5_data response_data;
437f59d82ffSelric 
438f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_RETRIEVE, &request);
439f59d82ffSelric     if (ret)
440f59d82ffSelric 	return ret;
441f59d82ffSelric 
442f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
443f59d82ffSelric     if (ret) {
444f59d82ffSelric 	krb5_storage_free(request);
445f59d82ffSelric 	return ret;
446f59d82ffSelric     }
447f59d82ffSelric 
448f59d82ffSelric     ret = krb5_store_int32(request, which);
449f59d82ffSelric     if (ret) {
450f59d82ffSelric 	krb5_storage_free(request);
451f59d82ffSelric 	return ret;
452f59d82ffSelric     }
453f59d82ffSelric 
454f59d82ffSelric     ret = krb5_store_creds_tag(request, rk_UNCONST(mcred));
455f59d82ffSelric     if (ret) {
456f59d82ffSelric 	krb5_storage_free(request);
457f59d82ffSelric 	return ret;
458f59d82ffSelric     }
459f59d82ffSelric 
460f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
461f59d82ffSelric     if (ret) {
462f59d82ffSelric 	krb5_storage_free(request);
463f59d82ffSelric 	return ret;
464f59d82ffSelric     }
465f59d82ffSelric 
466f59d82ffSelric     ret = krb5_ret_creds(response, creds);
467f59d82ffSelric     if (ret)
468f59d82ffSelric 	ret = KRB5_CC_IO;
469f59d82ffSelric 
470f59d82ffSelric     krb5_storage_free(request);
471f59d82ffSelric     krb5_storage_free(response);
472f59d82ffSelric     krb5_data_free(&response_data);
473f59d82ffSelric 
474f59d82ffSelric     return ret;
475f59d82ffSelric }
476f59d82ffSelric #endif
477f59d82ffSelric 
478f59d82ffSelric /*
479f59d82ffSelric  * Request:
480f59d82ffSelric  *      NameZ
481f59d82ffSelric  *
482f59d82ffSelric  * Response:
483f59d82ffSelric  *      Principal
484f59d82ffSelric  */
485f59d82ffSelric static krb5_error_code
kcm_get_principal(krb5_context context,krb5_ccache id,krb5_principal * principal)486f59d82ffSelric kcm_get_principal(krb5_context context,
487f59d82ffSelric 		  krb5_ccache id,
488f59d82ffSelric 		  krb5_principal *principal)
489f59d82ffSelric {
490f59d82ffSelric     krb5_error_code ret;
491f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
492f59d82ffSelric     krb5_storage *request, *response;
493f59d82ffSelric     krb5_data response_data;
494f59d82ffSelric 
495f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request);
496f59d82ffSelric     if (ret)
497f59d82ffSelric 	return ret;
498f59d82ffSelric 
499f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
500f59d82ffSelric     if (ret) {
501f59d82ffSelric 	krb5_storage_free(request);
502f59d82ffSelric 	return ret;
503f59d82ffSelric     }
504f59d82ffSelric 
505f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
506f59d82ffSelric     if (ret) {
507f59d82ffSelric 	krb5_storage_free(request);
508f59d82ffSelric 	return ret;
509f59d82ffSelric     }
510f59d82ffSelric 
511f59d82ffSelric     ret = krb5_ret_principal(response, principal);
512f59d82ffSelric     if (ret)
513f59d82ffSelric 	ret = KRB5_CC_IO;
514f59d82ffSelric 
515f59d82ffSelric     krb5_storage_free(request);
516f59d82ffSelric     krb5_storage_free(response);
517f59d82ffSelric     krb5_data_free(&response_data);
518f59d82ffSelric 
519f59d82ffSelric     return ret;
520f59d82ffSelric }
521f59d82ffSelric 
522f59d82ffSelric /*
523f59d82ffSelric  * Request:
524f59d82ffSelric  *      NameZ
525f59d82ffSelric  *
526f59d82ffSelric  * Response:
527f59d82ffSelric  *      Cursor
528f59d82ffSelric  *
529f59d82ffSelric  */
530f59d82ffSelric static krb5_error_code
kcm_get_first(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)531f59d82ffSelric kcm_get_first (krb5_context context,
532f59d82ffSelric 	       krb5_ccache id,
533f59d82ffSelric 	       krb5_cc_cursor *cursor)
534f59d82ffSelric {
535f59d82ffSelric     krb5_error_code ret;
536f59d82ffSelric     krb5_kcm_cursor c;
537f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
538f59d82ffSelric     krb5_storage *request, *response;
539f59d82ffSelric     krb5_data response_data;
540f59d82ffSelric 
541f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_UUID_LIST, &request);
542f59d82ffSelric     if (ret)
543f59d82ffSelric 	return ret;
544f59d82ffSelric 
545f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
546f59d82ffSelric     if (ret) {
547f59d82ffSelric 	krb5_storage_free(request);
548f59d82ffSelric 	return ret;
549f59d82ffSelric     }
550f59d82ffSelric 
551f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
552f59d82ffSelric     krb5_storage_free(request);
553f59d82ffSelric     if (ret)
554f59d82ffSelric 	return ret;
555f59d82ffSelric 
556f59d82ffSelric     c = calloc(1, sizeof(*c));
557f59d82ffSelric     if (c == NULL) {
558e0895134Schristos 	ret = krb5_enomem(context);
559f59d82ffSelric 	return ret;
560f59d82ffSelric     }
561f59d82ffSelric 
562f59d82ffSelric     while (1) {
563f59d82ffSelric 	ssize_t sret;
564f59d82ffSelric 	kcmuuid_t uuid;
565f59d82ffSelric 	void *ptr;
566f59d82ffSelric 
567f59d82ffSelric 	sret = krb5_storage_read(response, &uuid, sizeof(uuid));
568f59d82ffSelric 	if (sret == 0) {
569f59d82ffSelric 	    ret = 0;
570f59d82ffSelric 	    break;
571f59d82ffSelric 	} else if (sret != sizeof(uuid)) {
572f59d82ffSelric 	    ret = EINVAL;
573f59d82ffSelric 	    break;
574f59d82ffSelric 	}
575f59d82ffSelric 
576f59d82ffSelric 	ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
577f59d82ffSelric 	if (ptr == NULL) {
578f59d82ffSelric 	    free(c->uuids);
579f59d82ffSelric 	    free(c);
580e0895134Schristos 	    return krb5_enomem(context);
581f59d82ffSelric 	}
582f59d82ffSelric 	c->uuids = ptr;
583f59d82ffSelric 
584f59d82ffSelric 	memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
585f59d82ffSelric 	c->length += 1;
586f59d82ffSelric     }
587f59d82ffSelric 
588f59d82ffSelric     krb5_storage_free(response);
589f59d82ffSelric     krb5_data_free(&response_data);
590f59d82ffSelric 
591f59d82ffSelric     if (ret) {
592f59d82ffSelric         free(c->uuids);
593f59d82ffSelric         free(c);
594f59d82ffSelric 	return ret;
595f59d82ffSelric     }
596f59d82ffSelric 
597f59d82ffSelric     *cursor = c;
598f59d82ffSelric 
599f59d82ffSelric     return 0;
600f59d82ffSelric }
601f59d82ffSelric 
602f59d82ffSelric /*
603f59d82ffSelric  * Request:
604f59d82ffSelric  *      NameZ
605f59d82ffSelric  *      Cursor
606f59d82ffSelric  *
607f59d82ffSelric  * Response:
608f59d82ffSelric  *      Creds
609f59d82ffSelric  */
610f59d82ffSelric static krb5_error_code
kcm_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)611f59d82ffSelric kcm_get_next (krb5_context context,
612f59d82ffSelric 		krb5_ccache id,
613f59d82ffSelric 		krb5_cc_cursor *cursor,
614f59d82ffSelric 		krb5_creds *creds)
615f59d82ffSelric {
616f59d82ffSelric     krb5_error_code ret;
617f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
618f59d82ffSelric     krb5_kcm_cursor c = KCMCURSOR(*cursor);
619f59d82ffSelric     krb5_storage *request, *response;
620f59d82ffSelric     krb5_data response_data;
621f59d82ffSelric     ssize_t sret;
622f59d82ffSelric 
623f59d82ffSelric  again:
624f59d82ffSelric 
625f59d82ffSelric     if (c->offset >= c->length)
626f59d82ffSelric 	return KRB5_CC_END;
627f59d82ffSelric 
628f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_BY_UUID, &request);
629f59d82ffSelric     if (ret)
630f59d82ffSelric 	return ret;
631f59d82ffSelric 
632f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
633f59d82ffSelric     if (ret) {
634f59d82ffSelric 	krb5_storage_free(request);
635f59d82ffSelric 	return ret;
636f59d82ffSelric     }
637f59d82ffSelric 
638f59d82ffSelric     sret = krb5_storage_write(request,
639f59d82ffSelric 			      &c->uuids[c->offset],
640f59d82ffSelric 			      sizeof(c->uuids[c->offset]));
641f59d82ffSelric     c->offset++;
642f59d82ffSelric     if (sret != sizeof(c->uuids[c->offset])) {
643f59d82ffSelric 	krb5_storage_free(request);
644f59d82ffSelric 	krb5_clear_error_message(context);
645f59d82ffSelric 	return ENOMEM;
646f59d82ffSelric     }
647f59d82ffSelric 
648f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
649f59d82ffSelric     krb5_storage_free(request);
650f59d82ffSelric     if (ret == KRB5_CC_END) {
651f59d82ffSelric 	goto again;
652f59d82ffSelric     }
653f59d82ffSelric 
654f59d82ffSelric     ret = krb5_ret_creds(response, creds);
655f59d82ffSelric     if (ret)
656f59d82ffSelric 	ret = KRB5_CC_IO;
657f59d82ffSelric 
658f59d82ffSelric     krb5_storage_free(response);
659f59d82ffSelric     krb5_data_free(&response_data);
660f59d82ffSelric 
661f59d82ffSelric     return ret;
662f59d82ffSelric }
663f59d82ffSelric 
664f59d82ffSelric /*
665f59d82ffSelric  * Request:
666f59d82ffSelric  *      NameZ
667f59d82ffSelric  *      Cursor
668f59d82ffSelric  *
669f59d82ffSelric  * Response:
670f59d82ffSelric  *
671f59d82ffSelric  */
672f59d82ffSelric static krb5_error_code
kcm_end_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)673f59d82ffSelric kcm_end_get (krb5_context context,
674f59d82ffSelric 	     krb5_ccache id,
675f59d82ffSelric 	     krb5_cc_cursor *cursor)
676f59d82ffSelric {
677f59d82ffSelric     krb5_kcm_cursor c = KCMCURSOR(*cursor);
678f59d82ffSelric 
679f59d82ffSelric     free(c->uuids);
680f59d82ffSelric     free(c);
681f59d82ffSelric 
682f59d82ffSelric     *cursor = NULL;
683f59d82ffSelric 
684f59d82ffSelric     return 0;
685f59d82ffSelric }
686f59d82ffSelric 
687f59d82ffSelric /*
688f59d82ffSelric  * Request:
689f59d82ffSelric  *      NameZ
690f59d82ffSelric  *      WhichFields
691f59d82ffSelric  *      MatchCreds
692f59d82ffSelric  *
693f59d82ffSelric  * Response:
694f59d82ffSelric  *
695f59d82ffSelric  */
696f59d82ffSelric static krb5_error_code
kcm_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * cred)697f59d82ffSelric kcm_remove_cred(krb5_context context,
698f59d82ffSelric 		krb5_ccache id,
699f59d82ffSelric 		krb5_flags which,
700f59d82ffSelric 		krb5_creds *cred)
701f59d82ffSelric {
702f59d82ffSelric     krb5_error_code ret;
703f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
704f59d82ffSelric     krb5_storage *request;
705f59d82ffSelric 
706f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request);
707f59d82ffSelric     if (ret)
708f59d82ffSelric 	return ret;
709f59d82ffSelric 
710f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
711f59d82ffSelric     if (ret) {
712f59d82ffSelric 	krb5_storage_free(request);
713f59d82ffSelric 	return ret;
714f59d82ffSelric     }
715f59d82ffSelric 
716f59d82ffSelric     ret = krb5_store_int32(request, which);
717f59d82ffSelric     if (ret) {
718f59d82ffSelric 	krb5_storage_free(request);
719f59d82ffSelric 	return ret;
720f59d82ffSelric     }
721f59d82ffSelric 
722f59d82ffSelric     ret = krb5_store_creds_tag(request, cred);
723f59d82ffSelric     if (ret) {
724f59d82ffSelric 	krb5_storage_free(request);
725f59d82ffSelric 	return ret;
726f59d82ffSelric     }
727f59d82ffSelric 
728f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
729f59d82ffSelric 
730f59d82ffSelric     krb5_storage_free(request);
731f59d82ffSelric     return ret;
732f59d82ffSelric }
733f59d82ffSelric 
734f59d82ffSelric static krb5_error_code
kcm_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)735f59d82ffSelric kcm_set_flags(krb5_context context,
736f59d82ffSelric 	      krb5_ccache id,
737f59d82ffSelric 	      krb5_flags flags)
738f59d82ffSelric {
739f59d82ffSelric     krb5_error_code ret;
740f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
741f59d82ffSelric     krb5_storage *request;
742f59d82ffSelric 
743f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_SET_FLAGS, &request);
744f59d82ffSelric     if (ret)
745f59d82ffSelric 	return ret;
746f59d82ffSelric 
747f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
748f59d82ffSelric     if (ret) {
749f59d82ffSelric 	krb5_storage_free(request);
750f59d82ffSelric 	return ret;
751f59d82ffSelric     }
752f59d82ffSelric 
753f59d82ffSelric     ret = krb5_store_int32(request, flags);
754f59d82ffSelric     if (ret) {
755f59d82ffSelric 	krb5_storage_free(request);
756f59d82ffSelric 	return ret;
757f59d82ffSelric     }
758f59d82ffSelric 
759f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
760f59d82ffSelric 
761f59d82ffSelric     krb5_storage_free(request);
762f59d82ffSelric     return ret;
763f59d82ffSelric }
764f59d82ffSelric 
765f59d82ffSelric static int
kcm_get_version(krb5_context context,krb5_ccache id)766f59d82ffSelric kcm_get_version(krb5_context context,
767f59d82ffSelric 		krb5_ccache id)
768f59d82ffSelric {
769f59d82ffSelric     return 0;
770f59d82ffSelric }
771f59d82ffSelric 
772f59d82ffSelric /*
773f59d82ffSelric  * Send nothing
774f59d82ffSelric  * get back list of uuids
775f59d82ffSelric  */
776f59d82ffSelric 
777f59d82ffSelric static krb5_error_code
kcm_get_cache_first(krb5_context context,krb5_cc_cursor * cursor)778f59d82ffSelric kcm_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
779f59d82ffSelric {
780f59d82ffSelric     krb5_error_code ret;
781f59d82ffSelric     krb5_kcm_cursor c;
782f59d82ffSelric     krb5_storage *request, *response;
783f59d82ffSelric     krb5_data response_data;
784f59d82ffSelric 
785f59d82ffSelric     *cursor = NULL;
786f59d82ffSelric 
787f59d82ffSelric     c = calloc(1, sizeof(*c));
788f59d82ffSelric     if (c == NULL) {
789e0895134Schristos 	ret = krb5_enomem(context);
790f59d82ffSelric 	goto out;
791f59d82ffSelric     }
792f59d82ffSelric 
793f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_UUID_LIST, &request);
794f59d82ffSelric     if (ret)
795f59d82ffSelric 	goto out;
796f59d82ffSelric 
797f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
798f59d82ffSelric     krb5_storage_free(request);
799f59d82ffSelric     if (ret)
800f59d82ffSelric 	goto out;
801f59d82ffSelric 
802f59d82ffSelric     while (1) {
803f59d82ffSelric 	ssize_t sret;
804f59d82ffSelric 	kcmuuid_t uuid;
805f59d82ffSelric 	void *ptr;
806f59d82ffSelric 
807f59d82ffSelric 	sret = krb5_storage_read(response, &uuid, sizeof(uuid));
808f59d82ffSelric 	if (sret == 0) {
809f59d82ffSelric 	    ret = 0;
810f59d82ffSelric 	    break;
811f59d82ffSelric 	} else if (sret != sizeof(uuid)) {
812f59d82ffSelric 	    ret = EINVAL;
813f59d82ffSelric 	    goto out;
814f59d82ffSelric 	}
815f59d82ffSelric 
816f59d82ffSelric 	ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
817f59d82ffSelric 	if (ptr == NULL) {
818e0895134Schristos 	    ret = krb5_enomem(context);
819f59d82ffSelric 	    goto out;
820f59d82ffSelric 	}
821f59d82ffSelric 	c->uuids = ptr;
822f59d82ffSelric 
823f59d82ffSelric 	memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
824f59d82ffSelric 	c->length += 1;
825f59d82ffSelric     }
826f59d82ffSelric 
827f59d82ffSelric     krb5_storage_free(response);
828f59d82ffSelric     krb5_data_free(&response_data);
829f59d82ffSelric 
830f59d82ffSelric  out:
831f59d82ffSelric     if (ret && c) {
832f59d82ffSelric         free(c->uuids);
833f59d82ffSelric         free(c);
834f59d82ffSelric     } else
835f59d82ffSelric 	*cursor = c;
836f59d82ffSelric 
837f59d82ffSelric     return ret;
838f59d82ffSelric }
839f59d82ffSelric 
840f59d82ffSelric /*
841f59d82ffSelric  * Send uuid
842f59d82ffSelric  * Recv cache name
843f59d82ffSelric  */
844f59d82ffSelric 
845f59d82ffSelric static krb5_error_code
kcm_get_cache_next(krb5_context context,krb5_cc_cursor cursor,const krb5_cc_ops * ops,krb5_ccache * id)846f59d82ffSelric kcm_get_cache_next(krb5_context context, krb5_cc_cursor cursor, const krb5_cc_ops *ops, krb5_ccache *id)
847f59d82ffSelric {
848f59d82ffSelric     krb5_error_code ret;
849f59d82ffSelric     krb5_kcm_cursor c = KCMCURSOR(cursor);
850f59d82ffSelric     krb5_storage *request, *response;
851f59d82ffSelric     krb5_data response_data;
852f59d82ffSelric     ssize_t sret;
853f59d82ffSelric     char *name;
854f59d82ffSelric 
855f59d82ffSelric     *id = NULL;
856f59d82ffSelric 
857f59d82ffSelric  again:
858f59d82ffSelric 
859f59d82ffSelric     if (c->offset >= c->length)
860f59d82ffSelric 	return KRB5_CC_END;
861f59d82ffSelric 
862f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_BY_UUID, &request);
863f59d82ffSelric     if (ret)
864f59d82ffSelric 	return ret;
865f59d82ffSelric 
866f59d82ffSelric     sret = krb5_storage_write(request,
867f59d82ffSelric 			      &c->uuids[c->offset],
868f59d82ffSelric 			      sizeof(c->uuids[c->offset]));
869f59d82ffSelric     c->offset++;
870f59d82ffSelric     if (sret != sizeof(c->uuids[c->offset])) {
871f59d82ffSelric 	krb5_storage_free(request);
872f59d82ffSelric 	krb5_clear_error_message(context);
873f59d82ffSelric 	return ENOMEM;
874f59d82ffSelric     }
875f59d82ffSelric 
876f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
877f59d82ffSelric     krb5_storage_free(request);
878f59d82ffSelric     if (ret == KRB5_CC_END)
879f59d82ffSelric 	goto again;
880f59d82ffSelric 
881f59d82ffSelric     ret = krb5_ret_stringz(response, &name);
882f59d82ffSelric     krb5_storage_free(response);
883f59d82ffSelric     krb5_data_free(&response_data);
884f59d82ffSelric 
885f59d82ffSelric     if (ret == 0) {
886f59d82ffSelric 	ret = _krb5_cc_allocate(context, ops, id);
887f59d82ffSelric 	if (ret == 0)
888f59d82ffSelric 	    ret = kcm_alloc(context, name, id);
889f59d82ffSelric 	krb5_xfree(name);
890f59d82ffSelric     }
891f59d82ffSelric 
892f59d82ffSelric     return ret;
893f59d82ffSelric }
894f59d82ffSelric 
895f59d82ffSelric static krb5_error_code
kcm_get_cache_next_kcm(krb5_context context,krb5_cc_cursor cursor,krb5_ccache * id)896f59d82ffSelric kcm_get_cache_next_kcm(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
897f59d82ffSelric {
898f59d82ffSelric #ifndef KCM_IS_API_CACHE
899f59d82ffSelric     return kcm_get_cache_next(context, cursor, &krb5_kcm_ops, id);
900f59d82ffSelric #else
901f59d82ffSelric     return KRB5_CC_END;
902f59d82ffSelric #endif
903f59d82ffSelric }
904f59d82ffSelric 
905f59d82ffSelric static krb5_error_code
kcm_get_cache_next_api(krb5_context context,krb5_cc_cursor cursor,krb5_ccache * id)906f59d82ffSelric kcm_get_cache_next_api(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
907f59d82ffSelric {
908f59d82ffSelric     return kcm_get_cache_next(context, cursor, &krb5_akcm_ops, id);
909f59d82ffSelric }
910f59d82ffSelric 
911f59d82ffSelric 
912f59d82ffSelric static krb5_error_code
kcm_end_cache_get(krb5_context context,krb5_cc_cursor cursor)913f59d82ffSelric kcm_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
914f59d82ffSelric {
915f59d82ffSelric     krb5_kcm_cursor c = KCMCURSOR(cursor);
916f59d82ffSelric 
917f59d82ffSelric     free(c->uuids);
918f59d82ffSelric     free(c);
919f59d82ffSelric     return 0;
920f59d82ffSelric }
921f59d82ffSelric 
922f59d82ffSelric 
923f59d82ffSelric static krb5_error_code
kcm_move(krb5_context context,krb5_ccache from,krb5_ccache to)924f59d82ffSelric kcm_move(krb5_context context, krb5_ccache from, krb5_ccache to)
925f59d82ffSelric {
926f59d82ffSelric     krb5_error_code ret;
927f59d82ffSelric     krb5_kcmcache *oldk = KCMCACHE(from);
928f59d82ffSelric     krb5_kcmcache *newk = KCMCACHE(to);
929f59d82ffSelric     krb5_storage *request;
930f59d82ffSelric 
931f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_MOVE_CACHE, &request);
932f59d82ffSelric     if (ret)
933f59d82ffSelric 	return ret;
934f59d82ffSelric 
935f59d82ffSelric     ret = krb5_store_stringz(request, oldk->name);
936f59d82ffSelric     if (ret) {
937f59d82ffSelric 	krb5_storage_free(request);
938f59d82ffSelric 	return ret;
939f59d82ffSelric     }
940f59d82ffSelric 
941f59d82ffSelric     ret = krb5_store_stringz(request, newk->name);
942f59d82ffSelric     if (ret) {
943f59d82ffSelric 	krb5_storage_free(request);
944f59d82ffSelric 	return ret;
945f59d82ffSelric     }
946f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
947f59d82ffSelric 
948f59d82ffSelric     krb5_storage_free(request);
949f59d82ffSelric     return ret;
950f59d82ffSelric }
951f59d82ffSelric 
952f59d82ffSelric static krb5_error_code
kcm_get_default_name(krb5_context context,const krb5_cc_ops * ops,const char * defstr,char ** str)953f59d82ffSelric kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops,
954f59d82ffSelric 		     const char *defstr, char **str)
955f59d82ffSelric {
956f59d82ffSelric     krb5_error_code ret;
957f59d82ffSelric     krb5_storage *request, *response;
958f59d82ffSelric     krb5_data response_data;
959f59d82ffSelric     char *name;
960e0895134Schristos     int aret;
961f59d82ffSelric 
962f59d82ffSelric     *str = NULL;
963f59d82ffSelric 
964f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_DEFAULT_CACHE, &request);
965f59d82ffSelric     if (ret)
966f59d82ffSelric 	return ret;
967f59d82ffSelric 
968f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
969f59d82ffSelric     krb5_storage_free(request);
970f59d82ffSelric     if (ret)
971f59d82ffSelric 	return _krb5_expand_default_cc_name(context, defstr, str);
972f59d82ffSelric 
973f59d82ffSelric     ret = krb5_ret_stringz(response, &name);
974f59d82ffSelric     krb5_storage_free(response);
975f59d82ffSelric     krb5_data_free(&response_data);
976f59d82ffSelric     if (ret)
977f59d82ffSelric 	return ret;
978f59d82ffSelric 
979e0895134Schristos     aret = asprintf(str, "%s:%s", ops->prefix, name);
980f59d82ffSelric     free(name);
981e0895134Schristos     if (aret == -1 || str == NULL)
982f59d82ffSelric 	return ENOMEM;
983f59d82ffSelric 
984f59d82ffSelric     return 0;
985f59d82ffSelric }
986f59d82ffSelric 
987f59d82ffSelric static krb5_error_code
kcm_get_default_name_api(krb5_context context,char ** str)988f59d82ffSelric kcm_get_default_name_api(krb5_context context, char **str)
989f59d82ffSelric {
990f59d82ffSelric     return kcm_get_default_name(context, &krb5_akcm_ops,
991f59d82ffSelric 				KRB5_DEFAULT_CCNAME_KCM_API, str);
992f59d82ffSelric }
993f59d82ffSelric 
994f59d82ffSelric static krb5_error_code
kcm_get_default_name_kcm(krb5_context context,char ** str)995f59d82ffSelric kcm_get_default_name_kcm(krb5_context context, char **str)
996f59d82ffSelric {
997f59d82ffSelric     return kcm_get_default_name(context, &krb5_kcm_ops,
998f59d82ffSelric 				KRB5_DEFAULT_CCNAME_KCM_KCM, str);
999f59d82ffSelric }
1000f59d82ffSelric 
1001f59d82ffSelric static krb5_error_code
kcm_set_default(krb5_context context,krb5_ccache id)1002f59d82ffSelric kcm_set_default(krb5_context context, krb5_ccache id)
1003f59d82ffSelric {
1004f59d82ffSelric     krb5_error_code ret;
1005f59d82ffSelric     krb5_storage *request;
1006f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
1007f59d82ffSelric 
1008f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_SET_DEFAULT_CACHE, &request);
1009f59d82ffSelric     if (ret)
1010f59d82ffSelric 	return ret;
1011f59d82ffSelric 
1012f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
1013f59d82ffSelric     if (ret) {
1014f59d82ffSelric 	krb5_storage_free(request);
1015f59d82ffSelric 	return ret;
1016f59d82ffSelric     }
1017f59d82ffSelric 
1018f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
1019f59d82ffSelric     krb5_storage_free(request);
1020f59d82ffSelric 
1021f59d82ffSelric     return ret;
1022f59d82ffSelric }
1023f59d82ffSelric 
1024f59d82ffSelric static krb5_error_code
kcm_lastchange(krb5_context context,krb5_ccache id,krb5_timestamp * mtime)1025f59d82ffSelric kcm_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
1026f59d82ffSelric {
1027f59d82ffSelric     *mtime = time(NULL);
1028f59d82ffSelric     return 0;
1029f59d82ffSelric }
1030f59d82ffSelric 
1031f59d82ffSelric static krb5_error_code
kcm_set_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat kdc_offset)1032f59d82ffSelric kcm_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
1033f59d82ffSelric {
1034f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
1035f59d82ffSelric     krb5_error_code ret;
1036f59d82ffSelric     krb5_storage *request;
1037f59d82ffSelric 
1038f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_SET_KDC_OFFSET, &request);
1039f59d82ffSelric     if (ret)
1040f59d82ffSelric 	return ret;
1041f59d82ffSelric 
1042f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
1043f59d82ffSelric     if (ret) {
1044f59d82ffSelric 	krb5_storage_free(request);
1045f59d82ffSelric 	return ret;
1046f59d82ffSelric     }
1047f59d82ffSelric     ret = krb5_store_int32(request, kdc_offset);
1048f59d82ffSelric     if (ret) {
1049f59d82ffSelric 	krb5_storage_free(request);
1050f59d82ffSelric 	return ret;
1051f59d82ffSelric     }
1052f59d82ffSelric 
1053f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
1054f59d82ffSelric     krb5_storage_free(request);
1055f59d82ffSelric 
1056f59d82ffSelric     return ret;
1057f59d82ffSelric }
1058f59d82ffSelric 
1059f59d82ffSelric static krb5_error_code
kcm_get_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat * kdc_offset)1060f59d82ffSelric kcm_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
1061f59d82ffSelric {
1062f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
1063f59d82ffSelric     krb5_error_code ret;
1064f59d82ffSelric     krb5_storage *request, *response;
1065f59d82ffSelric     krb5_data response_data;
1066f59d82ffSelric     int32_t offset;
1067f59d82ffSelric 
1068f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_KDC_OFFSET, &request);
1069f59d82ffSelric     if (ret)
1070f59d82ffSelric 	return ret;
1071f59d82ffSelric 
1072f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
1073f59d82ffSelric     if (ret) {
1074f59d82ffSelric 	krb5_storage_free(request);
1075f59d82ffSelric 	return ret;
1076f59d82ffSelric     }
1077f59d82ffSelric 
1078f59d82ffSelric     ret = krb5_kcm_call(context, request, &response, &response_data);
1079f59d82ffSelric     krb5_storage_free(request);
1080f59d82ffSelric     if (ret)
1081f59d82ffSelric 	return ret;
1082f59d82ffSelric 
1083f59d82ffSelric     ret = krb5_ret_int32(response, &offset);
1084f59d82ffSelric     krb5_storage_free(response);
1085f59d82ffSelric     krb5_data_free(&response_data);
1086f59d82ffSelric     if (ret)
1087f59d82ffSelric 	return ret;
1088f59d82ffSelric 
1089f59d82ffSelric     *kdc_offset = offset;
1090f59d82ffSelric 
1091f59d82ffSelric     return 0;
1092f59d82ffSelric }
1093f59d82ffSelric 
1094f59d82ffSelric /**
1095f59d82ffSelric  * Variable containing the KCM based credential cache implemention.
1096f59d82ffSelric  *
1097f59d82ffSelric  * @ingroup krb5_ccache
1098f59d82ffSelric  */
1099f59d82ffSelric 
1100f59d82ffSelric KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = {
1101f59d82ffSelric     KRB5_CC_OPS_VERSION,
1102f59d82ffSelric     "KCM",
1103f59d82ffSelric     kcm_get_name,
1104f59d82ffSelric     kcm_resolve,
1105f59d82ffSelric     kcm_gen_new,
1106f59d82ffSelric     kcm_initialize,
1107f59d82ffSelric     kcm_destroy,
1108f59d82ffSelric     kcm_close,
1109f59d82ffSelric     kcm_store_cred,
1110f59d82ffSelric     NULL /* kcm_retrieve */,
1111f59d82ffSelric     kcm_get_principal,
1112f59d82ffSelric     kcm_get_first,
1113f59d82ffSelric     kcm_get_next,
1114f59d82ffSelric     kcm_end_get,
1115f59d82ffSelric     kcm_remove_cred,
1116f59d82ffSelric     kcm_set_flags,
1117f59d82ffSelric     kcm_get_version,
1118f59d82ffSelric     kcm_get_cache_first,
1119f59d82ffSelric     kcm_get_cache_next_kcm,
1120f59d82ffSelric     kcm_end_cache_get,
1121f59d82ffSelric     kcm_move,
1122f59d82ffSelric     kcm_get_default_name_kcm,
1123f59d82ffSelric     kcm_set_default,
1124f59d82ffSelric     kcm_lastchange,
1125f59d82ffSelric     kcm_set_kdc_offset,
1126f59d82ffSelric     kcm_get_kdc_offset
1127f59d82ffSelric };
1128f59d82ffSelric 
1129f59d82ffSelric KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = {
1130f59d82ffSelric     KRB5_CC_OPS_VERSION,
1131f59d82ffSelric     "API",
1132f59d82ffSelric     kcm_get_name,
1133f59d82ffSelric     kcm_resolve,
1134f59d82ffSelric     kcm_gen_new,
1135f59d82ffSelric     kcm_initialize,
1136f59d82ffSelric     kcm_destroy,
1137f59d82ffSelric     kcm_close,
1138f59d82ffSelric     kcm_store_cred,
1139f59d82ffSelric     NULL /* kcm_retrieve */,
1140f59d82ffSelric     kcm_get_principal,
1141f59d82ffSelric     kcm_get_first,
1142f59d82ffSelric     kcm_get_next,
1143f59d82ffSelric     kcm_end_get,
1144f59d82ffSelric     kcm_remove_cred,
1145f59d82ffSelric     kcm_set_flags,
1146f59d82ffSelric     kcm_get_version,
1147f59d82ffSelric     kcm_get_cache_first,
1148f59d82ffSelric     kcm_get_cache_next_api,
1149f59d82ffSelric     kcm_end_cache_get,
1150f59d82ffSelric     kcm_move,
1151f59d82ffSelric     kcm_get_default_name_api,
1152f59d82ffSelric     kcm_set_default,
1153603f2576Spettai     kcm_lastchange,
1154603f2576Spettai     NULL,
1155603f2576Spettai     NULL
1156f59d82ffSelric };
1157f59d82ffSelric 
1158f59d82ffSelric 
1159603f2576Spettai KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
_krb5_kcm_is_running(krb5_context context)1160f59d82ffSelric _krb5_kcm_is_running(krb5_context context)
1161f59d82ffSelric {
1162f59d82ffSelric     krb5_error_code ret;
1163f59d82ffSelric     krb5_ccache_data ccdata;
1164f59d82ffSelric     krb5_ccache id = &ccdata;
1165f59d82ffSelric     krb5_boolean running;
1166f59d82ffSelric 
1167f59d82ffSelric     ret = kcm_alloc(context, NULL, &id);
1168f59d82ffSelric     if (ret)
1169f59d82ffSelric 	return 0;
1170f59d82ffSelric 
1171f59d82ffSelric     running = (_krb5_kcm_noop(context, id) == 0);
1172f59d82ffSelric 
1173f59d82ffSelric     kcm_free(context, &id);
1174f59d82ffSelric 
1175f59d82ffSelric     return running;
1176f59d82ffSelric }
1177f59d82ffSelric 
1178f59d82ffSelric /*
1179f59d82ffSelric  * Request:
1180f59d82ffSelric  *
1181f59d82ffSelric  * Response:
1182f59d82ffSelric  *
1183f59d82ffSelric  */
1184603f2576Spettai KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_kcm_noop(krb5_context context,krb5_ccache id)1185f59d82ffSelric _krb5_kcm_noop(krb5_context context,
1186f59d82ffSelric 	       krb5_ccache id)
1187f59d82ffSelric {
1188f59d82ffSelric     krb5_error_code ret;
1189f59d82ffSelric     krb5_storage *request;
1190f59d82ffSelric 
1191f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_NOOP, &request);
1192f59d82ffSelric     if (ret)
1193f59d82ffSelric 	return ret;
1194f59d82ffSelric 
1195f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
1196f59d82ffSelric 
1197f59d82ffSelric     krb5_storage_free(request);
1198f59d82ffSelric     return ret;
1199f59d82ffSelric }
1200f59d82ffSelric 
1201f59d82ffSelric 
1202f59d82ffSelric /*
1203f59d82ffSelric  * Request:
1204f59d82ffSelric  *      NameZ
1205f59d82ffSelric  *      ServerPrincipalPresent
1206f59d82ffSelric  *      ServerPrincipal OPTIONAL
1207f59d82ffSelric  *      Key
1208f59d82ffSelric  *
1209f59d82ffSelric  * Repsonse:
1210f59d82ffSelric  *
1211f59d82ffSelric  */
1212603f2576Spettai KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_kcm_get_initial_ticket(krb5_context context,krb5_ccache id,krb5_principal server,krb5_keyblock * key)1213f59d82ffSelric _krb5_kcm_get_initial_ticket(krb5_context context,
1214f59d82ffSelric 			     krb5_ccache id,
1215f59d82ffSelric 			     krb5_principal server,
1216f59d82ffSelric 			     krb5_keyblock *key)
1217f59d82ffSelric {
1218f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
1219f59d82ffSelric     krb5_error_code ret;
1220f59d82ffSelric     krb5_storage *request;
1221f59d82ffSelric 
1222f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request);
1223f59d82ffSelric     if (ret)
1224f59d82ffSelric 	return ret;
1225f59d82ffSelric 
1226f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
1227f59d82ffSelric     if (ret) {
1228f59d82ffSelric 	krb5_storage_free(request);
1229f59d82ffSelric 	return ret;
1230f59d82ffSelric     }
1231f59d82ffSelric 
1232f59d82ffSelric     ret = krb5_store_int8(request, (server == NULL) ? 0 : 1);
1233f59d82ffSelric     if (ret) {
1234f59d82ffSelric 	krb5_storage_free(request);
1235f59d82ffSelric 	return ret;
1236f59d82ffSelric     }
1237f59d82ffSelric 
1238f59d82ffSelric     if (server != NULL) {
1239f59d82ffSelric 	ret = krb5_store_principal(request, server);
1240f59d82ffSelric 	if (ret) {
1241f59d82ffSelric 	    krb5_storage_free(request);
1242f59d82ffSelric 	    return ret;
1243f59d82ffSelric 	}
1244f59d82ffSelric     }
1245f59d82ffSelric 
1246f59d82ffSelric     ret = krb5_store_keyblock(request, *key);
1247f59d82ffSelric     if (ret) {
1248f59d82ffSelric 	krb5_storage_free(request);
1249f59d82ffSelric 	return ret;
1250f59d82ffSelric     }
1251f59d82ffSelric 
1252f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
1253f59d82ffSelric 
1254f59d82ffSelric     krb5_storage_free(request);
1255f59d82ffSelric     return ret;
1256f59d82ffSelric }
1257f59d82ffSelric 
1258f59d82ffSelric 
1259f59d82ffSelric /*
1260f59d82ffSelric  * Request:
1261f59d82ffSelric  *      NameZ
1262f59d82ffSelric  *      KDCFlags
1263f59d82ffSelric  *      EncryptionType
1264f59d82ffSelric  *      ServerPrincipal
1265f59d82ffSelric  *
1266f59d82ffSelric  * Repsonse:
1267f59d82ffSelric  *
1268f59d82ffSelric  */
1269603f2576Spettai KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_kcm_get_ticket(krb5_context context,krb5_ccache id,krb5_kdc_flags flags,krb5_enctype enctype,krb5_principal server)1270f59d82ffSelric _krb5_kcm_get_ticket(krb5_context context,
1271f59d82ffSelric 		     krb5_ccache id,
1272f59d82ffSelric 		     krb5_kdc_flags flags,
1273f59d82ffSelric 		     krb5_enctype enctype,
1274f59d82ffSelric 		     krb5_principal server)
1275f59d82ffSelric {
1276f59d82ffSelric     krb5_error_code ret;
1277f59d82ffSelric     krb5_kcmcache *k = KCMCACHE(id);
1278f59d82ffSelric     krb5_storage *request;
1279f59d82ffSelric 
1280f59d82ffSelric     ret = krb5_kcm_storage_request(context, KCM_OP_GET_TICKET, &request);
1281f59d82ffSelric     if (ret)
1282f59d82ffSelric 	return ret;
1283f59d82ffSelric 
1284f59d82ffSelric     ret = krb5_store_stringz(request, k->name);
1285f59d82ffSelric     if (ret) {
1286f59d82ffSelric 	krb5_storage_free(request);
1287f59d82ffSelric 	return ret;
1288f59d82ffSelric     }
1289f59d82ffSelric 
1290f59d82ffSelric     ret = krb5_store_int32(request, flags.i);
1291f59d82ffSelric     if (ret) {
1292f59d82ffSelric 	krb5_storage_free(request);
1293f59d82ffSelric 	return ret;
1294f59d82ffSelric     }
1295f59d82ffSelric 
1296f59d82ffSelric     ret = krb5_store_int32(request, enctype);
1297f59d82ffSelric     if (ret) {
1298f59d82ffSelric 	krb5_storage_free(request);
1299f59d82ffSelric 	return ret;
1300f59d82ffSelric     }
1301f59d82ffSelric 
1302f59d82ffSelric     ret = krb5_store_principal(request, server);
1303f59d82ffSelric     if (ret) {
1304f59d82ffSelric 	krb5_storage_free(request);
1305f59d82ffSelric 	return ret;
1306f59d82ffSelric     }
1307f59d82ffSelric 
1308f59d82ffSelric     ret = krb5_kcm_call(context, request, NULL, NULL);
1309f59d82ffSelric 
1310f59d82ffSelric     krb5_storage_free(request);
1311f59d82ffSelric     return ret;
1312f59d82ffSelric }
1313f59d82ffSelric 
1314f59d82ffSelric #endif /* HAVE_KCM */
1315