xref: /minix3/crypto/external/bsd/heimdal/dist/kcm/protocol.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: protocol.c,v 1.1.1.2 2014/04/24 12:45:27 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 2005, PADL Software Pty Ltd.
5ebfedea0SLionel Sambuc  * All rights reserved.
6ebfedea0SLionel Sambuc  *
7ebfedea0SLionel Sambuc  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8ebfedea0SLionel Sambuc  *
9ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
10ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
11ebfedea0SLionel Sambuc  * are met:
12ebfedea0SLionel Sambuc  *
13ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15ebfedea0SLionel Sambuc  *
16ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
17ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
18ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
19ebfedea0SLionel Sambuc  *
20ebfedea0SLionel Sambuc  * 3. Neither the name of PADL Software nor the names of its contributors
21ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
22ebfedea0SLionel Sambuc  *    without specific prior written permission.
23ebfedea0SLionel Sambuc  *
24ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
25ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
28ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34ebfedea0SLionel Sambuc  * SUCH DAMAGE.
35ebfedea0SLionel Sambuc  */
36ebfedea0SLionel Sambuc 
37ebfedea0SLionel Sambuc #include "kcm_locl.h"
38ebfedea0SLionel Sambuc #include <krb5/heimntlm.h>
39ebfedea0SLionel Sambuc 
40ebfedea0SLionel Sambuc static void
41ebfedea0SLionel Sambuc kcm_drop_default_cache(krb5_context context, kcm_client *client, char *name);
42ebfedea0SLionel Sambuc 
43ebfedea0SLionel Sambuc 
44ebfedea0SLionel Sambuc int
kcm_is_same_session(kcm_client * client,uid_t uid,pid_t session)45ebfedea0SLionel Sambuc kcm_is_same_session(kcm_client *client, uid_t uid, pid_t session)
46ebfedea0SLionel Sambuc {
47ebfedea0SLionel Sambuc #if 0 /* XXX pppd is running in diffrent session the user */
48ebfedea0SLionel Sambuc     if (session != -1)
49ebfedea0SLionel Sambuc 	return (client->session == session);
50ebfedea0SLionel Sambuc     else
51ebfedea0SLionel Sambuc #endif
52ebfedea0SLionel Sambuc 	return  (client->uid == uid);
53ebfedea0SLionel Sambuc }
54ebfedea0SLionel Sambuc 
55ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_noop(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)56ebfedea0SLionel Sambuc kcm_op_noop(krb5_context context,
57ebfedea0SLionel Sambuc 	    kcm_client *client,
58ebfedea0SLionel Sambuc 	    kcm_operation opcode,
59ebfedea0SLionel Sambuc 	    krb5_storage *request,
60ebfedea0SLionel Sambuc 	    krb5_storage *response)
61ebfedea0SLionel Sambuc {
62ebfedea0SLionel Sambuc     KCM_LOG_REQUEST(context, client, opcode);
63ebfedea0SLionel Sambuc 
64ebfedea0SLionel Sambuc     return 0;
65ebfedea0SLionel Sambuc }
66ebfedea0SLionel Sambuc 
67ebfedea0SLionel Sambuc /*
68ebfedea0SLionel Sambuc  * Request:
69ebfedea0SLionel Sambuc  *	NameZ
70ebfedea0SLionel Sambuc  * Response:
71ebfedea0SLionel Sambuc  *	NameZ
72ebfedea0SLionel Sambuc  *
73ebfedea0SLionel Sambuc  */
74ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_name(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)75ebfedea0SLionel Sambuc kcm_op_get_name(krb5_context context,
76ebfedea0SLionel Sambuc 		kcm_client *client,
77ebfedea0SLionel Sambuc 		kcm_operation opcode,
78ebfedea0SLionel Sambuc 		krb5_storage *request,
79ebfedea0SLionel Sambuc 		krb5_storage *response)
80ebfedea0SLionel Sambuc 
81ebfedea0SLionel Sambuc {
82ebfedea0SLionel Sambuc     krb5_error_code ret;
83ebfedea0SLionel Sambuc     char *name = NULL;
84ebfedea0SLionel Sambuc     kcm_ccache ccache;
85ebfedea0SLionel Sambuc 
86ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
87ebfedea0SLionel Sambuc     if (ret)
88ebfedea0SLionel Sambuc 	return ret;
89ebfedea0SLionel Sambuc 
90ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
91ebfedea0SLionel Sambuc 
92ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
93ebfedea0SLionel Sambuc 				    name, &ccache);
94ebfedea0SLionel Sambuc     if (ret) {
95ebfedea0SLionel Sambuc 	free(name);
96ebfedea0SLionel Sambuc 	return ret;
97ebfedea0SLionel Sambuc     }
98ebfedea0SLionel Sambuc 
99ebfedea0SLionel Sambuc     ret = krb5_store_stringz(response, ccache->name);
100ebfedea0SLionel Sambuc     if (ret) {
101ebfedea0SLionel Sambuc 	kcm_release_ccache(context, ccache);
102ebfedea0SLionel Sambuc 	free(name);
103ebfedea0SLionel Sambuc 	return ret;
104ebfedea0SLionel Sambuc     }
105ebfedea0SLionel Sambuc 
106ebfedea0SLionel Sambuc     free(name);
107ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
108ebfedea0SLionel Sambuc     return 0;
109ebfedea0SLionel Sambuc }
110ebfedea0SLionel Sambuc 
111ebfedea0SLionel Sambuc /*
112ebfedea0SLionel Sambuc  * Request:
113ebfedea0SLionel Sambuc  *
114ebfedea0SLionel Sambuc  * Response:
115ebfedea0SLionel Sambuc  *	NameZ
116ebfedea0SLionel Sambuc  */
117ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_gen_new(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)118ebfedea0SLionel Sambuc kcm_op_gen_new(krb5_context context,
119ebfedea0SLionel Sambuc 	       kcm_client *client,
120ebfedea0SLionel Sambuc 	       kcm_operation opcode,
121ebfedea0SLionel Sambuc 	       krb5_storage *request,
122ebfedea0SLionel Sambuc 	       krb5_storage *response)
123ebfedea0SLionel Sambuc {
124ebfedea0SLionel Sambuc     krb5_error_code ret;
125ebfedea0SLionel Sambuc     char *name;
126ebfedea0SLionel Sambuc 
127ebfedea0SLionel Sambuc     KCM_LOG_REQUEST(context, client, opcode);
128ebfedea0SLionel Sambuc 
129ebfedea0SLionel Sambuc     name = kcm_ccache_nextid(client->pid, client->uid, client->gid);
130ebfedea0SLionel Sambuc     if (name == NULL) {
131ebfedea0SLionel Sambuc 	return KRB5_CC_NOMEM;
132ebfedea0SLionel Sambuc     }
133ebfedea0SLionel Sambuc 
134ebfedea0SLionel Sambuc     ret = krb5_store_stringz(response, name);
135ebfedea0SLionel Sambuc     free(name);
136ebfedea0SLionel Sambuc 
137ebfedea0SLionel Sambuc     return ret;
138ebfedea0SLionel Sambuc }
139ebfedea0SLionel Sambuc 
140ebfedea0SLionel Sambuc /*
141ebfedea0SLionel Sambuc  * Request:
142ebfedea0SLionel Sambuc  *	NameZ
143ebfedea0SLionel Sambuc  *	Principal
144ebfedea0SLionel Sambuc  *
145ebfedea0SLionel Sambuc  * Response:
146ebfedea0SLionel Sambuc  *
147ebfedea0SLionel Sambuc  */
148ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_initialize(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)149ebfedea0SLionel Sambuc kcm_op_initialize(krb5_context context,
150ebfedea0SLionel Sambuc 		  kcm_client *client,
151ebfedea0SLionel Sambuc 		  kcm_operation opcode,
152ebfedea0SLionel Sambuc 		  krb5_storage *request,
153ebfedea0SLionel Sambuc 		  krb5_storage *response)
154ebfedea0SLionel Sambuc {
155ebfedea0SLionel Sambuc     kcm_ccache ccache;
156ebfedea0SLionel Sambuc     krb5_principal principal;
157ebfedea0SLionel Sambuc     krb5_error_code ret;
158ebfedea0SLionel Sambuc     char *name;
159ebfedea0SLionel Sambuc #if 0
160ebfedea0SLionel Sambuc     kcm_event event;
161ebfedea0SLionel Sambuc #endif
162ebfedea0SLionel Sambuc 
163ebfedea0SLionel Sambuc     KCM_LOG_REQUEST(context, client, opcode);
164ebfedea0SLionel Sambuc 
165ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
166ebfedea0SLionel Sambuc     if (ret)
167ebfedea0SLionel Sambuc 	return ret;
168ebfedea0SLionel Sambuc 
169ebfedea0SLionel Sambuc     ret = krb5_ret_principal(request, &principal);
170ebfedea0SLionel Sambuc     if (ret) {
171ebfedea0SLionel Sambuc 	free(name);
172ebfedea0SLionel Sambuc 	return ret;
173ebfedea0SLionel Sambuc     }
174ebfedea0SLionel Sambuc 
175ebfedea0SLionel Sambuc     ret = kcm_ccache_new_client(context, client, name, &ccache);
176ebfedea0SLionel Sambuc     if (ret) {
177ebfedea0SLionel Sambuc 	free(name);
178ebfedea0SLionel Sambuc 	krb5_free_principal(context, principal);
179ebfedea0SLionel Sambuc 	return ret;
180ebfedea0SLionel Sambuc     }
181ebfedea0SLionel Sambuc 
182ebfedea0SLionel Sambuc     ccache->client = principal;
183ebfedea0SLionel Sambuc 
184ebfedea0SLionel Sambuc     free(name);
185ebfedea0SLionel Sambuc 
186ebfedea0SLionel Sambuc #if 0
187ebfedea0SLionel Sambuc     /*
188ebfedea0SLionel Sambuc      * Create a new credentials cache. To mitigate DoS attacks we will
189ebfedea0SLionel Sambuc      * expire it in 30 minutes unless it has some credentials added
190ebfedea0SLionel Sambuc      * to it
191ebfedea0SLionel Sambuc      */
192ebfedea0SLionel Sambuc 
193ebfedea0SLionel Sambuc     event.fire_time = 30 * 60;
194ebfedea0SLionel Sambuc     event.expire_time = 0;
195ebfedea0SLionel Sambuc     event.backoff_time = 0;
196ebfedea0SLionel Sambuc     event.action = KCM_EVENT_DESTROY_EMPTY_CACHE;
197ebfedea0SLionel Sambuc     event.ccache = ccache;
198ebfedea0SLionel Sambuc 
199ebfedea0SLionel Sambuc     ret = kcm_enqueue_event_relative(context, &event);
200ebfedea0SLionel Sambuc #endif
201ebfedea0SLionel Sambuc 
202ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
203ebfedea0SLionel Sambuc 
204ebfedea0SLionel Sambuc     return ret;
205ebfedea0SLionel Sambuc }
206ebfedea0SLionel Sambuc 
207ebfedea0SLionel Sambuc /*
208ebfedea0SLionel Sambuc  * Request:
209ebfedea0SLionel Sambuc  *	NameZ
210ebfedea0SLionel Sambuc  *
211ebfedea0SLionel Sambuc  * Response:
212ebfedea0SLionel Sambuc  *
213ebfedea0SLionel Sambuc  */
214ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_destroy(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)215ebfedea0SLionel Sambuc kcm_op_destroy(krb5_context context,
216ebfedea0SLionel Sambuc 	       kcm_client *client,
217ebfedea0SLionel Sambuc 	       kcm_operation opcode,
218ebfedea0SLionel Sambuc 	       krb5_storage *request,
219ebfedea0SLionel Sambuc 	       krb5_storage *response)
220ebfedea0SLionel Sambuc {
221ebfedea0SLionel Sambuc     krb5_error_code ret;
222ebfedea0SLionel Sambuc     char *name;
223ebfedea0SLionel Sambuc 
224ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
225ebfedea0SLionel Sambuc     if (ret)
226ebfedea0SLionel Sambuc 	return ret;
227ebfedea0SLionel Sambuc 
228ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
229ebfedea0SLionel Sambuc 
230ebfedea0SLionel Sambuc     ret = kcm_ccache_destroy_client(context, client, name);
231ebfedea0SLionel Sambuc     if (ret == 0)
232ebfedea0SLionel Sambuc 	kcm_drop_default_cache(context, client, name);
233ebfedea0SLionel Sambuc 
234ebfedea0SLionel Sambuc     free(name);
235ebfedea0SLionel Sambuc 
236ebfedea0SLionel Sambuc     return ret;
237ebfedea0SLionel Sambuc }
238ebfedea0SLionel Sambuc 
239ebfedea0SLionel Sambuc /*
240ebfedea0SLionel Sambuc  * Request:
241ebfedea0SLionel Sambuc  *	NameZ
242ebfedea0SLionel Sambuc  *	Creds
243ebfedea0SLionel Sambuc  *
244ebfedea0SLionel Sambuc  * Response:
245ebfedea0SLionel Sambuc  *
246ebfedea0SLionel Sambuc  */
247ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_store(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)248ebfedea0SLionel Sambuc kcm_op_store(krb5_context context,
249ebfedea0SLionel Sambuc 	     kcm_client *client,
250ebfedea0SLionel Sambuc 	     kcm_operation opcode,
251ebfedea0SLionel Sambuc 	     krb5_storage *request,
252ebfedea0SLionel Sambuc 	     krb5_storage *response)
253ebfedea0SLionel Sambuc {
254ebfedea0SLionel Sambuc     krb5_creds creds;
255ebfedea0SLionel Sambuc     krb5_error_code ret;
256ebfedea0SLionel Sambuc     kcm_ccache ccache;
257ebfedea0SLionel Sambuc     char *name;
258ebfedea0SLionel Sambuc 
259ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
260ebfedea0SLionel Sambuc     if (ret)
261ebfedea0SLionel Sambuc 	return ret;
262ebfedea0SLionel Sambuc 
263ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
264ebfedea0SLionel Sambuc 
265ebfedea0SLionel Sambuc     ret = krb5_ret_creds(request, &creds);
266ebfedea0SLionel Sambuc     if (ret) {
267ebfedea0SLionel Sambuc 	free(name);
268ebfedea0SLionel Sambuc 	return ret;
269ebfedea0SLionel Sambuc     }
270ebfedea0SLionel Sambuc 
271ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
272ebfedea0SLionel Sambuc 				    name, &ccache);
273ebfedea0SLionel Sambuc     if (ret) {
274ebfedea0SLionel Sambuc 	free(name);
275ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, &creds);
276ebfedea0SLionel Sambuc 	return ret;
277ebfedea0SLionel Sambuc     }
278ebfedea0SLionel Sambuc 
279ebfedea0SLionel Sambuc     ret = kcm_ccache_store_cred(context, ccache, &creds, 0);
280ebfedea0SLionel Sambuc     if (ret) {
281ebfedea0SLionel Sambuc 	free(name);
282ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, &creds);
283ebfedea0SLionel Sambuc 	kcm_release_ccache(context, ccache);
284ebfedea0SLionel Sambuc 	return ret;
285ebfedea0SLionel Sambuc     }
286ebfedea0SLionel Sambuc 
287ebfedea0SLionel Sambuc     kcm_ccache_enqueue_default(context, ccache, &creds);
288ebfedea0SLionel Sambuc 
289ebfedea0SLionel Sambuc     free(name);
290ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
291ebfedea0SLionel Sambuc 
292ebfedea0SLionel Sambuc     return 0;
293ebfedea0SLionel Sambuc }
294ebfedea0SLionel Sambuc 
295ebfedea0SLionel Sambuc /*
296ebfedea0SLionel Sambuc  * Request:
297ebfedea0SLionel Sambuc  *	NameZ
298ebfedea0SLionel Sambuc  *	WhichFields
299ebfedea0SLionel Sambuc  *	MatchCreds
300ebfedea0SLionel Sambuc  *
301ebfedea0SLionel Sambuc  * Response:
302ebfedea0SLionel Sambuc  *	Creds
303ebfedea0SLionel Sambuc  *
304ebfedea0SLionel Sambuc  */
305ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_retrieve(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)306ebfedea0SLionel Sambuc kcm_op_retrieve(krb5_context context,
307ebfedea0SLionel Sambuc 		kcm_client *client,
308ebfedea0SLionel Sambuc 		kcm_operation opcode,
309ebfedea0SLionel Sambuc 		krb5_storage *request,
310ebfedea0SLionel Sambuc 		krb5_storage *response)
311ebfedea0SLionel Sambuc {
312ebfedea0SLionel Sambuc     uint32_t flags;
313ebfedea0SLionel Sambuc     krb5_creds mcreds;
314ebfedea0SLionel Sambuc     krb5_error_code ret;
315ebfedea0SLionel Sambuc     kcm_ccache ccache;
316ebfedea0SLionel Sambuc     char *name;
317ebfedea0SLionel Sambuc     krb5_creds *credp;
318ebfedea0SLionel Sambuc     int free_creds = 0;
319ebfedea0SLionel Sambuc 
320ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
321ebfedea0SLionel Sambuc     if (ret)
322ebfedea0SLionel Sambuc 	return ret;
323ebfedea0SLionel Sambuc 
324ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
325ebfedea0SLionel Sambuc 
326ebfedea0SLionel Sambuc     ret = krb5_ret_uint32(request, &flags);
327ebfedea0SLionel Sambuc     if (ret) {
328ebfedea0SLionel Sambuc 	free(name);
329ebfedea0SLionel Sambuc 	return ret;
330ebfedea0SLionel Sambuc     }
331ebfedea0SLionel Sambuc 
332ebfedea0SLionel Sambuc     ret = krb5_ret_creds_tag(request, &mcreds);
333ebfedea0SLionel Sambuc     if (ret) {
334ebfedea0SLionel Sambuc 	free(name);
335ebfedea0SLionel Sambuc 	return ret;
336ebfedea0SLionel Sambuc     }
337ebfedea0SLionel Sambuc 
338ebfedea0SLionel Sambuc     if (disallow_getting_krbtgt &&
339ebfedea0SLionel Sambuc 	mcreds.server->name.name_string.len == 2 &&
340ebfedea0SLionel Sambuc 	strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0)
341ebfedea0SLionel Sambuc     {
342ebfedea0SLionel Sambuc 	free(name);
343ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, &mcreds);
344ebfedea0SLionel Sambuc 	return KRB5_FCC_PERM;
345ebfedea0SLionel Sambuc     }
346ebfedea0SLionel Sambuc 
347ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
348ebfedea0SLionel Sambuc 				    name, &ccache);
349ebfedea0SLionel Sambuc     if (ret) {
350ebfedea0SLionel Sambuc 	free(name);
351ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, &mcreds);
352ebfedea0SLionel Sambuc 	return ret;
353ebfedea0SLionel Sambuc     }
354ebfedea0SLionel Sambuc 
355ebfedea0SLionel Sambuc     ret = kcm_ccache_retrieve_cred(context, ccache, flags,
356ebfedea0SLionel Sambuc 				   &mcreds, &credp);
357ebfedea0SLionel Sambuc     if (ret && ((flags & KRB5_GC_CACHED) == 0) &&
358ebfedea0SLionel Sambuc 	!krb5_is_config_principal(context, mcreds.server)) {
359ebfedea0SLionel Sambuc 	krb5_ccache_data ccdata;
360ebfedea0SLionel Sambuc 
361ebfedea0SLionel Sambuc 	/* try and acquire */
362ebfedea0SLionel Sambuc 	HEIMDAL_MUTEX_lock(&ccache->mutex);
363ebfedea0SLionel Sambuc 
364ebfedea0SLionel Sambuc 	/* Fake up an internal ccache */
365ebfedea0SLionel Sambuc 	kcm_internal_ccache(context, ccache, &ccdata);
366ebfedea0SLionel Sambuc 
367ebfedea0SLionel Sambuc 	/* glue cc layer will store creds */
368ebfedea0SLionel Sambuc 	ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp);
369ebfedea0SLionel Sambuc 	if (ret == 0)
370ebfedea0SLionel Sambuc 	    free_creds = 1;
371ebfedea0SLionel Sambuc 
372ebfedea0SLionel Sambuc 	HEIMDAL_MUTEX_unlock(&ccache->mutex);
373ebfedea0SLionel Sambuc     }
374ebfedea0SLionel Sambuc 
375ebfedea0SLionel Sambuc     if (ret == 0) {
376ebfedea0SLionel Sambuc 	ret = krb5_store_creds(response, credp);
377ebfedea0SLionel Sambuc     }
378ebfedea0SLionel Sambuc 
379ebfedea0SLionel Sambuc     free(name);
380ebfedea0SLionel Sambuc     krb5_free_cred_contents(context, &mcreds);
381ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
382ebfedea0SLionel Sambuc 
383ebfedea0SLionel Sambuc     if (free_creds)
384ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, credp);
385ebfedea0SLionel Sambuc 
386ebfedea0SLionel Sambuc     return ret;
387ebfedea0SLionel Sambuc }
388ebfedea0SLionel Sambuc 
389ebfedea0SLionel Sambuc /*
390ebfedea0SLionel Sambuc  * Request:
391ebfedea0SLionel Sambuc  *	NameZ
392ebfedea0SLionel Sambuc  *
393ebfedea0SLionel Sambuc  * Response:
394ebfedea0SLionel Sambuc  *	Principal
395ebfedea0SLionel Sambuc  */
396ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_principal(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)397ebfedea0SLionel Sambuc kcm_op_get_principal(krb5_context context,
398ebfedea0SLionel Sambuc 		     kcm_client *client,
399ebfedea0SLionel Sambuc 		     kcm_operation opcode,
400ebfedea0SLionel Sambuc 		     krb5_storage *request,
401ebfedea0SLionel Sambuc 		     krb5_storage *response)
402ebfedea0SLionel Sambuc {
403ebfedea0SLionel Sambuc     krb5_error_code ret;
404ebfedea0SLionel Sambuc     kcm_ccache ccache;
405ebfedea0SLionel Sambuc     char *name;
406ebfedea0SLionel Sambuc 
407ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
408ebfedea0SLionel Sambuc     if (ret)
409ebfedea0SLionel Sambuc 	return ret;
410ebfedea0SLionel Sambuc 
411ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
412ebfedea0SLionel Sambuc 
413ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
414ebfedea0SLionel Sambuc 				    name, &ccache);
415ebfedea0SLionel Sambuc     if (ret) {
416ebfedea0SLionel Sambuc 	free(name);
417ebfedea0SLionel Sambuc 	return ret;
418ebfedea0SLionel Sambuc     }
419ebfedea0SLionel Sambuc 
420ebfedea0SLionel Sambuc     if (ccache->client == NULL)
421ebfedea0SLionel Sambuc 	ret = KRB5_CC_NOTFOUND;
422ebfedea0SLionel Sambuc     else
423ebfedea0SLionel Sambuc 	ret = krb5_store_principal(response, ccache->client);
424ebfedea0SLionel Sambuc 
425ebfedea0SLionel Sambuc     free(name);
426ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
427ebfedea0SLionel Sambuc 
428ebfedea0SLionel Sambuc     return 0;
429ebfedea0SLionel Sambuc }
430ebfedea0SLionel Sambuc 
431ebfedea0SLionel Sambuc /*
432ebfedea0SLionel Sambuc  * Request:
433ebfedea0SLionel Sambuc  *	NameZ
434ebfedea0SLionel Sambuc  *
435ebfedea0SLionel Sambuc  * Response:
436ebfedea0SLionel Sambuc  *	UUIDs
437ebfedea0SLionel Sambuc  *
438ebfedea0SLionel Sambuc  */
439ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_cred_uuid_list(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)440ebfedea0SLionel Sambuc kcm_op_get_cred_uuid_list(krb5_context context,
441ebfedea0SLionel Sambuc 			  kcm_client *client,
442ebfedea0SLionel Sambuc 			  kcm_operation opcode,
443ebfedea0SLionel Sambuc 			  krb5_storage *request,
444ebfedea0SLionel Sambuc 			  krb5_storage *response)
445ebfedea0SLionel Sambuc {
446ebfedea0SLionel Sambuc     struct kcm_creds *creds;
447ebfedea0SLionel Sambuc     krb5_error_code ret;
448ebfedea0SLionel Sambuc     kcm_ccache ccache;
449ebfedea0SLionel Sambuc     char *name;
450ebfedea0SLionel Sambuc 
451ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
452ebfedea0SLionel Sambuc     if (ret)
453ebfedea0SLionel Sambuc 	return ret;
454ebfedea0SLionel Sambuc 
455ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
456ebfedea0SLionel Sambuc 
457ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
458ebfedea0SLionel Sambuc 				    name, &ccache);
459ebfedea0SLionel Sambuc     free(name);
460ebfedea0SLionel Sambuc     if (ret)
461ebfedea0SLionel Sambuc 	return ret;
462ebfedea0SLionel Sambuc 
463ebfedea0SLionel Sambuc     for (creds = ccache->creds ; creds ; creds = creds->next) {
464ebfedea0SLionel Sambuc 	ssize_t sret;
465ebfedea0SLionel Sambuc 	sret = krb5_storage_write(response, &creds->uuid, sizeof(creds->uuid));
466ebfedea0SLionel Sambuc 	if (sret != sizeof(creds->uuid)) {
467ebfedea0SLionel Sambuc 	    ret = ENOMEM;
468ebfedea0SLionel Sambuc 	    break;
469ebfedea0SLionel Sambuc 	}
470ebfedea0SLionel Sambuc     }
471ebfedea0SLionel Sambuc 
472ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
473ebfedea0SLionel Sambuc 
474ebfedea0SLionel Sambuc     return ret;
475ebfedea0SLionel Sambuc }
476ebfedea0SLionel Sambuc 
477ebfedea0SLionel Sambuc /*
478ebfedea0SLionel Sambuc  * Request:
479ebfedea0SLionel Sambuc  *	NameZ
480ebfedea0SLionel Sambuc  *	Cursor
481ebfedea0SLionel Sambuc  *
482ebfedea0SLionel Sambuc  * Response:
483ebfedea0SLionel Sambuc  *	Creds
484ebfedea0SLionel Sambuc  */
485ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_cred_by_uuid(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)486ebfedea0SLionel Sambuc kcm_op_get_cred_by_uuid(krb5_context context,
487ebfedea0SLionel Sambuc 			kcm_client *client,
488ebfedea0SLionel Sambuc 			kcm_operation opcode,
489ebfedea0SLionel Sambuc 			krb5_storage *request,
490ebfedea0SLionel Sambuc 			krb5_storage *response)
491ebfedea0SLionel Sambuc {
492ebfedea0SLionel Sambuc     krb5_error_code ret;
493ebfedea0SLionel Sambuc     kcm_ccache ccache;
494ebfedea0SLionel Sambuc     char *name;
495ebfedea0SLionel Sambuc     struct kcm_creds *c;
496ebfedea0SLionel Sambuc     kcmuuid_t uuid;
497ebfedea0SLionel Sambuc     ssize_t sret;
498ebfedea0SLionel Sambuc 
499ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
500ebfedea0SLionel Sambuc     if (ret)
501ebfedea0SLionel Sambuc 	return ret;
502ebfedea0SLionel Sambuc 
503ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
504ebfedea0SLionel Sambuc 
505ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
506ebfedea0SLionel Sambuc 				    name, &ccache);
507ebfedea0SLionel Sambuc     free(name);
508ebfedea0SLionel Sambuc     if (ret)
509ebfedea0SLionel Sambuc 	return ret;
510ebfedea0SLionel Sambuc 
511ebfedea0SLionel Sambuc     sret = krb5_storage_read(request, &uuid, sizeof(uuid));
512ebfedea0SLionel Sambuc     if (sret != sizeof(uuid)) {
513ebfedea0SLionel Sambuc 	kcm_release_ccache(context, ccache);
514ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
515ebfedea0SLionel Sambuc 	return KRB5_CC_IO;
516ebfedea0SLionel Sambuc     }
517ebfedea0SLionel Sambuc 
518ebfedea0SLionel Sambuc     c = kcm_ccache_find_cred_uuid(context, ccache, uuid);
519ebfedea0SLionel Sambuc     if (c == NULL) {
520ebfedea0SLionel Sambuc 	kcm_release_ccache(context, ccache);
521ebfedea0SLionel Sambuc 	return KRB5_CC_END;
522ebfedea0SLionel Sambuc     }
523ebfedea0SLionel Sambuc 
524ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_lock(&ccache->mutex);
525ebfedea0SLionel Sambuc     ret = krb5_store_creds(response, &c->cred);
526ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_unlock(&ccache->mutex);
527ebfedea0SLionel Sambuc 
528ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
529ebfedea0SLionel Sambuc 
530ebfedea0SLionel Sambuc     return ret;
531ebfedea0SLionel Sambuc }
532ebfedea0SLionel Sambuc 
533ebfedea0SLionel Sambuc /*
534ebfedea0SLionel Sambuc  * Request:
535ebfedea0SLionel Sambuc  *	NameZ
536ebfedea0SLionel Sambuc  *	WhichFields
537ebfedea0SLionel Sambuc  *	MatchCreds
538ebfedea0SLionel Sambuc  *
539ebfedea0SLionel Sambuc  * Response:
540ebfedea0SLionel Sambuc  *
541ebfedea0SLionel Sambuc  */
542ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_remove_cred(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)543ebfedea0SLionel Sambuc kcm_op_remove_cred(krb5_context context,
544ebfedea0SLionel Sambuc 		   kcm_client *client,
545ebfedea0SLionel Sambuc 		   kcm_operation opcode,
546ebfedea0SLionel Sambuc 		   krb5_storage *request,
547ebfedea0SLionel Sambuc 		   krb5_storage *response)
548ebfedea0SLionel Sambuc {
549ebfedea0SLionel Sambuc     uint32_t whichfields;
550ebfedea0SLionel Sambuc     krb5_creds mcreds;
551ebfedea0SLionel Sambuc     krb5_error_code ret;
552ebfedea0SLionel Sambuc     kcm_ccache ccache;
553ebfedea0SLionel Sambuc     char *name;
554ebfedea0SLionel Sambuc 
555ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
556ebfedea0SLionel Sambuc     if (ret)
557ebfedea0SLionel Sambuc 	return ret;
558ebfedea0SLionel Sambuc 
559ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
560ebfedea0SLionel Sambuc 
561ebfedea0SLionel Sambuc     ret = krb5_ret_uint32(request, &whichfields);
562ebfedea0SLionel Sambuc     if (ret) {
563ebfedea0SLionel Sambuc 	free(name);
564ebfedea0SLionel Sambuc 	return ret;
565ebfedea0SLionel Sambuc     }
566ebfedea0SLionel Sambuc 
567ebfedea0SLionel Sambuc     ret = krb5_ret_creds_tag(request, &mcreds);
568ebfedea0SLionel Sambuc     if (ret) {
569ebfedea0SLionel Sambuc 	free(name);
570ebfedea0SLionel Sambuc 	return ret;
571ebfedea0SLionel Sambuc     }
572ebfedea0SLionel Sambuc 
573ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
574ebfedea0SLionel Sambuc 				    name, &ccache);
575ebfedea0SLionel Sambuc     if (ret) {
576ebfedea0SLionel Sambuc 	free(name);
577ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, &mcreds);
578ebfedea0SLionel Sambuc 	return ret;
579ebfedea0SLionel Sambuc     }
580ebfedea0SLionel Sambuc 
581ebfedea0SLionel Sambuc     ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds);
582ebfedea0SLionel Sambuc 
583ebfedea0SLionel Sambuc     /* XXX need to remove any events that match */
584ebfedea0SLionel Sambuc 
585ebfedea0SLionel Sambuc     free(name);
586ebfedea0SLionel Sambuc     krb5_free_cred_contents(context, &mcreds);
587ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
588ebfedea0SLionel Sambuc 
589ebfedea0SLionel Sambuc     return ret;
590ebfedea0SLionel Sambuc }
591ebfedea0SLionel Sambuc 
592ebfedea0SLionel Sambuc /*
593ebfedea0SLionel Sambuc  * Request:
594ebfedea0SLionel Sambuc  *	NameZ
595ebfedea0SLionel Sambuc  *	Flags
596ebfedea0SLionel Sambuc  *
597ebfedea0SLionel Sambuc  * Response:
598ebfedea0SLionel Sambuc  *
599ebfedea0SLionel Sambuc  */
600ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_set_flags(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)601ebfedea0SLionel Sambuc kcm_op_set_flags(krb5_context context,
602ebfedea0SLionel Sambuc 		 kcm_client *client,
603ebfedea0SLionel Sambuc 		 kcm_operation opcode,
604ebfedea0SLionel Sambuc 		 krb5_storage *request,
605ebfedea0SLionel Sambuc 		 krb5_storage *response)
606ebfedea0SLionel Sambuc {
607ebfedea0SLionel Sambuc     uint32_t flags;
608ebfedea0SLionel Sambuc     krb5_error_code ret;
609ebfedea0SLionel Sambuc     kcm_ccache ccache;
610ebfedea0SLionel Sambuc     char *name;
611ebfedea0SLionel Sambuc 
612ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
613ebfedea0SLionel Sambuc     if (ret)
614ebfedea0SLionel Sambuc 	return ret;
615ebfedea0SLionel Sambuc 
616ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
617ebfedea0SLionel Sambuc 
618ebfedea0SLionel Sambuc     ret = krb5_ret_uint32(request, &flags);
619ebfedea0SLionel Sambuc     if (ret) {
620ebfedea0SLionel Sambuc 	free(name);
621ebfedea0SLionel Sambuc 	return ret;
622ebfedea0SLionel Sambuc     }
623ebfedea0SLionel Sambuc 
624ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
625ebfedea0SLionel Sambuc 				    name, &ccache);
626ebfedea0SLionel Sambuc     if (ret) {
627ebfedea0SLionel Sambuc 	free(name);
628ebfedea0SLionel Sambuc 	return ret;
629ebfedea0SLionel Sambuc     }
630ebfedea0SLionel Sambuc 
631ebfedea0SLionel Sambuc     /* we don't really support any flags yet */
632ebfedea0SLionel Sambuc     free(name);
633ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
634ebfedea0SLionel Sambuc 
635ebfedea0SLionel Sambuc     return 0;
636ebfedea0SLionel Sambuc }
637ebfedea0SLionel Sambuc 
638ebfedea0SLionel Sambuc /*
639ebfedea0SLionel Sambuc  * Request:
640ebfedea0SLionel Sambuc  *	NameZ
641ebfedea0SLionel Sambuc  *	UID
642ebfedea0SLionel Sambuc  *	GID
643ebfedea0SLionel Sambuc  *
644ebfedea0SLionel Sambuc  * Response:
645ebfedea0SLionel Sambuc  *
646ebfedea0SLionel Sambuc  */
647ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_chown(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)648ebfedea0SLionel Sambuc kcm_op_chown(krb5_context context,
649ebfedea0SLionel Sambuc 	     kcm_client *client,
650ebfedea0SLionel Sambuc 	     kcm_operation opcode,
651ebfedea0SLionel Sambuc 	     krb5_storage *request,
652ebfedea0SLionel Sambuc 	     krb5_storage *response)
653ebfedea0SLionel Sambuc {
654ebfedea0SLionel Sambuc     uint32_t uid;
655ebfedea0SLionel Sambuc     uint32_t gid;
656ebfedea0SLionel Sambuc     krb5_error_code ret;
657ebfedea0SLionel Sambuc     kcm_ccache ccache;
658ebfedea0SLionel Sambuc     char *name;
659ebfedea0SLionel Sambuc 
660ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
661ebfedea0SLionel Sambuc     if (ret)
662ebfedea0SLionel Sambuc 	return ret;
663ebfedea0SLionel Sambuc 
664ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
665ebfedea0SLionel Sambuc 
666ebfedea0SLionel Sambuc     ret = krb5_ret_uint32(request, &uid);
667ebfedea0SLionel Sambuc     if (ret) {
668ebfedea0SLionel Sambuc 	free(name);
669ebfedea0SLionel Sambuc 	return ret;
670ebfedea0SLionel Sambuc     }
671ebfedea0SLionel Sambuc 
672ebfedea0SLionel Sambuc     ret = krb5_ret_uint32(request, &gid);
673ebfedea0SLionel Sambuc     if (ret) {
674ebfedea0SLionel Sambuc 	free(name);
675ebfedea0SLionel Sambuc 	return ret;
676ebfedea0SLionel Sambuc     }
677ebfedea0SLionel Sambuc 
678ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
679ebfedea0SLionel Sambuc 				    name, &ccache);
680ebfedea0SLionel Sambuc     if (ret) {
681ebfedea0SLionel Sambuc 	free(name);
682ebfedea0SLionel Sambuc 	return ret;
683ebfedea0SLionel Sambuc     }
684ebfedea0SLionel Sambuc 
685ebfedea0SLionel Sambuc     ret = kcm_chown(context, client, ccache, uid, gid);
686ebfedea0SLionel Sambuc 
687ebfedea0SLionel Sambuc     free(name);
688ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
689ebfedea0SLionel Sambuc 
690ebfedea0SLionel Sambuc     return ret;
691ebfedea0SLionel Sambuc }
692ebfedea0SLionel Sambuc 
693ebfedea0SLionel Sambuc /*
694ebfedea0SLionel Sambuc  * Request:
695ebfedea0SLionel Sambuc  *	NameZ
696ebfedea0SLionel Sambuc  *	Mode
697ebfedea0SLionel Sambuc  *
698ebfedea0SLionel Sambuc  * Response:
699ebfedea0SLionel Sambuc  *
700ebfedea0SLionel Sambuc  */
701ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_chmod(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)702ebfedea0SLionel Sambuc kcm_op_chmod(krb5_context context,
703ebfedea0SLionel Sambuc 	     kcm_client *client,
704ebfedea0SLionel Sambuc 	     kcm_operation opcode,
705ebfedea0SLionel Sambuc 	     krb5_storage *request,
706ebfedea0SLionel Sambuc 	     krb5_storage *response)
707ebfedea0SLionel Sambuc {
708ebfedea0SLionel Sambuc     uint16_t mode;
709ebfedea0SLionel Sambuc     krb5_error_code ret;
710ebfedea0SLionel Sambuc     kcm_ccache ccache;
711ebfedea0SLionel Sambuc     char *name;
712ebfedea0SLionel Sambuc 
713ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
714ebfedea0SLionel Sambuc     if (ret)
715ebfedea0SLionel Sambuc 	return ret;
716ebfedea0SLionel Sambuc 
717ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
718ebfedea0SLionel Sambuc 
719ebfedea0SLionel Sambuc     ret = krb5_ret_uint16(request, &mode);
720ebfedea0SLionel Sambuc     if (ret) {
721ebfedea0SLionel Sambuc 	free(name);
722ebfedea0SLionel Sambuc 	return ret;
723ebfedea0SLionel Sambuc     }
724ebfedea0SLionel Sambuc 
725ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
726ebfedea0SLionel Sambuc 				    name, &ccache);
727ebfedea0SLionel Sambuc     if (ret) {
728ebfedea0SLionel Sambuc 	free(name);
729ebfedea0SLionel Sambuc 	return ret;
730ebfedea0SLionel Sambuc     }
731ebfedea0SLionel Sambuc 
732ebfedea0SLionel Sambuc     ret = kcm_chmod(context, client, ccache, mode);
733ebfedea0SLionel Sambuc 
734ebfedea0SLionel Sambuc     free(name);
735ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
736ebfedea0SLionel Sambuc 
737ebfedea0SLionel Sambuc     return ret;
738ebfedea0SLionel Sambuc }
739ebfedea0SLionel Sambuc 
740ebfedea0SLionel Sambuc /*
741ebfedea0SLionel Sambuc  * Protocol extensions for moving ticket acquisition responsibility
742ebfedea0SLionel Sambuc  * from client to KCM follow.
743ebfedea0SLionel Sambuc  */
744ebfedea0SLionel Sambuc 
745ebfedea0SLionel Sambuc /*
746ebfedea0SLionel Sambuc  * Request:
747ebfedea0SLionel Sambuc  *	NameZ
748ebfedea0SLionel Sambuc  *	ServerPrincipalPresent
749ebfedea0SLionel Sambuc  *	ServerPrincipal OPTIONAL
750ebfedea0SLionel Sambuc  *	Key
751ebfedea0SLionel Sambuc  *
752ebfedea0SLionel Sambuc  * Repsonse:
753ebfedea0SLionel Sambuc  *
754ebfedea0SLionel Sambuc  */
755ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_initial_ticket(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)756ebfedea0SLionel Sambuc kcm_op_get_initial_ticket(krb5_context context,
757ebfedea0SLionel Sambuc 			  kcm_client *client,
758ebfedea0SLionel Sambuc 			  kcm_operation opcode,
759ebfedea0SLionel Sambuc 			  krb5_storage *request,
760ebfedea0SLionel Sambuc 			  krb5_storage *response)
761ebfedea0SLionel Sambuc {
762ebfedea0SLionel Sambuc     krb5_error_code ret;
763ebfedea0SLionel Sambuc     kcm_ccache ccache;
764ebfedea0SLionel Sambuc     char *name;
765ebfedea0SLionel Sambuc     int8_t not_tgt = 0;
766ebfedea0SLionel Sambuc     krb5_principal server = NULL;
767ebfedea0SLionel Sambuc     krb5_keyblock key;
768ebfedea0SLionel Sambuc 
769ebfedea0SLionel Sambuc     krb5_keyblock_zero(&key);
770ebfedea0SLionel Sambuc 
771ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
772ebfedea0SLionel Sambuc     if (ret)
773ebfedea0SLionel Sambuc 	return ret;
774ebfedea0SLionel Sambuc 
775ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
776ebfedea0SLionel Sambuc 
777ebfedea0SLionel Sambuc     ret = krb5_ret_int8(request, &not_tgt);
778ebfedea0SLionel Sambuc     if (ret) {
779ebfedea0SLionel Sambuc 	free(name);
780ebfedea0SLionel Sambuc 	return ret;
781ebfedea0SLionel Sambuc     }
782ebfedea0SLionel Sambuc 
783ebfedea0SLionel Sambuc     if (not_tgt) {
784ebfedea0SLionel Sambuc 	ret = krb5_ret_principal(request, &server);
785ebfedea0SLionel Sambuc 	if (ret) {
786ebfedea0SLionel Sambuc 	    free(name);
787ebfedea0SLionel Sambuc 	    return ret;
788ebfedea0SLionel Sambuc 	}
789ebfedea0SLionel Sambuc     }
790ebfedea0SLionel Sambuc 
791ebfedea0SLionel Sambuc     ret = krb5_ret_keyblock(request, &key);
792ebfedea0SLionel Sambuc     if (ret) {
793ebfedea0SLionel Sambuc 	free(name);
794ebfedea0SLionel Sambuc 	if (server != NULL)
795ebfedea0SLionel Sambuc 	    krb5_free_principal(context, server);
796ebfedea0SLionel Sambuc 	return ret;
797ebfedea0SLionel Sambuc     }
798ebfedea0SLionel Sambuc 
799ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
800ebfedea0SLionel Sambuc 				    name, &ccache);
801ebfedea0SLionel Sambuc     if (ret == 0) {
802ebfedea0SLionel Sambuc 	HEIMDAL_MUTEX_lock(&ccache->mutex);
803ebfedea0SLionel Sambuc 
804ebfedea0SLionel Sambuc 	if (ccache->server != NULL) {
805ebfedea0SLionel Sambuc 	    krb5_free_principal(context, ccache->server);
806ebfedea0SLionel Sambuc 	    ccache->server = NULL;
807ebfedea0SLionel Sambuc 	}
808ebfedea0SLionel Sambuc 
809ebfedea0SLionel Sambuc 	krb5_free_keyblock(context, &ccache->key.keyblock);
810ebfedea0SLionel Sambuc 
811ebfedea0SLionel Sambuc 	ccache->server = server;
812ebfedea0SLionel Sambuc 	ccache->key.keyblock = key;
813ebfedea0SLionel Sambuc     	ccache->flags |= KCM_FLAGS_USE_CACHED_KEY;
814ebfedea0SLionel Sambuc 
815ebfedea0SLionel Sambuc 	ret = kcm_ccache_enqueue_default(context, ccache, NULL);
816ebfedea0SLionel Sambuc 	if (ret) {
817ebfedea0SLionel Sambuc 	    ccache->server = NULL;
818ebfedea0SLionel Sambuc 	    krb5_keyblock_zero(&ccache->key.keyblock);
819ebfedea0SLionel Sambuc 	    ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY);
820ebfedea0SLionel Sambuc 	}
821ebfedea0SLionel Sambuc 
822ebfedea0SLionel Sambuc 	HEIMDAL_MUTEX_unlock(&ccache->mutex);
823ebfedea0SLionel Sambuc     }
824ebfedea0SLionel Sambuc 
825ebfedea0SLionel Sambuc     free(name);
826ebfedea0SLionel Sambuc 
827ebfedea0SLionel Sambuc     if (ret != 0) {
828ebfedea0SLionel Sambuc 	krb5_free_principal(context, server);
829ebfedea0SLionel Sambuc 	krb5_free_keyblock(context, &key);
830ebfedea0SLionel Sambuc     }
831ebfedea0SLionel Sambuc 
832ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
833ebfedea0SLionel Sambuc 
834ebfedea0SLionel Sambuc     return ret;
835ebfedea0SLionel Sambuc }
836ebfedea0SLionel Sambuc 
837ebfedea0SLionel Sambuc /*
838ebfedea0SLionel Sambuc  * Request:
839ebfedea0SLionel Sambuc  *	NameZ
840ebfedea0SLionel Sambuc  *	ServerPrincipal
841ebfedea0SLionel Sambuc  *	KDCFlags
842ebfedea0SLionel Sambuc  *	EncryptionType
843ebfedea0SLionel Sambuc  *
844ebfedea0SLionel Sambuc  * Repsonse:
845ebfedea0SLionel Sambuc  *
846ebfedea0SLionel Sambuc  */
847ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_ticket(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)848ebfedea0SLionel Sambuc kcm_op_get_ticket(krb5_context context,
849ebfedea0SLionel Sambuc 		  kcm_client *client,
850ebfedea0SLionel Sambuc 		  kcm_operation opcode,
851ebfedea0SLionel Sambuc 		  krb5_storage *request,
852ebfedea0SLionel Sambuc 		  krb5_storage *response)
853ebfedea0SLionel Sambuc {
854ebfedea0SLionel Sambuc     krb5_error_code ret;
855ebfedea0SLionel Sambuc     kcm_ccache ccache;
856ebfedea0SLionel Sambuc     char *name;
857ebfedea0SLionel Sambuc     krb5_principal server = NULL;
858ebfedea0SLionel Sambuc     krb5_ccache_data ccdata;
859ebfedea0SLionel Sambuc     krb5_creds in, *out;
860ebfedea0SLionel Sambuc     krb5_kdc_flags flags;
861ebfedea0SLionel Sambuc 
862ebfedea0SLionel Sambuc     memset(&in, 0, sizeof(in));
863ebfedea0SLionel Sambuc 
864ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
865ebfedea0SLionel Sambuc     if (ret)
866ebfedea0SLionel Sambuc 	return ret;
867ebfedea0SLionel Sambuc 
868ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
869ebfedea0SLionel Sambuc 
870ebfedea0SLionel Sambuc     ret = krb5_ret_uint32(request, &flags.i);
871ebfedea0SLionel Sambuc     if (ret) {
872ebfedea0SLionel Sambuc 	free(name);
873ebfedea0SLionel Sambuc 	return ret;
874ebfedea0SLionel Sambuc     }
875ebfedea0SLionel Sambuc 
876ebfedea0SLionel Sambuc     ret = krb5_ret_int32(request, &in.session.keytype);
877ebfedea0SLionel Sambuc     if (ret) {
878ebfedea0SLionel Sambuc 	free(name);
879ebfedea0SLionel Sambuc 	return ret;
880ebfedea0SLionel Sambuc     }
881ebfedea0SLionel Sambuc 
882ebfedea0SLionel Sambuc     ret = krb5_ret_principal(request, &server);
883ebfedea0SLionel Sambuc     if (ret) {
884ebfedea0SLionel Sambuc 	free(name);
885ebfedea0SLionel Sambuc 	return ret;
886ebfedea0SLionel Sambuc     }
887ebfedea0SLionel Sambuc 
888ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode,
889ebfedea0SLionel Sambuc 				    name, &ccache);
890ebfedea0SLionel Sambuc     if (ret) {
891ebfedea0SLionel Sambuc 	krb5_free_principal(context, server);
892ebfedea0SLionel Sambuc 	free(name);
893ebfedea0SLionel Sambuc 	return ret;
894ebfedea0SLionel Sambuc     }
895ebfedea0SLionel Sambuc 
896ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_lock(&ccache->mutex);
897ebfedea0SLionel Sambuc 
898ebfedea0SLionel Sambuc     /* Fake up an internal ccache */
899ebfedea0SLionel Sambuc     kcm_internal_ccache(context, ccache, &ccdata);
900ebfedea0SLionel Sambuc 
901ebfedea0SLionel Sambuc     in.client = ccache->client;
902ebfedea0SLionel Sambuc     in.server = server;
903ebfedea0SLionel Sambuc     in.times.endtime = 0;
904ebfedea0SLionel Sambuc 
905ebfedea0SLionel Sambuc     /* glue cc layer will store creds */
906ebfedea0SLionel Sambuc     ret = krb5_get_credentials_with_flags(context, 0, flags,
907ebfedea0SLionel Sambuc 					  &ccdata, &in, &out);
908ebfedea0SLionel Sambuc 
909ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_unlock(&ccache->mutex);
910ebfedea0SLionel Sambuc 
911ebfedea0SLionel Sambuc     krb5_free_principal(context, server);
912ebfedea0SLionel Sambuc 
913ebfedea0SLionel Sambuc     if (ret == 0)
914ebfedea0SLionel Sambuc 	krb5_free_cred_contents(context, out);
915ebfedea0SLionel Sambuc 
916ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
917ebfedea0SLionel Sambuc     free(name);
918ebfedea0SLionel Sambuc 
919ebfedea0SLionel Sambuc     return ret;
920ebfedea0SLionel Sambuc }
921ebfedea0SLionel Sambuc 
922ebfedea0SLionel Sambuc /*
923ebfedea0SLionel Sambuc  * Request:
924ebfedea0SLionel Sambuc  *	OldNameZ
925ebfedea0SLionel Sambuc  *	NewNameZ
926ebfedea0SLionel Sambuc  *
927ebfedea0SLionel Sambuc  * Repsonse:
928ebfedea0SLionel Sambuc  *
929ebfedea0SLionel Sambuc  */
930ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_move_cache(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)931ebfedea0SLionel Sambuc kcm_op_move_cache(krb5_context context,
932ebfedea0SLionel Sambuc 		  kcm_client *client,
933ebfedea0SLionel Sambuc 		  kcm_operation opcode,
934ebfedea0SLionel Sambuc 		  krb5_storage *request,
935ebfedea0SLionel Sambuc 		  krb5_storage *response)
936ebfedea0SLionel Sambuc {
937ebfedea0SLionel Sambuc     krb5_error_code ret;
938ebfedea0SLionel Sambuc     kcm_ccache oldid, newid;
939ebfedea0SLionel Sambuc     char *oldname, *newname;
940ebfedea0SLionel Sambuc 
941ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &oldname);
942ebfedea0SLionel Sambuc     if (ret)
943ebfedea0SLionel Sambuc 	return ret;
944ebfedea0SLionel Sambuc 
945ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, oldname);
946ebfedea0SLionel Sambuc 
947ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &newname);
948ebfedea0SLionel Sambuc     if (ret) {
949ebfedea0SLionel Sambuc 	free(oldname);
950ebfedea0SLionel Sambuc 	return ret;
951ebfedea0SLionel Sambuc     }
952ebfedea0SLionel Sambuc 
953ebfedea0SLionel Sambuc     /* move to ourself is simple, done! */
954ebfedea0SLionel Sambuc     if (strcmp(oldname, newname) == 0) {
955ebfedea0SLionel Sambuc 	free(oldname);
956ebfedea0SLionel Sambuc 	free(newname);
957ebfedea0SLionel Sambuc 	return 0;
958ebfedea0SLionel Sambuc     }
959ebfedea0SLionel Sambuc 
960ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid);
961ebfedea0SLionel Sambuc     if (ret) {
962ebfedea0SLionel Sambuc 	free(oldname);
963ebfedea0SLionel Sambuc 	free(newname);
964ebfedea0SLionel Sambuc 	return ret;
965ebfedea0SLionel Sambuc     }
966ebfedea0SLionel Sambuc 
967ebfedea0SLionel Sambuc     /* Check if new credential cache exists, if not create one. */
968ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode, newname, &newid);
969ebfedea0SLionel Sambuc     if (ret == KRB5_FCC_NOFILE)
970ebfedea0SLionel Sambuc 	ret = kcm_ccache_new_client(context, client, newname, &newid);
971ebfedea0SLionel Sambuc     free(newname);
972ebfedea0SLionel Sambuc 
973ebfedea0SLionel Sambuc     if (ret) {
974ebfedea0SLionel Sambuc 	free(oldname);
975ebfedea0SLionel Sambuc 	kcm_release_ccache(context, oldid);
976ebfedea0SLionel Sambuc 	return ret;
977ebfedea0SLionel Sambuc     }
978ebfedea0SLionel Sambuc 
979ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_lock(&oldid->mutex);
980ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_lock(&newid->mutex);
981ebfedea0SLionel Sambuc 
982ebfedea0SLionel Sambuc     /* move content */
983ebfedea0SLionel Sambuc     {
984ebfedea0SLionel Sambuc 	kcm_ccache_data tmp;
985ebfedea0SLionel Sambuc 
986ebfedea0SLionel Sambuc #define MOVE(n,o,f) { tmp.f = n->f ; n->f = o->f; o->f = tmp.f; }
987ebfedea0SLionel Sambuc 
988ebfedea0SLionel Sambuc 	MOVE(newid, oldid, flags);
989ebfedea0SLionel Sambuc 	MOVE(newid, oldid, client);
990ebfedea0SLionel Sambuc 	MOVE(newid, oldid, server);
991ebfedea0SLionel Sambuc 	MOVE(newid, oldid, creds);
992ebfedea0SLionel Sambuc 	MOVE(newid, oldid, tkt_life);
993ebfedea0SLionel Sambuc 	MOVE(newid, oldid, renew_life);
994ebfedea0SLionel Sambuc 	MOVE(newid, oldid, key);
995ebfedea0SLionel Sambuc 	MOVE(newid, oldid, kdc_offset);
996ebfedea0SLionel Sambuc #undef MOVE
997ebfedea0SLionel Sambuc     }
998ebfedea0SLionel Sambuc 
999ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_unlock(&oldid->mutex);
1000ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_unlock(&newid->mutex);
1001ebfedea0SLionel Sambuc 
1002ebfedea0SLionel Sambuc     kcm_release_ccache(context, oldid);
1003ebfedea0SLionel Sambuc     kcm_release_ccache(context, newid);
1004ebfedea0SLionel Sambuc 
1005ebfedea0SLionel Sambuc     ret = kcm_ccache_destroy_client(context, client, oldname);
1006ebfedea0SLionel Sambuc     if (ret == 0)
1007ebfedea0SLionel Sambuc 	kcm_drop_default_cache(context, client, oldname);
1008ebfedea0SLionel Sambuc 
1009ebfedea0SLionel Sambuc     free(oldname);
1010ebfedea0SLionel Sambuc 
1011ebfedea0SLionel Sambuc     return ret;
1012ebfedea0SLionel Sambuc }
1013ebfedea0SLionel Sambuc 
1014ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_cache_uuid_list(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1015ebfedea0SLionel Sambuc kcm_op_get_cache_uuid_list(krb5_context context,
1016ebfedea0SLionel Sambuc 			   kcm_client *client,
1017ebfedea0SLionel Sambuc 			   kcm_operation opcode,
1018ebfedea0SLionel Sambuc 			   krb5_storage *request,
1019ebfedea0SLionel Sambuc 			   krb5_storage *response)
1020ebfedea0SLionel Sambuc {
1021ebfedea0SLionel Sambuc     KCM_LOG_REQUEST(context, client, opcode);
1022ebfedea0SLionel Sambuc 
1023ebfedea0SLionel Sambuc     return kcm_ccache_get_uuids(context, client, opcode, response);
1024ebfedea0SLionel Sambuc }
1025ebfedea0SLionel Sambuc 
1026ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_cache_by_uuid(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1027ebfedea0SLionel Sambuc kcm_op_get_cache_by_uuid(krb5_context context,
1028ebfedea0SLionel Sambuc 			 kcm_client *client,
1029ebfedea0SLionel Sambuc 			 kcm_operation opcode,
1030ebfedea0SLionel Sambuc 			 krb5_storage *request,
1031ebfedea0SLionel Sambuc 			 krb5_storage *response)
1032ebfedea0SLionel Sambuc {
1033ebfedea0SLionel Sambuc     krb5_error_code ret;
1034ebfedea0SLionel Sambuc     kcmuuid_t uuid;
1035ebfedea0SLionel Sambuc     ssize_t sret;
1036ebfedea0SLionel Sambuc     kcm_ccache cache;
1037ebfedea0SLionel Sambuc 
1038ebfedea0SLionel Sambuc     KCM_LOG_REQUEST(context, client, opcode);
1039ebfedea0SLionel Sambuc 
1040ebfedea0SLionel Sambuc     sret = krb5_storage_read(request, &uuid, sizeof(uuid));
1041ebfedea0SLionel Sambuc     if (sret != sizeof(uuid)) {
1042ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
1043ebfedea0SLionel Sambuc 	return KRB5_CC_IO;
1044ebfedea0SLionel Sambuc     }
1045ebfedea0SLionel Sambuc 
1046ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_by_uuid(context, uuid, &cache);
1047ebfedea0SLionel Sambuc     if (ret)
1048ebfedea0SLionel Sambuc 	return ret;
1049ebfedea0SLionel Sambuc 
1050ebfedea0SLionel Sambuc     ret = kcm_access(context, client, opcode, cache);
1051ebfedea0SLionel Sambuc     if (ret)
1052ebfedea0SLionel Sambuc 	ret = KRB5_FCC_NOFILE;
1053ebfedea0SLionel Sambuc 
1054ebfedea0SLionel Sambuc     if (ret == 0)
1055ebfedea0SLionel Sambuc 	ret = krb5_store_stringz(response, cache->name);
1056ebfedea0SLionel Sambuc 
1057ebfedea0SLionel Sambuc     kcm_release_ccache(context, cache);
1058ebfedea0SLionel Sambuc 
1059ebfedea0SLionel Sambuc     return ret;
1060ebfedea0SLionel Sambuc }
1061ebfedea0SLionel Sambuc 
1062ebfedea0SLionel Sambuc struct kcm_default_cache *default_caches;
1063ebfedea0SLionel Sambuc 
1064ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_default_cache(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1065ebfedea0SLionel Sambuc kcm_op_get_default_cache(krb5_context context,
1066ebfedea0SLionel Sambuc 			 kcm_client *client,
1067ebfedea0SLionel Sambuc 			 kcm_operation opcode,
1068ebfedea0SLionel Sambuc 			 krb5_storage *request,
1069ebfedea0SLionel Sambuc 			 krb5_storage *response)
1070ebfedea0SLionel Sambuc {
1071ebfedea0SLionel Sambuc     struct kcm_default_cache *c;
1072ebfedea0SLionel Sambuc     krb5_error_code ret;
1073ebfedea0SLionel Sambuc     const char *name = NULL;
1074ebfedea0SLionel Sambuc     char *n = NULL;
1075ebfedea0SLionel Sambuc 
1076ebfedea0SLionel Sambuc     KCM_LOG_REQUEST(context, client, opcode);
1077ebfedea0SLionel Sambuc 
1078ebfedea0SLionel Sambuc     for (c = default_caches; c != NULL; c = c->next) {
1079ebfedea0SLionel Sambuc 	if (kcm_is_same_session(client, c->uid, c->session)) {
1080ebfedea0SLionel Sambuc 	    name = c->name;
1081ebfedea0SLionel Sambuc 	    break;
1082ebfedea0SLionel Sambuc 	}
1083ebfedea0SLionel Sambuc     }
1084ebfedea0SLionel Sambuc     if (name == NULL)
1085ebfedea0SLionel Sambuc 	name = n = kcm_ccache_first_name(client);
1086ebfedea0SLionel Sambuc 
1087ebfedea0SLionel Sambuc     if (name == NULL) {
1088ebfedea0SLionel Sambuc 	asprintf(&n, "%d", (int)client->uid);
1089ebfedea0SLionel Sambuc 	name = n;
1090ebfedea0SLionel Sambuc     }
1091ebfedea0SLionel Sambuc     if (name == NULL)
1092ebfedea0SLionel Sambuc 	return ENOMEM;
1093ebfedea0SLionel Sambuc     ret = krb5_store_stringz(response, name);
1094ebfedea0SLionel Sambuc     if (n)
1095ebfedea0SLionel Sambuc 	free(n);
1096ebfedea0SLionel Sambuc     return ret;
1097ebfedea0SLionel Sambuc }
1098ebfedea0SLionel Sambuc 
1099ebfedea0SLionel Sambuc static void
kcm_drop_default_cache(krb5_context context,kcm_client * client,char * name)1100ebfedea0SLionel Sambuc kcm_drop_default_cache(krb5_context context, kcm_client *client, char *name)
1101ebfedea0SLionel Sambuc {
1102ebfedea0SLionel Sambuc     struct kcm_default_cache **c;
1103ebfedea0SLionel Sambuc 
1104ebfedea0SLionel Sambuc     for (c = &default_caches; *c != NULL; c = &(*c)->next) {
1105ebfedea0SLionel Sambuc 	if (!kcm_is_same_session(client, (*c)->uid, (*c)->session))
1106ebfedea0SLionel Sambuc 	    continue;
1107ebfedea0SLionel Sambuc 	if (strcmp((*c)->name, name) == 0) {
1108ebfedea0SLionel Sambuc 	    struct kcm_default_cache *h = *c;
1109ebfedea0SLionel Sambuc 	    *c = (*c)->next;
1110ebfedea0SLionel Sambuc 	    free(h->name);
1111ebfedea0SLionel Sambuc 	    free(h);
1112ebfedea0SLionel Sambuc 	    break;
1113ebfedea0SLionel Sambuc 	}
1114ebfedea0SLionel Sambuc     }
1115ebfedea0SLionel Sambuc }
1116ebfedea0SLionel Sambuc 
1117ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_set_default_cache(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1118ebfedea0SLionel Sambuc kcm_op_set_default_cache(krb5_context context,
1119ebfedea0SLionel Sambuc 			 kcm_client *client,
1120ebfedea0SLionel Sambuc 			 kcm_operation opcode,
1121ebfedea0SLionel Sambuc 			 krb5_storage *request,
1122ebfedea0SLionel Sambuc 			 krb5_storage *response)
1123ebfedea0SLionel Sambuc {
1124ebfedea0SLionel Sambuc     struct kcm_default_cache *c;
1125ebfedea0SLionel Sambuc     krb5_error_code ret;
1126ebfedea0SLionel Sambuc     char *name;
1127ebfedea0SLionel Sambuc 
1128ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
1129ebfedea0SLionel Sambuc     if (ret)
1130ebfedea0SLionel Sambuc 	return ret;
1131ebfedea0SLionel Sambuc 
1132ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
1133ebfedea0SLionel Sambuc 
1134ebfedea0SLionel Sambuc     for (c = default_caches; c != NULL; c = c->next) {
1135ebfedea0SLionel Sambuc 	if (kcm_is_same_session(client, c->uid, c->session))
1136ebfedea0SLionel Sambuc 	    break;
1137ebfedea0SLionel Sambuc     }
1138ebfedea0SLionel Sambuc     if (c == NULL) {
1139ebfedea0SLionel Sambuc 	c = malloc(sizeof(*c));
1140ebfedea0SLionel Sambuc 	if (c == NULL)
1141ebfedea0SLionel Sambuc 	    return ENOMEM;
1142ebfedea0SLionel Sambuc 	c->session = client->session;
1143ebfedea0SLionel Sambuc 	c->uid = client->uid;
1144ebfedea0SLionel Sambuc 	c->name = strdup(name);
1145ebfedea0SLionel Sambuc 
1146ebfedea0SLionel Sambuc 	c->next = default_caches;
1147ebfedea0SLionel Sambuc 	default_caches = c;
1148ebfedea0SLionel Sambuc     } else {
1149ebfedea0SLionel Sambuc 	free(c->name);
1150ebfedea0SLionel Sambuc 	c->name = strdup(name);
1151ebfedea0SLionel Sambuc     }
1152ebfedea0SLionel Sambuc 
1153ebfedea0SLionel Sambuc     return 0;
1154ebfedea0SLionel Sambuc }
1155ebfedea0SLionel Sambuc 
1156ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_kdc_offset(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1157ebfedea0SLionel Sambuc kcm_op_get_kdc_offset(krb5_context context,
1158ebfedea0SLionel Sambuc 		      kcm_client *client,
1159ebfedea0SLionel Sambuc 		      kcm_operation opcode,
1160ebfedea0SLionel Sambuc 		      krb5_storage *request,
1161ebfedea0SLionel Sambuc 		      krb5_storage *response)
1162ebfedea0SLionel Sambuc {
1163ebfedea0SLionel Sambuc     krb5_error_code ret;
1164ebfedea0SLionel Sambuc     kcm_ccache ccache;
1165ebfedea0SLionel Sambuc     char *name;
1166ebfedea0SLionel Sambuc 
1167ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
1168ebfedea0SLionel Sambuc     if (ret)
1169ebfedea0SLionel Sambuc 	return ret;
1170ebfedea0SLionel Sambuc 
1171ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
1172ebfedea0SLionel Sambuc 
1173ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache);
1174ebfedea0SLionel Sambuc     free(name);
1175ebfedea0SLionel Sambuc     if (ret)
1176ebfedea0SLionel Sambuc 	return ret;
1177ebfedea0SLionel Sambuc 
1178ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_lock(&ccache->mutex);
1179ebfedea0SLionel Sambuc     ret = krb5_store_int32(response, ccache->kdc_offset);
1180ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_unlock(&ccache->mutex);
1181ebfedea0SLionel Sambuc 
1182ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
1183ebfedea0SLionel Sambuc 
1184ebfedea0SLionel Sambuc     return ret;
1185ebfedea0SLionel Sambuc }
1186ebfedea0SLionel Sambuc 
1187ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_set_kdc_offset(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1188ebfedea0SLionel Sambuc kcm_op_set_kdc_offset(krb5_context context,
1189ebfedea0SLionel Sambuc 		      kcm_client *client,
1190ebfedea0SLionel Sambuc 		      kcm_operation opcode,
1191ebfedea0SLionel Sambuc 		      krb5_storage *request,
1192ebfedea0SLionel Sambuc 		      krb5_storage *response)
1193ebfedea0SLionel Sambuc {
1194ebfedea0SLionel Sambuc     krb5_error_code ret;
1195ebfedea0SLionel Sambuc     kcm_ccache ccache;
1196ebfedea0SLionel Sambuc     int32_t offset;
1197ebfedea0SLionel Sambuc     char *name;
1198ebfedea0SLionel Sambuc 
1199ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &name);
1200ebfedea0SLionel Sambuc     if (ret)
1201ebfedea0SLionel Sambuc 	return ret;
1202ebfedea0SLionel Sambuc 
1203ebfedea0SLionel Sambuc     KCM_LOG_REQUEST_NAME(context, client, opcode, name);
1204ebfedea0SLionel Sambuc 
1205ebfedea0SLionel Sambuc     ret = krb5_ret_int32(request, &offset);
1206ebfedea0SLionel Sambuc     if (ret) {
1207ebfedea0SLionel Sambuc 	free(name);
1208ebfedea0SLionel Sambuc 	return ret;
1209ebfedea0SLionel Sambuc     }
1210ebfedea0SLionel Sambuc 
1211ebfedea0SLionel Sambuc     ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache);
1212ebfedea0SLionel Sambuc     free(name);
1213ebfedea0SLionel Sambuc     if (ret)
1214ebfedea0SLionel Sambuc 	return ret;
1215ebfedea0SLionel Sambuc 
1216ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_lock(&ccache->mutex);
1217ebfedea0SLionel Sambuc     ccache->kdc_offset = offset;
1218ebfedea0SLionel Sambuc     HEIMDAL_MUTEX_unlock(&ccache->mutex);
1219ebfedea0SLionel Sambuc 
1220ebfedea0SLionel Sambuc     kcm_release_ccache(context, ccache);
1221ebfedea0SLionel Sambuc 
1222ebfedea0SLionel Sambuc     return ret;
1223ebfedea0SLionel Sambuc }
1224ebfedea0SLionel Sambuc 
1225ebfedea0SLionel Sambuc struct kcm_ntlm_cred {
1226ebfedea0SLionel Sambuc     kcmuuid_t uuid;
1227ebfedea0SLionel Sambuc     char *user;
1228ebfedea0SLionel Sambuc     char *domain;
1229ebfedea0SLionel Sambuc     krb5_data nthash;
1230ebfedea0SLionel Sambuc     uid_t uid;
1231ebfedea0SLionel Sambuc     pid_t session;
1232ebfedea0SLionel Sambuc     struct kcm_ntlm_cred *next;
1233ebfedea0SLionel Sambuc };
1234ebfedea0SLionel Sambuc 
1235ebfedea0SLionel Sambuc static struct kcm_ntlm_cred *ntlm_head;
1236ebfedea0SLionel Sambuc 
1237ebfedea0SLionel Sambuc static void
free_cred(struct kcm_ntlm_cred * cred)1238ebfedea0SLionel Sambuc free_cred(struct kcm_ntlm_cred *cred)
1239ebfedea0SLionel Sambuc {
1240ebfedea0SLionel Sambuc     free(cred->user);
1241ebfedea0SLionel Sambuc     free(cred->domain);
1242ebfedea0SLionel Sambuc     krb5_data_free(&cred->nthash);
1243ebfedea0SLionel Sambuc     free(cred);
1244ebfedea0SLionel Sambuc }
1245ebfedea0SLionel Sambuc 
1246ebfedea0SLionel Sambuc 
1247ebfedea0SLionel Sambuc /*
1248ebfedea0SLionel Sambuc  * name
1249ebfedea0SLionel Sambuc  * domain
1250ebfedea0SLionel Sambuc  * ntlm hash
1251ebfedea0SLionel Sambuc  *
1252ebfedea0SLionel Sambuc  * Reply:
1253ebfedea0SLionel Sambuc  *   uuid
1254ebfedea0SLionel Sambuc  */
1255ebfedea0SLionel Sambuc 
1256ebfedea0SLionel Sambuc static struct kcm_ntlm_cred *
find_ntlm_cred(const char * user,const char * domain,kcm_client * client)1257ebfedea0SLionel Sambuc find_ntlm_cred(const char *user, const char *domain, kcm_client *client)
1258ebfedea0SLionel Sambuc {
1259ebfedea0SLionel Sambuc     struct kcm_ntlm_cred *c;
1260ebfedea0SLionel Sambuc 
1261ebfedea0SLionel Sambuc     for (c = ntlm_head; c != NULL; c = c->next)
1262ebfedea0SLionel Sambuc 	if ((user[0] == '\0' || strcmp(user, c->user) == 0) &&
1263ebfedea0SLionel Sambuc 	    (domain == NULL || strcmp(domain, c->domain) == 0) &&
1264ebfedea0SLionel Sambuc 	    kcm_is_same_session(client, c->uid, c->session))
1265ebfedea0SLionel Sambuc 	    return c;
1266ebfedea0SLionel Sambuc 
1267ebfedea0SLionel Sambuc     return NULL;
1268ebfedea0SLionel Sambuc }
1269ebfedea0SLionel Sambuc 
1270ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_add_ntlm_cred(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1271ebfedea0SLionel Sambuc kcm_op_add_ntlm_cred(krb5_context context,
1272ebfedea0SLionel Sambuc 		     kcm_client *client,
1273ebfedea0SLionel Sambuc 		     kcm_operation opcode,
1274ebfedea0SLionel Sambuc 		     krb5_storage *request,
1275ebfedea0SLionel Sambuc 		     krb5_storage *response)
1276ebfedea0SLionel Sambuc {
1277ebfedea0SLionel Sambuc     struct kcm_ntlm_cred *cred, *c;
1278ebfedea0SLionel Sambuc     krb5_error_code ret;
1279ebfedea0SLionel Sambuc 
1280ebfedea0SLionel Sambuc     cred = calloc(1, sizeof(*cred));
1281ebfedea0SLionel Sambuc     if (cred == NULL)
1282ebfedea0SLionel Sambuc 	return ENOMEM;
1283ebfedea0SLionel Sambuc 
1284ebfedea0SLionel Sambuc     RAND_bytes(cred->uuid, sizeof(cred->uuid));
1285ebfedea0SLionel Sambuc 
1286ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &cred->user);
1287ebfedea0SLionel Sambuc     if (ret)
1288ebfedea0SLionel Sambuc 	goto error;
1289ebfedea0SLionel Sambuc 
1290ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &cred->domain);
1291ebfedea0SLionel Sambuc     if (ret)
1292ebfedea0SLionel Sambuc 	goto error;
1293ebfedea0SLionel Sambuc 
1294ebfedea0SLionel Sambuc     ret = krb5_ret_data(request, &cred->nthash);
1295ebfedea0SLionel Sambuc     if (ret)
1296ebfedea0SLionel Sambuc 	goto error;
1297ebfedea0SLionel Sambuc 
1298ebfedea0SLionel Sambuc     /* search for dups */
1299ebfedea0SLionel Sambuc     c = find_ntlm_cred(cred->user, cred->domain, client);
1300ebfedea0SLionel Sambuc     if (c) {
1301ebfedea0SLionel Sambuc 	krb5_data hash = c->nthash;
1302ebfedea0SLionel Sambuc 	c->nthash = cred->nthash;
1303ebfedea0SLionel Sambuc 	cred->nthash = hash;
1304ebfedea0SLionel Sambuc 	free_cred(cred);
1305ebfedea0SLionel Sambuc 	cred = c;
1306ebfedea0SLionel Sambuc     } else {
1307ebfedea0SLionel Sambuc 	cred->next = ntlm_head;
1308ebfedea0SLionel Sambuc 	ntlm_head = cred;
1309ebfedea0SLionel Sambuc     }
1310ebfedea0SLionel Sambuc 
1311ebfedea0SLionel Sambuc     cred->uid = client->uid;
1312ebfedea0SLionel Sambuc     cred->session = client->session;
1313ebfedea0SLionel Sambuc 
1314ebfedea0SLionel Sambuc     /* write response */
1315ebfedea0SLionel Sambuc     (void)krb5_storage_write(response, &cred->uuid, sizeof(cred->uuid));
1316ebfedea0SLionel Sambuc 
1317ebfedea0SLionel Sambuc     return 0;
1318ebfedea0SLionel Sambuc 
1319ebfedea0SLionel Sambuc  error:
1320ebfedea0SLionel Sambuc     free_cred(cred);
1321ebfedea0SLionel Sambuc 
1322ebfedea0SLionel Sambuc     return ret;
1323ebfedea0SLionel Sambuc }
1324ebfedea0SLionel Sambuc 
1325ebfedea0SLionel Sambuc /*
1326ebfedea0SLionel Sambuc  * { "HAVE_NTLM_CRED",		NULL },
1327ebfedea0SLionel Sambuc  *
1328ebfedea0SLionel Sambuc  * input:
1329ebfedea0SLionel Sambuc  *  name
1330ebfedea0SLionel Sambuc  *  domain
1331ebfedea0SLionel Sambuc  */
1332ebfedea0SLionel Sambuc 
1333ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_have_ntlm_cred(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1334ebfedea0SLionel Sambuc kcm_op_have_ntlm_cred(krb5_context context,
1335ebfedea0SLionel Sambuc 		     kcm_client *client,
1336ebfedea0SLionel Sambuc 		     kcm_operation opcode,
1337ebfedea0SLionel Sambuc 		     krb5_storage *request,
1338ebfedea0SLionel Sambuc 		     krb5_storage *response)
1339ebfedea0SLionel Sambuc {
1340ebfedea0SLionel Sambuc     struct kcm_ntlm_cred *c;
1341ebfedea0SLionel Sambuc     char *user = NULL, *domain = NULL;
1342ebfedea0SLionel Sambuc     krb5_error_code ret;
1343ebfedea0SLionel Sambuc 
1344ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &user);
1345ebfedea0SLionel Sambuc     if (ret)
1346ebfedea0SLionel Sambuc 	goto error;
1347ebfedea0SLionel Sambuc 
1348ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &domain);
1349ebfedea0SLionel Sambuc     if (ret)
1350ebfedea0SLionel Sambuc 	goto error;
1351ebfedea0SLionel Sambuc 
1352ebfedea0SLionel Sambuc     if (domain[0] == '\0') {
1353ebfedea0SLionel Sambuc 	free(domain);
1354ebfedea0SLionel Sambuc 	domain = NULL;
1355ebfedea0SLionel Sambuc     }
1356ebfedea0SLionel Sambuc 
1357ebfedea0SLionel Sambuc     c = find_ntlm_cred(user, domain, client);
1358ebfedea0SLionel Sambuc     if (c == NULL)
1359ebfedea0SLionel Sambuc 	ret = ENOENT;
1360ebfedea0SLionel Sambuc 
1361ebfedea0SLionel Sambuc  error:
1362ebfedea0SLionel Sambuc     free(user);
1363ebfedea0SLionel Sambuc     if (domain)
1364ebfedea0SLionel Sambuc 	free(domain);
1365ebfedea0SLionel Sambuc 
1366ebfedea0SLionel Sambuc     return ret;
1367ebfedea0SLionel Sambuc }
1368ebfedea0SLionel Sambuc 
1369ebfedea0SLionel Sambuc /*
1370ebfedea0SLionel Sambuc  * { "DEL_NTLM_CRED",		NULL },
1371ebfedea0SLionel Sambuc  *
1372ebfedea0SLionel Sambuc  * input:
1373ebfedea0SLionel Sambuc  *  name
1374ebfedea0SLionel Sambuc  *  domain
1375ebfedea0SLionel Sambuc  */
1376ebfedea0SLionel Sambuc 
1377ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_del_ntlm_cred(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1378ebfedea0SLionel Sambuc kcm_op_del_ntlm_cred(krb5_context context,
1379ebfedea0SLionel Sambuc 		     kcm_client *client,
1380ebfedea0SLionel Sambuc 		     kcm_operation opcode,
1381ebfedea0SLionel Sambuc 		     krb5_storage *request,
1382ebfedea0SLionel Sambuc 		     krb5_storage *response)
1383ebfedea0SLionel Sambuc {
1384ebfedea0SLionel Sambuc     struct kcm_ntlm_cred **cp, *c;
1385ebfedea0SLionel Sambuc     char *user = NULL, *domain = NULL;
1386ebfedea0SLionel Sambuc     krb5_error_code ret;
1387ebfedea0SLionel Sambuc 
1388ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &user);
1389ebfedea0SLionel Sambuc     if (ret)
1390ebfedea0SLionel Sambuc 	goto error;
1391ebfedea0SLionel Sambuc 
1392ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &domain);
1393ebfedea0SLionel Sambuc     if (ret)
1394ebfedea0SLionel Sambuc 	goto error;
1395ebfedea0SLionel Sambuc 
1396ebfedea0SLionel Sambuc     for (cp = &ntlm_head; *cp != NULL; cp = &(*cp)->next) {
1397ebfedea0SLionel Sambuc 	if (strcmp(user, (*cp)->user) == 0 && strcmp(domain, (*cp)->domain) == 0 &&
1398ebfedea0SLionel Sambuc 	    kcm_is_same_session(client, (*cp)->uid, (*cp)->session))
1399ebfedea0SLionel Sambuc 	{
1400ebfedea0SLionel Sambuc 	    c = *cp;
1401ebfedea0SLionel Sambuc 	    *cp = c->next;
1402ebfedea0SLionel Sambuc 
1403ebfedea0SLionel Sambuc 	    free_cred(c);
1404ebfedea0SLionel Sambuc 	    break;
1405ebfedea0SLionel Sambuc 	}
1406ebfedea0SLionel Sambuc     }
1407ebfedea0SLionel Sambuc 
1408ebfedea0SLionel Sambuc  error:
1409ebfedea0SLionel Sambuc     free(user);
1410ebfedea0SLionel Sambuc     free(domain);
1411ebfedea0SLionel Sambuc 
1412ebfedea0SLionel Sambuc     return ret;
1413ebfedea0SLionel Sambuc }
1414ebfedea0SLionel Sambuc 
1415ebfedea0SLionel Sambuc /*
1416ebfedea0SLionel Sambuc  * { "DO_NTLM_AUTH",		NULL },
1417ebfedea0SLionel Sambuc  *
1418ebfedea0SLionel Sambuc  * input:
1419ebfedea0SLionel Sambuc  *  name:string
1420ebfedea0SLionel Sambuc  *  domain:string
1421ebfedea0SLionel Sambuc  *  type2:data
1422ebfedea0SLionel Sambuc  *
1423ebfedea0SLionel Sambuc  * reply:
1424ebfedea0SLionel Sambuc  *  type3:data
1425ebfedea0SLionel Sambuc  *  flags:int32
1426ebfedea0SLionel Sambuc  *  session-key:data
1427ebfedea0SLionel Sambuc  */
1428ebfedea0SLionel Sambuc 
1429ebfedea0SLionel Sambuc #define NTLM_FLAG_SESSIONKEY 1
1430ebfedea0SLionel Sambuc #define NTLM_FLAG_NTLM2_SESSION 2
1431ebfedea0SLionel Sambuc #define NTLM_FLAG_KEYEX 4
1432ebfedea0SLionel Sambuc 
1433ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_do_ntlm(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1434ebfedea0SLionel Sambuc kcm_op_do_ntlm(krb5_context context,
1435ebfedea0SLionel Sambuc 	       kcm_client *client,
1436ebfedea0SLionel Sambuc 	       kcm_operation opcode,
1437ebfedea0SLionel Sambuc 	       krb5_storage *request,
1438ebfedea0SLionel Sambuc 	       krb5_storage *response)
1439ebfedea0SLionel Sambuc {
1440ebfedea0SLionel Sambuc     struct kcm_ntlm_cred *c;
1441ebfedea0SLionel Sambuc     struct ntlm_type2 type2;
1442ebfedea0SLionel Sambuc     struct ntlm_type3 type3;
1443ebfedea0SLionel Sambuc     char *user = NULL, *domain = NULL;
1444ebfedea0SLionel Sambuc     struct ntlm_buf ndata, sessionkey;
1445ebfedea0SLionel Sambuc     krb5_data data;
1446ebfedea0SLionel Sambuc     krb5_error_code ret;
1447ebfedea0SLionel Sambuc     uint32_t flags = 0;
1448ebfedea0SLionel Sambuc 
1449ebfedea0SLionel Sambuc     memset(&type2, 0, sizeof(type2));
1450ebfedea0SLionel Sambuc     memset(&type3, 0, sizeof(type3));
1451ebfedea0SLionel Sambuc     sessionkey.data = NULL;
1452ebfedea0SLionel Sambuc     sessionkey.length = 0;
1453ebfedea0SLionel Sambuc 
1454ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &user);
1455ebfedea0SLionel Sambuc     if (ret)
1456ebfedea0SLionel Sambuc 	goto error;
1457ebfedea0SLionel Sambuc 
1458ebfedea0SLionel Sambuc     ret = krb5_ret_stringz(request, &domain);
1459ebfedea0SLionel Sambuc     if (ret)
1460ebfedea0SLionel Sambuc 	goto error;
1461ebfedea0SLionel Sambuc 
1462ebfedea0SLionel Sambuc     if (domain[0] == '\0') {
1463ebfedea0SLionel Sambuc 	free(domain);
1464ebfedea0SLionel Sambuc 	domain = NULL;
1465ebfedea0SLionel Sambuc     }
1466ebfedea0SLionel Sambuc 
1467ebfedea0SLionel Sambuc     c = find_ntlm_cred(user, domain, client);
1468ebfedea0SLionel Sambuc     if (c == NULL) {
1469ebfedea0SLionel Sambuc 	ret = EINVAL;
1470ebfedea0SLionel Sambuc 	goto error;
1471ebfedea0SLionel Sambuc     }
1472ebfedea0SLionel Sambuc 
1473ebfedea0SLionel Sambuc     ret = krb5_ret_data(request, &data);
1474ebfedea0SLionel Sambuc     if (ret)
1475ebfedea0SLionel Sambuc 	goto error;
1476ebfedea0SLionel Sambuc 
1477ebfedea0SLionel Sambuc     ndata.data = data.data;
1478ebfedea0SLionel Sambuc     ndata.length = data.length;
1479ebfedea0SLionel Sambuc 
1480ebfedea0SLionel Sambuc     ret = heim_ntlm_decode_type2(&ndata, &type2);
1481ebfedea0SLionel Sambuc     krb5_data_free(&data);
1482ebfedea0SLionel Sambuc     if (ret)
1483ebfedea0SLionel Sambuc 	goto error;
1484ebfedea0SLionel Sambuc 
1485ebfedea0SLionel Sambuc     if (domain && strcmp(domain, type2.targetname) == 0) {
1486ebfedea0SLionel Sambuc 	ret = EINVAL;
1487ebfedea0SLionel Sambuc 	goto error;
1488ebfedea0SLionel Sambuc     }
1489ebfedea0SLionel Sambuc 
1490ebfedea0SLionel Sambuc     type3.username = c->user;
1491ebfedea0SLionel Sambuc     type3.flags = type2.flags;
1492ebfedea0SLionel Sambuc     type3.targetname = type2.targetname;
1493ebfedea0SLionel Sambuc     type3.ws = rk_UNCONST("workstation");
1494ebfedea0SLionel Sambuc 
1495ebfedea0SLionel Sambuc     /*
1496ebfedea0SLionel Sambuc      * NTLM Version 1 if no targetinfo buffer.
1497ebfedea0SLionel Sambuc      */
1498ebfedea0SLionel Sambuc 
1499ebfedea0SLionel Sambuc     if (1 || type2.targetinfo.length == 0) {
1500ebfedea0SLionel Sambuc 	struct ntlm_buf sessionkey;
1501ebfedea0SLionel Sambuc 
1502ebfedea0SLionel Sambuc 	if (type2.flags & NTLM_NEG_NTLM2_SESSION) {
1503ebfedea0SLionel Sambuc 	    unsigned char nonce[8];
1504ebfedea0SLionel Sambuc 
1505ebfedea0SLionel Sambuc 	    if (RAND_bytes(nonce, sizeof(nonce)) != 1) {
1506ebfedea0SLionel Sambuc 		ret = EINVAL;
1507ebfedea0SLionel Sambuc 		goto error;
1508ebfedea0SLionel Sambuc 	    }
1509ebfedea0SLionel Sambuc 
1510ebfedea0SLionel Sambuc 	    ret = heim_ntlm_calculate_ntlm2_sess(nonce,
1511ebfedea0SLionel Sambuc 						 type2.challenge,
1512ebfedea0SLionel Sambuc 						 c->nthash.data,
1513ebfedea0SLionel Sambuc 						 &type3.lm,
1514ebfedea0SLionel Sambuc 						 &type3.ntlm);
1515ebfedea0SLionel Sambuc 	} else {
1516ebfedea0SLionel Sambuc 	    ret = heim_ntlm_calculate_ntlm1(c->nthash.data,
1517ebfedea0SLionel Sambuc 					    c->nthash.length,
1518ebfedea0SLionel Sambuc 					    type2.challenge,
1519ebfedea0SLionel Sambuc 					    &type3.ntlm);
1520ebfedea0SLionel Sambuc 
1521ebfedea0SLionel Sambuc 	}
1522ebfedea0SLionel Sambuc 	if (ret)
1523ebfedea0SLionel Sambuc 	    goto error;
1524ebfedea0SLionel Sambuc 
1525ebfedea0SLionel Sambuc 	ret = heim_ntlm_build_ntlm1_master(c->nthash.data,
1526ebfedea0SLionel Sambuc 					   c->nthash.length,
1527ebfedea0SLionel Sambuc 					   &sessionkey,
1528ebfedea0SLionel Sambuc 					   &type3.sessionkey);
1529ebfedea0SLionel Sambuc 	if (ret) {
1530ebfedea0SLionel Sambuc 	    if (type3.lm.data)
1531ebfedea0SLionel Sambuc 		free(type3.lm.data);
1532ebfedea0SLionel Sambuc 	    if (type3.ntlm.data)
1533ebfedea0SLionel Sambuc 		free(type3.ntlm.data);
1534ebfedea0SLionel Sambuc 	    goto error;
1535ebfedea0SLionel Sambuc 	}
1536ebfedea0SLionel Sambuc 
1537ebfedea0SLionel Sambuc 	free(sessionkey.data);
1538ebfedea0SLionel Sambuc 	if (ret) {
1539ebfedea0SLionel Sambuc 	    if (type3.lm.data)
1540ebfedea0SLionel Sambuc 		free(type3.lm.data);
1541ebfedea0SLionel Sambuc 	    if (type3.ntlm.data)
1542ebfedea0SLionel Sambuc 		free(type3.ntlm.data);
1543ebfedea0SLionel Sambuc 	    goto error;
1544ebfedea0SLionel Sambuc 	}
1545ebfedea0SLionel Sambuc 	flags |= NTLM_FLAG_SESSIONKEY;
1546ebfedea0SLionel Sambuc #if 0
1547ebfedea0SLionel Sambuc     } else {
1548ebfedea0SLionel Sambuc 	struct ntlm_buf sessionkey;
1549ebfedea0SLionel Sambuc 	unsigned char ntlmv2[16];
1550ebfedea0SLionel Sambuc 	struct ntlm_targetinfo ti;
1551ebfedea0SLionel Sambuc 
1552ebfedea0SLionel Sambuc 	/* verify infotarget */
1553ebfedea0SLionel Sambuc 
1554ebfedea0SLionel Sambuc 	ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti);
1555ebfedea0SLionel Sambuc 	if(ret) {
1556ebfedea0SLionel Sambuc 	    _gss_ntlm_delete_sec_context(minor_status,
1557ebfedea0SLionel Sambuc 					 context_handle, NULL);
1558ebfedea0SLionel Sambuc 	    *minor_status = ret;
1559ebfedea0SLionel Sambuc 	    return GSS_S_FAILURE;
1560ebfedea0SLionel Sambuc 	}
1561ebfedea0SLionel Sambuc 
1562ebfedea0SLionel Sambuc 	if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) {
1563ebfedea0SLionel Sambuc 	    _gss_ntlm_delete_sec_context(minor_status,
1564ebfedea0SLionel Sambuc 					 context_handle, NULL);
1565ebfedea0SLionel Sambuc 	    *minor_status = EINVAL;
1566ebfedea0SLionel Sambuc 	    return GSS_S_FAILURE;
1567ebfedea0SLionel Sambuc 	}
1568ebfedea0SLionel Sambuc 
1569ebfedea0SLionel Sambuc 	ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data,
1570ebfedea0SLionel Sambuc 					ctx->client->key.length,
1571ebfedea0SLionel Sambuc 					type3.username,
1572ebfedea0SLionel Sambuc 					name->domain,
1573ebfedea0SLionel Sambuc 					type2.challenge,
1574ebfedea0SLionel Sambuc 					&type2.targetinfo,
1575ebfedea0SLionel Sambuc 					ntlmv2,
1576ebfedea0SLionel Sambuc 					&type3.ntlm);
1577ebfedea0SLionel Sambuc 	if (ret) {
1578ebfedea0SLionel Sambuc 	    _gss_ntlm_delete_sec_context(minor_status,
1579ebfedea0SLionel Sambuc 					 context_handle, NULL);
1580ebfedea0SLionel Sambuc 	    *minor_status = ret;
1581ebfedea0SLionel Sambuc 	    return GSS_S_FAILURE;
1582ebfedea0SLionel Sambuc 	}
1583ebfedea0SLionel Sambuc 
1584ebfedea0SLionel Sambuc 	ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),
1585ebfedea0SLionel Sambuc 					   &sessionkey,
1586ebfedea0SLionel Sambuc 					   &type3.sessionkey);
1587ebfedea0SLionel Sambuc 	memset(ntlmv2, 0, sizeof(ntlmv2));
1588ebfedea0SLionel Sambuc 	if (ret) {
1589ebfedea0SLionel Sambuc 	    _gss_ntlm_delete_sec_context(minor_status,
1590ebfedea0SLionel Sambuc 					 context_handle, NULL);
1591ebfedea0SLionel Sambuc 	    *minor_status = ret;
1592ebfedea0SLionel Sambuc 	    return GSS_S_FAILURE;
1593ebfedea0SLionel Sambuc 	}
1594ebfedea0SLionel Sambuc 
1595ebfedea0SLionel Sambuc 	flags |= NTLM_FLAG_NTLM2_SESSION |
1596ebfedea0SLionel Sambuc 	         NTLM_FLAG_SESSION;
1597ebfedea0SLionel Sambuc 
1598ebfedea0SLionel Sambuc 	if (type3.flags & NTLM_NEG_KEYEX)
1599ebfedea0SLionel Sambuc 	    flags |= NTLM_FLAG_KEYEX;
1600ebfedea0SLionel Sambuc 
1601ebfedea0SLionel Sambuc 	ret = krb5_data_copy(&ctx->sessionkey,
1602ebfedea0SLionel Sambuc 			     sessionkey.data, sessionkey.length);
1603ebfedea0SLionel Sambuc 	free(sessionkey.data);
1604ebfedea0SLionel Sambuc 	if (ret) {
1605ebfedea0SLionel Sambuc 	    _gss_ntlm_delete_sec_context(minor_status,
1606ebfedea0SLionel Sambuc 					 context_handle, NULL);
1607ebfedea0SLionel Sambuc 	    *minor_status = ret;
1608ebfedea0SLionel Sambuc 	    return GSS_S_FAILURE;
1609ebfedea0SLionel Sambuc 	}
1610ebfedea0SLionel Sambuc #endif
1611ebfedea0SLionel Sambuc     }
1612ebfedea0SLionel Sambuc 
1613ebfedea0SLionel Sambuc #if 0
1614ebfedea0SLionel Sambuc     if (flags & NTLM_FLAG_NTLM2_SESSION) {
1615ebfedea0SLionel Sambuc 	_gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX),
1616ebfedea0SLionel Sambuc 			  ctx->sessionkey.data,
1617ebfedea0SLionel Sambuc 			  ctx->sessionkey.length);
1618ebfedea0SLionel Sambuc 	_gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX),
1619ebfedea0SLionel Sambuc 			  ctx->sessionkey.data,
1620ebfedea0SLionel Sambuc 			  ctx->sessionkey.length);
1621ebfedea0SLionel Sambuc     } else {
1622ebfedea0SLionel Sambuc 	flags |= NTLM_FLAG_SESSION;
1623ebfedea0SLionel Sambuc 	RC4_set_key(&ctx->u.v1.crypto_recv.key,
1624ebfedea0SLionel Sambuc 		    ctx->sessionkey.length,
1625ebfedea0SLionel Sambuc 		    ctx->sessionkey.data);
1626ebfedea0SLionel Sambuc 	RC4_set_key(&ctx->u.v1.crypto_send.key,
1627ebfedea0SLionel Sambuc 		    ctx->sessionkey.length,
1628ebfedea0SLionel Sambuc 		    ctx->sessionkey.data);
1629ebfedea0SLionel Sambuc     }
1630ebfedea0SLionel Sambuc #endif
1631ebfedea0SLionel Sambuc 
1632ebfedea0SLionel Sambuc     ret = heim_ntlm_encode_type3(&type3, &ndata);
1633ebfedea0SLionel Sambuc     if (ret)
1634ebfedea0SLionel Sambuc 	goto error;
1635ebfedea0SLionel Sambuc 
1636ebfedea0SLionel Sambuc     data.data = ndata.data;
1637ebfedea0SLionel Sambuc     data.length = ndata.length;
1638ebfedea0SLionel Sambuc     ret = krb5_store_data(response, data);
1639ebfedea0SLionel Sambuc     heim_ntlm_free_buf(&ndata);
1640ebfedea0SLionel Sambuc     if (ret) goto error;
1641ebfedea0SLionel Sambuc 
1642ebfedea0SLionel Sambuc     ret = krb5_store_int32(response, flags);
1643ebfedea0SLionel Sambuc     if (ret) goto error;
1644ebfedea0SLionel Sambuc 
1645ebfedea0SLionel Sambuc     data.data = sessionkey.data;
1646ebfedea0SLionel Sambuc     data.length = sessionkey.length;
1647ebfedea0SLionel Sambuc 
1648ebfedea0SLionel Sambuc     ret = krb5_store_data(response, data);
1649ebfedea0SLionel Sambuc     if (ret) goto error;
1650ebfedea0SLionel Sambuc 
1651ebfedea0SLionel Sambuc  error:
1652ebfedea0SLionel Sambuc     free(type3.username);
1653ebfedea0SLionel Sambuc     heim_ntlm_free_type2(&type2);
1654ebfedea0SLionel Sambuc     free(user);
1655ebfedea0SLionel Sambuc     if (domain)
1656ebfedea0SLionel Sambuc 	free(domain);
1657ebfedea0SLionel Sambuc 
1658ebfedea0SLionel Sambuc     return ret;
1659ebfedea0SLionel Sambuc }
1660ebfedea0SLionel Sambuc 
1661ebfedea0SLionel Sambuc 
1662ebfedea0SLionel Sambuc /*
1663ebfedea0SLionel Sambuc  * { "GET_NTLM_UUID_LIST",	NULL }
1664ebfedea0SLionel Sambuc  *
1665ebfedea0SLionel Sambuc  * reply:
1666ebfedea0SLionel Sambuc  *   1 user domain
1667ebfedea0SLionel Sambuc  *   0 [ end of list ]
1668ebfedea0SLionel Sambuc  */
1669ebfedea0SLionel Sambuc 
1670ebfedea0SLionel Sambuc static krb5_error_code
kcm_op_get_ntlm_user_list(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * request,krb5_storage * response)1671ebfedea0SLionel Sambuc kcm_op_get_ntlm_user_list(krb5_context context,
1672ebfedea0SLionel Sambuc 			  kcm_client *client,
1673ebfedea0SLionel Sambuc 			  kcm_operation opcode,
1674ebfedea0SLionel Sambuc 			  krb5_storage *request,
1675ebfedea0SLionel Sambuc 			  krb5_storage *response)
1676ebfedea0SLionel Sambuc {
1677ebfedea0SLionel Sambuc     struct kcm_ntlm_cred *c;
1678ebfedea0SLionel Sambuc     krb5_error_code ret;
1679ebfedea0SLionel Sambuc 
1680ebfedea0SLionel Sambuc     for (c = ntlm_head; c != NULL; c = c->next) {
1681ebfedea0SLionel Sambuc 	if (!kcm_is_same_session(client, c->uid, c->session))
1682ebfedea0SLionel Sambuc 	    continue;
1683ebfedea0SLionel Sambuc 
1684ebfedea0SLionel Sambuc 	ret = krb5_store_uint32(response, 1);
1685ebfedea0SLionel Sambuc 	if (ret)
1686ebfedea0SLionel Sambuc 	    return ret;
1687ebfedea0SLionel Sambuc 	ret = krb5_store_stringz(response, c->user);
1688ebfedea0SLionel Sambuc 	if (ret)
1689ebfedea0SLionel Sambuc 	    return ret;
1690ebfedea0SLionel Sambuc 	ret = krb5_store_stringz(response, c->domain);
1691ebfedea0SLionel Sambuc 	if (ret)
1692ebfedea0SLionel Sambuc 	    return ret;
1693ebfedea0SLionel Sambuc     }
1694ebfedea0SLionel Sambuc     return krb5_store_uint32(response, 0);
1695ebfedea0SLionel Sambuc }
1696ebfedea0SLionel Sambuc 
1697ebfedea0SLionel Sambuc /*
1698ebfedea0SLionel Sambuc  *
1699ebfedea0SLionel Sambuc  */
1700ebfedea0SLionel Sambuc 
1701ebfedea0SLionel Sambuc static struct kcm_op kcm_ops[] = {
1702ebfedea0SLionel Sambuc     { "NOOP", 			kcm_op_noop },
1703ebfedea0SLionel Sambuc     { "GET_NAME",		kcm_op_get_name },
1704ebfedea0SLionel Sambuc     { "RESOLVE",		kcm_op_noop },
1705ebfedea0SLionel Sambuc     { "GEN_NEW", 		kcm_op_gen_new },
1706ebfedea0SLionel Sambuc     { "INITIALIZE",		kcm_op_initialize },
1707ebfedea0SLionel Sambuc     { "DESTROY",		kcm_op_destroy },
1708ebfedea0SLionel Sambuc     { "STORE",			kcm_op_store },
1709ebfedea0SLionel Sambuc     { "RETRIEVE",		kcm_op_retrieve },
1710ebfedea0SLionel Sambuc     { "GET_PRINCIPAL",		kcm_op_get_principal },
1711ebfedea0SLionel Sambuc     { "GET_CRED_UUID_LIST",	kcm_op_get_cred_uuid_list },
1712ebfedea0SLionel Sambuc     { "GET_CRED_BY_UUID",	kcm_op_get_cred_by_uuid },
1713ebfedea0SLionel Sambuc     { "REMOVE_CRED",		kcm_op_remove_cred },
1714ebfedea0SLionel Sambuc     { "SET_FLAGS",		kcm_op_set_flags },
1715ebfedea0SLionel Sambuc     { "CHOWN",			kcm_op_chown },
1716ebfedea0SLionel Sambuc     { "CHMOD",			kcm_op_chmod },
1717ebfedea0SLionel Sambuc     { "GET_INITIAL_TICKET",	kcm_op_get_initial_ticket },
1718ebfedea0SLionel Sambuc     { "GET_TICKET",		kcm_op_get_ticket },
1719ebfedea0SLionel Sambuc     { "MOVE_CACHE",		kcm_op_move_cache },
1720ebfedea0SLionel Sambuc     { "GET_CACHE_UUID_LIST",	kcm_op_get_cache_uuid_list },
1721ebfedea0SLionel Sambuc     { "GET_CACHE_BY_UUID",	kcm_op_get_cache_by_uuid },
1722ebfedea0SLionel Sambuc     { "GET_DEFAULT_CACHE",      kcm_op_get_default_cache },
1723ebfedea0SLionel Sambuc     { "SET_DEFAULT_CACHE",      kcm_op_set_default_cache },
1724ebfedea0SLionel Sambuc     { "GET_KDC_OFFSET",      	kcm_op_get_kdc_offset },
1725ebfedea0SLionel Sambuc     { "SET_KDC_OFFSET",      	kcm_op_set_kdc_offset },
1726ebfedea0SLionel Sambuc     { "ADD_NTLM_CRED",		kcm_op_add_ntlm_cred },
1727ebfedea0SLionel Sambuc     { "HAVE_USER_CRED",		kcm_op_have_ntlm_cred },
1728ebfedea0SLionel Sambuc     { "DEL_NTLM_CRED",		kcm_op_del_ntlm_cred },
1729ebfedea0SLionel Sambuc     { "DO_NTLM_AUTH",		kcm_op_do_ntlm },
1730ebfedea0SLionel Sambuc     { "GET_NTLM_USER_LIST",	kcm_op_get_ntlm_user_list }
1731ebfedea0SLionel Sambuc };
1732ebfedea0SLionel Sambuc 
1733ebfedea0SLionel Sambuc 
1734ebfedea0SLionel Sambuc const char *
kcm_op2string(kcm_operation opcode)1735ebfedea0SLionel Sambuc kcm_op2string(kcm_operation opcode)
1736ebfedea0SLionel Sambuc {
1737ebfedea0SLionel Sambuc     if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0]))
1738ebfedea0SLionel Sambuc 	return "Unknown operation";
1739ebfedea0SLionel Sambuc 
1740ebfedea0SLionel Sambuc     return kcm_ops[opcode].name;
1741ebfedea0SLionel Sambuc }
1742ebfedea0SLionel Sambuc 
1743ebfedea0SLionel Sambuc krb5_error_code
kcm_dispatch(krb5_context context,kcm_client * client,krb5_data * req_data,krb5_data * resp_data)1744ebfedea0SLionel Sambuc kcm_dispatch(krb5_context context,
1745ebfedea0SLionel Sambuc 	     kcm_client *client,
1746ebfedea0SLionel Sambuc 	     krb5_data *req_data,
1747ebfedea0SLionel Sambuc 	     krb5_data *resp_data)
1748ebfedea0SLionel Sambuc {
1749ebfedea0SLionel Sambuc     krb5_error_code ret;
1750ebfedea0SLionel Sambuc     kcm_method method;
1751ebfedea0SLionel Sambuc     krb5_storage *req_sp = NULL;
1752ebfedea0SLionel Sambuc     krb5_storage *resp_sp = NULL;
1753ebfedea0SLionel Sambuc     uint16_t opcode;
1754ebfedea0SLionel Sambuc 
1755ebfedea0SLionel Sambuc     resp_sp = krb5_storage_emem();
1756ebfedea0SLionel Sambuc     if (resp_sp == NULL) {
1757ebfedea0SLionel Sambuc 	return ENOMEM;
1758ebfedea0SLionel Sambuc     }
1759ebfedea0SLionel Sambuc 
1760ebfedea0SLionel Sambuc     if (client->pid == -1) {
1761ebfedea0SLionel Sambuc 	kcm_log(0, "Client had invalid process number");
1762ebfedea0SLionel Sambuc 	ret = KRB5_FCC_INTERNAL;
1763ebfedea0SLionel Sambuc 	goto out;
1764ebfedea0SLionel Sambuc     }
1765ebfedea0SLionel Sambuc 
1766ebfedea0SLionel Sambuc     req_sp = krb5_storage_from_data(req_data);
1767ebfedea0SLionel Sambuc     if (req_sp == NULL) {
1768ebfedea0SLionel Sambuc 	kcm_log(0, "Process %d: failed to initialize storage from data",
1769ebfedea0SLionel Sambuc 		client->pid);
1770ebfedea0SLionel Sambuc 	ret = KRB5_CC_IO;
1771ebfedea0SLionel Sambuc 	goto out;
1772ebfedea0SLionel Sambuc     }
1773ebfedea0SLionel Sambuc 
1774ebfedea0SLionel Sambuc     ret = krb5_ret_uint16(req_sp, &opcode);
1775ebfedea0SLionel Sambuc     if (ret) {
1776ebfedea0SLionel Sambuc 	kcm_log(0, "Process %d: didn't send a message", client->pid);
1777ebfedea0SLionel Sambuc 	goto out;
1778ebfedea0SLionel Sambuc     }
1779ebfedea0SLionel Sambuc 
1780ebfedea0SLionel Sambuc     if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) {
1781ebfedea0SLionel Sambuc 	kcm_log(0, "Process %d: invalid operation code %d",
1782ebfedea0SLionel Sambuc 		client->pid, opcode);
1783ebfedea0SLionel Sambuc 	ret = KRB5_FCC_INTERNAL;
1784ebfedea0SLionel Sambuc 	goto out;
1785ebfedea0SLionel Sambuc     }
1786ebfedea0SLionel Sambuc     method = kcm_ops[opcode].method;
1787ebfedea0SLionel Sambuc     if (method == NULL) {
1788ebfedea0SLionel Sambuc 	kcm_log(0, "Process %d: operation code %s not implemented",
1789ebfedea0SLionel Sambuc 		client->pid, kcm_op2string(opcode));
1790ebfedea0SLionel Sambuc 	ret = KRB5_FCC_INTERNAL;
1791ebfedea0SLionel Sambuc 	goto out;
1792ebfedea0SLionel Sambuc     }
1793ebfedea0SLionel Sambuc 
1794ebfedea0SLionel Sambuc     /* seek past place for status code */
1795ebfedea0SLionel Sambuc     krb5_storage_seek(resp_sp, 4, SEEK_SET);
1796ebfedea0SLionel Sambuc 
1797ebfedea0SLionel Sambuc     ret = (*method)(context, client, opcode, req_sp, resp_sp);
1798ebfedea0SLionel Sambuc 
1799ebfedea0SLionel Sambuc out:
1800ebfedea0SLionel Sambuc     if (req_sp != NULL) {
1801ebfedea0SLionel Sambuc 	krb5_storage_free(req_sp);
1802ebfedea0SLionel Sambuc     }
1803ebfedea0SLionel Sambuc 
1804ebfedea0SLionel Sambuc     krb5_storage_seek(resp_sp, 0, SEEK_SET);
1805ebfedea0SLionel Sambuc     krb5_store_int32(resp_sp, ret);
1806ebfedea0SLionel Sambuc 
1807ebfedea0SLionel Sambuc     ret = krb5_storage_to_data(resp_sp, resp_data);
1808ebfedea0SLionel Sambuc     krb5_storage_free(resp_sp);
1809ebfedea0SLionel Sambuc 
1810ebfedea0SLionel Sambuc     return ret;
1811ebfedea0SLionel Sambuc }
1812ebfedea0SLionel Sambuc 
1813