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, ¬_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