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