/src/krb5/src/lib/gssapi/krb5/init_sec_context.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | | /* |
3 | | * Copyright 2000, 2002, 2003, 2007, 2008 by the Massachusetts Institute of |
4 | | * Technology. All Rights Reserved. |
5 | | * |
6 | | * Export of this software from the United States of America may |
7 | | * require a specific license from the United States Government. |
8 | | * It is the responsibility of any person or organization contemplating |
9 | | * export to obtain such a license before exporting. |
10 | | * |
11 | | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
12 | | * distribute this software and its documentation for any purpose and |
13 | | * without fee is hereby granted, provided that the above copyright |
14 | | * notice appear in all copies and that both that copyright notice and |
15 | | * this permission notice appear in supporting documentation, and that |
16 | | * the name of M.I.T. not be used in advertising or publicity pertaining |
17 | | * to distribution of the software without specific, written prior |
18 | | * permission. Furthermore if you modify this software you must label |
19 | | * your software as modified software and not distribute it in such a |
20 | | * fashion that it might be confused with the original M.I.T. software. |
21 | | * M.I.T. makes no representations about the suitability of |
22 | | * this software for any purpose. It is provided "as is" without express |
23 | | * or implied warranty. |
24 | | */ |
25 | | /* |
26 | | * Copyright 1993 by OpenVision Technologies, Inc. |
27 | | * |
28 | | * Permission to use, copy, modify, distribute, and sell this software |
29 | | * and its documentation for any purpose is hereby granted without fee, |
30 | | * provided that the above copyright notice appears in all copies and |
31 | | * that both that copyright notice and this permission notice appear in |
32 | | * supporting documentation, and that the name of OpenVision not be used |
33 | | * in advertising or publicity pertaining to distribution of the software |
34 | | * without specific, written prior permission. OpenVision makes no |
35 | | * representations about the suitability of this software for any |
36 | | * purpose. It is provided "as is" without express or implied warranty. |
37 | | * |
38 | | * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
39 | | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
40 | | * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
41 | | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF |
42 | | * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
43 | | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
44 | | * PERFORMANCE OF THIS SOFTWARE. |
45 | | */ |
46 | | |
47 | | /* |
48 | | * Copyright (C) 1998 by the FundsXpress, INC. |
49 | | * |
50 | | * All rights reserved. |
51 | | * |
52 | | * Export of this software from the United States of America may require |
53 | | * a specific license from the United States Government. It is the |
54 | | * responsibility of any person or organization contemplating export to |
55 | | * obtain such a license before exporting. |
56 | | * |
57 | | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
58 | | * distribute this software and its documentation for any purpose and |
59 | | * without fee is hereby granted, provided that the above copyright |
60 | | * notice appear in all copies and that both that copyright notice and |
61 | | * this permission notice appear in supporting documentation, and that |
62 | | * the name of FundsXpress. not be used in advertising or publicity pertaining |
63 | | * to distribution of the software without specific, written prior |
64 | | * permission. FundsXpress makes no representations about the suitability of |
65 | | * this software for any purpose. It is provided "as is" without express |
66 | | * or implied warranty. |
67 | | * |
68 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
69 | | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
70 | | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
71 | | */ |
72 | | /* |
73 | | * Copyright (c) 2006-2008, Novell, Inc. |
74 | | * All rights reserved. |
75 | | * |
76 | | * Redistribution and use in source and binary forms, with or without |
77 | | * modification, are permitted provided that the following conditions are met: |
78 | | * |
79 | | * * Redistributions of source code must retain the above copyright notice, |
80 | | * this list of conditions and the following disclaimer. |
81 | | * * Redistributions in binary form must reproduce the above copyright |
82 | | * notice, this list of conditions and the following disclaimer in the |
83 | | * documentation and/or other materials provided with the distribution. |
84 | | * * The copyright holder's name is not used to endorse or promote products |
85 | | * derived from this software without specific prior written permission. |
86 | | * |
87 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
88 | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
89 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
90 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
91 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
92 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
93 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
94 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
95 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
96 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
97 | | * POSSIBILITY OF SUCH DAMAGE. |
98 | | */ |
99 | | |
100 | | #include "k5-int.h" |
101 | | #include "gssapiP_krb5.h" |
102 | | #ifdef HAVE_MEMORY_H |
103 | | #include <memory.h> |
104 | | #endif |
105 | | #include <stdlib.h> |
106 | | #include <assert.h> |
107 | | |
108 | | /* |
109 | | * $Id$ |
110 | | */ |
111 | | |
112 | | /* XXX This is for debugging only!!! Should become a real bitfield |
113 | | at some point */ |
114 | | int krb5_gss_dbg_client_expcreds = 0; |
115 | | |
116 | | /* |
117 | | * Common code which fetches the correct krb5 credentials from the |
118 | | * ccache. |
119 | | */ |
120 | | static krb5_error_code |
121 | | get_credentials(krb5_context context, krb5_gss_cred_id_t cred, |
122 | | krb5_gss_name_t server, krb5_timestamp now, |
123 | | krb5_timestamp endtime, krb5_creds **out_creds) |
124 | 0 | { |
125 | 0 | krb5_error_code code; |
126 | 0 | krb5_creds in_creds, evidence_creds, mcreds, *result_creds = NULL; |
127 | 0 | krb5_flags flags = 0; |
128 | 0 | krb5_principal_data server_data; |
129 | |
|
130 | 0 | *out_creds = NULL; |
131 | |
|
132 | 0 | k5_mutex_assert_locked(&cred->lock); |
133 | 0 | memset(&in_creds, 0, sizeof(krb5_creds)); |
134 | 0 | memset(&evidence_creds, 0, sizeof(krb5_creds)); |
135 | 0 | in_creds.client = in_creds.server = NULL; |
136 | |
|
137 | 0 | assert(cred->name != NULL); |
138 | | |
139 | | /* Remove assumed realm from host-based S4U2Proxy requests as they must |
140 | | * start in the client realm. */ |
141 | 0 | server_data = *server->princ; |
142 | 0 | if (cred->impersonator != NULL && server_data.type == KRB5_NT_SRV_HST) |
143 | 0 | server_data.realm = empty_data(); |
144 | 0 | in_creds.server = &server_data; |
145 | |
|
146 | 0 | in_creds.client = cred->name->princ; |
147 | 0 | in_creds.times.endtime = endtime; |
148 | 0 | in_creds.authdata = NULL; |
149 | 0 | in_creds.keyblock.enctype = 0; |
150 | | |
151 | | /* |
152 | | * cred->name is immutable, so there is no need to acquire |
153 | | * cred->name->lock. |
154 | | */ |
155 | 0 | if (cred->name->ad_context != NULL) { |
156 | 0 | code = krb5_authdata_export_authdata(context, |
157 | 0 | cred->name->ad_context, |
158 | 0 | AD_USAGE_TGS_REQ, |
159 | 0 | &in_creds.authdata); |
160 | 0 | if (code != 0) |
161 | 0 | goto cleanup; |
162 | 0 | } |
163 | | |
164 | | /* Try constrained delegation if we have proxy credentials. */ |
165 | 0 | if (cred->impersonator != NULL) { |
166 | | /* If we are trying to get a ticket to ourselves, we should use the |
167 | | * the evidence ticket directly from cache. */ |
168 | 0 | if (krb5_principal_compare(context, cred->impersonator, |
169 | 0 | server->princ)) { |
170 | 0 | flags |= KRB5_GC_CACHED; |
171 | 0 | } else { |
172 | 0 | memset(&mcreds, 0, sizeof(mcreds)); |
173 | 0 | mcreds.magic = KV5M_CREDS; |
174 | 0 | mcreds.server = cred->impersonator; |
175 | 0 | mcreds.client = cred->name->princ; |
176 | 0 | code = krb5_cc_retrieve_cred(context, cred->ccache, |
177 | 0 | KRB5_TC_MATCH_AUTHDATA, &mcreds, |
178 | 0 | &evidence_creds); |
179 | 0 | if (code) |
180 | 0 | goto cleanup; |
181 | | |
182 | 0 | in_creds.client = cred->impersonator; |
183 | 0 | in_creds.second_ticket = evidence_creds.ticket; |
184 | 0 | flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION; |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | | /* For IAKERB, only check the cache in this step. We will ask the server |
189 | | * to make any necessary TGS requests. */ |
190 | 0 | if (cred->iakerb_mech) |
191 | 0 | flags |= KRB5_GC_CACHED; |
192 | |
|
193 | 0 | code = krb5_get_credentials(context, flags, cred->ccache, |
194 | 0 | &in_creds, &result_creds); |
195 | 0 | if (code) |
196 | 0 | goto cleanup; |
197 | | |
198 | 0 | if (flags & KRB5_GC_CONSTRAINED_DELEGATION) { |
199 | 0 | if (!krb5_principal_compare(context, cred->name->princ, |
200 | 0 | result_creds->client)) { |
201 | | /* server did not support constrained delegation */ |
202 | 0 | code = KRB5_KDCREP_MODIFIED; |
203 | 0 | goto cleanup; |
204 | 0 | } |
205 | 0 | } |
206 | | |
207 | | /* |
208 | | * Enforce a stricter limit (without timeskew forgiveness at the |
209 | | * boundaries) because accept_sec_context code is also similarly |
210 | | * non-forgiving. |
211 | | */ |
212 | 0 | if (!krb5_gss_dbg_client_expcreds && |
213 | 0 | ts_after(now, result_creds->times.endtime)) { |
214 | 0 | code = KRB5KRB_AP_ERR_TKT_EXPIRED; |
215 | 0 | goto cleanup; |
216 | 0 | } |
217 | | |
218 | 0 | *out_creds = result_creds; |
219 | 0 | result_creds = NULL; |
220 | |
|
221 | 0 | cleanup: |
222 | 0 | krb5_free_authdata(context, in_creds.authdata); |
223 | 0 | krb5_free_cred_contents(context, &evidence_creds); |
224 | 0 | krb5_free_creds(context, result_creds); |
225 | |
|
226 | 0 | return code; |
227 | 0 | } |
228 | | struct gss_checksum_data { |
229 | | krb5_gss_ctx_id_rec *ctx; |
230 | | krb5_gss_cred_id_t cred; |
231 | | krb5_checksum md5; |
232 | | krb5_data checksum_data; |
233 | | krb5_gss_ctx_ext_t exts; |
234 | | }; |
235 | | |
236 | | #ifdef CFX_EXERCISE |
237 | | #include "../../krb5/krb/auth_con.h" |
238 | | #endif |
239 | | static krb5_error_code KRB5_CALLCONV |
240 | | make_gss_checksum (krb5_context context, krb5_auth_context auth_context, |
241 | | void *cksum_data, krb5_data **out) |
242 | 0 | { |
243 | 0 | krb5_error_code code; |
244 | 0 | krb5_int32 con_flags; |
245 | 0 | struct gss_checksum_data *data = cksum_data; |
246 | 0 | krb5_data credmsg; |
247 | 0 | unsigned int junk; |
248 | 0 | krb5_data *finished = NULL; |
249 | 0 | krb5_key send_subkey; |
250 | 0 | struct k5buf buf; |
251 | |
|
252 | 0 | data->checksum_data = empty_data(); |
253 | 0 | credmsg.data = 0; |
254 | | /* build the checksum field */ |
255 | |
|
256 | 0 | if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) { |
257 | | /* first get KRB_CRED message, so we know its length */ |
258 | | |
259 | | /* clear the time check flag that was set in krb5_auth_con_init() */ |
260 | 0 | krb5_auth_con_getflags(context, auth_context, &con_flags); |
261 | 0 | krb5_auth_con_setflags(context, auth_context, |
262 | 0 | con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME); |
263 | |
|
264 | 0 | assert(data->cred->name != NULL); |
265 | | |
266 | | /* |
267 | | * RFC 4121 4.1.1 specifies forwarded credentials must be encrypted in |
268 | | * the session key, but krb5_fwd_tgt_creds will use the send subkey if |
269 | | * it's set in the auth context. Suppress the send subkey |
270 | | * temporarily. |
271 | | */ |
272 | 0 | krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey); |
273 | 0 | krb5_auth_con_setsendsubkey_k(context, auth_context, NULL); |
274 | |
|
275 | 0 | code = krb5_fwd_tgt_creds(context, auth_context, 0, |
276 | 0 | data->cred->name->princ, data->ctx->there->princ, |
277 | 0 | data->cred->ccache, 1, |
278 | 0 | &credmsg); |
279 | | |
280 | | /* Turn KRB5_AUTH_CONTEXT_DO_TIME back on and reset the send subkey. */ |
281 | 0 | krb5_auth_con_setflags(context, auth_context, con_flags); |
282 | 0 | krb5_auth_con_setsendsubkey_k(context, auth_context, send_subkey); |
283 | 0 | krb5_k_free_key(context, send_subkey); |
284 | |
|
285 | 0 | if (code) { |
286 | | /* don't fail here; just don't accept/do the delegation |
287 | | request */ |
288 | 0 | data->ctx->gss_flags &= ~(GSS_C_DELEG_FLAG | |
289 | 0 | GSS_C_DELEG_POLICY_FLAG); |
290 | 0 | } else { |
291 | 0 | if (credmsg.length+28 > KRB5_INT16_MAX) { |
292 | 0 | code = KRB5KRB_ERR_FIELD_TOOLONG; |
293 | 0 | goto cleanup; |
294 | 0 | } |
295 | 0 | } |
296 | 0 | } |
297 | | #ifdef CFX_EXERCISE |
298 | | if (data->ctx->auth_context->keyblock != NULL |
299 | | && data->ctx->auth_context->keyblock->enctype == 18) { |
300 | | srand(time(0) ^ getpid()); |
301 | | /* Our ftp client code stupidly assumes a base64-encoded |
302 | | version of the token will fit in 10K, so don't make this |
303 | | too big. */ |
304 | | junk = rand() & 0xff; |
305 | | } else |
306 | | junk = 0; |
307 | | #else |
308 | 0 | junk = 0; |
309 | 0 | #endif |
310 | |
|
311 | 0 | assert(data->exts != NULL); |
312 | | |
313 | 0 | if (data->exts->iakerb.conv) { |
314 | 0 | krb5_key key; |
315 | |
|
316 | 0 | code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key); |
317 | 0 | if (code != 0) |
318 | 0 | goto cleanup; |
319 | | |
320 | 0 | code = iakerb_make_finished(context, key, data->exts->iakerb.conv, |
321 | 0 | &finished); |
322 | 0 | if (code != 0) { |
323 | 0 | krb5_k_free_key(context, key); |
324 | 0 | goto cleanup; |
325 | 0 | } |
326 | | |
327 | 0 | krb5_k_free_key(context, key); |
328 | 0 | } |
329 | | |
330 | | /* now allocate a buffer to hold the checksum data and |
331 | | (maybe) KRB_CRED msg */ |
332 | 0 | k5_buf_init_dynamic(&buf); |
333 | 0 | k5_buf_add_uint32_le(&buf, data->md5.length); |
334 | 0 | k5_buf_add_len(&buf, data->md5.contents, data->md5.length); |
335 | 0 | k5_buf_add_uint32_le(&buf, data->ctx->gss_flags); |
336 | 0 | if (credmsg.data != NULL) { |
337 | 0 | k5_buf_add_uint16_le(&buf, KRB5_GSS_FOR_CREDS_OPTION); |
338 | 0 | k5_buf_add_uint16_le(&buf, credmsg.length); |
339 | 0 | k5_buf_add_len(&buf, credmsg.data, credmsg.length); |
340 | 0 | } |
341 | 0 | if (data->exts->iakerb.conv != NULL) { |
342 | 0 | k5_buf_add_uint32_be(&buf, GSS_EXTS_FINISHED); |
343 | 0 | k5_buf_add_uint32_be(&buf, finished->length); |
344 | 0 | k5_buf_add_len(&buf, finished->data, finished->length); |
345 | 0 | } |
346 | 0 | while (junk--) |
347 | 0 | k5_buf_add_byte(&buf, 'i'); |
348 | |
|
349 | 0 | code = k5_buf_status(&buf); |
350 | 0 | if (code) |
351 | 0 | goto cleanup; |
352 | | |
353 | 0 | data->checksum_data = make_data(buf.data, buf.len); |
354 | 0 | *out = &data->checksum_data; |
355 | 0 | code = 0; |
356 | |
|
357 | 0 | cleanup: |
358 | 0 | krb5_free_data_contents(context, &credmsg); |
359 | 0 | krb5_free_data(context, finished); |
360 | 0 | return code; |
361 | 0 | } |
362 | | |
363 | | static krb5_error_code |
364 | | make_ap_req_v1(krb5_context context, krb5_gss_ctx_id_rec *ctx, |
365 | | krb5_gss_cred_id_t cred, krb5_creds *k_cred, |
366 | | krb5_authdata_context ad_context, |
367 | | gss_channel_bindings_t chan_bindings, gss_OID mech_type, |
368 | | int cbt_flag, gss_buffer_t token, krb5_gss_ctx_ext_t exts) |
369 | 0 | { |
370 | 0 | krb5_flags mk_req_flags = 0; |
371 | 0 | krb5_error_code code; |
372 | 0 | struct gss_checksum_data cksum_struct; |
373 | 0 | krb5_checksum md5; |
374 | 0 | krb5_data ap_req; |
375 | 0 | unsigned char *t; |
376 | 0 | unsigned int tlen; |
377 | 0 | struct k5buf buf; |
378 | |
|
379 | 0 | k5_mutex_assert_locked(&cred->lock); |
380 | 0 | ap_req.data = 0; |
381 | | |
382 | | /* compute the hash of the channel bindings */ |
383 | |
|
384 | 0 | if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5))) |
385 | 0 | return(code); |
386 | | |
387 | 0 | krb5_auth_con_set_req_cksumtype(context, ctx->auth_context, |
388 | 0 | CKSUMTYPE_KG_CB); |
389 | 0 | cksum_struct.md5 = md5; |
390 | 0 | cksum_struct.ctx = ctx; |
391 | 0 | cksum_struct.cred = cred; |
392 | 0 | cksum_struct.checksum_data.data = NULL; |
393 | 0 | cksum_struct.exts = exts; |
394 | 0 | krb5_auth_con_set_checksum_func(context, ctx->auth_context, |
395 | 0 | make_gss_checksum, &cksum_struct); |
396 | | |
397 | | /* call mk_req. subkey and ap_req need to be used or destroyed */ |
398 | |
|
399 | 0 | mk_req_flags = AP_OPTS_USE_SUBKEY; |
400 | |
|
401 | 0 | if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) |
402 | 0 | mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION; |
403 | 0 | if (cbt_flag) |
404 | 0 | mk_req_flags |= AP_OPTS_CBT_FLAG; |
405 | |
|
406 | 0 | krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context); |
407 | 0 | code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags, |
408 | 0 | NULL, k_cred, &ap_req); |
409 | 0 | krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL); |
410 | 0 | krb5_free_checksum_contents(context, &cksum_struct.md5); |
411 | 0 | krb5_free_data_contents(context, &cksum_struct.checksum_data); |
412 | 0 | if (code) |
413 | 0 | goto cleanup; |
414 | | |
415 | | /* store the interesting stuff from creds and authent */ |
416 | 0 | ctx->krb_times = k_cred->times; |
417 | 0 | ctx->krb_flags = k_cred->ticket_flags; |
418 | | |
419 | | /* build up the token */ |
420 | 0 | if (ctx->gss_flags & GSS_C_DCE_STYLE) { |
421 | | /* |
422 | | * For DCE RPC, do not encapsulate the AP-REQ in the |
423 | | * typical GSS wrapping. |
424 | | */ |
425 | 0 | code = data_to_gss(&ap_req, token); |
426 | 0 | if (code) |
427 | 0 | goto cleanup; |
428 | 0 | } else { |
429 | | /* allocate space for the token */ |
430 | 0 | tlen = g_token_size((gss_OID) mech_type, ap_req.length); |
431 | 0 | t = gssalloc_malloc(tlen); |
432 | 0 | if (t == NULL) { |
433 | 0 | code = ENOMEM; |
434 | 0 | goto cleanup; |
435 | 0 | } |
436 | 0 | k5_buf_init_fixed(&buf, t, tlen); |
437 | 0 | g_make_token_header(&buf, mech_type, ap_req.length, KG_TOK_CTX_AP_REQ); |
438 | 0 | k5_buf_add_len(&buf, ap_req.data, ap_req.length); |
439 | 0 | assert(buf.len == tlen); |
440 | | |
441 | | /* pass it back */ |
442 | | |
443 | 0 | token->length = tlen; |
444 | 0 | token->value = (void *) t; |
445 | 0 | } |
446 | | |
447 | 0 | code = 0; |
448 | |
|
449 | 0 | cleanup: |
450 | 0 | if (ap_req.data) |
451 | 0 | krb5_free_data_contents(context, &ap_req); |
452 | |
|
453 | 0 | return (code); |
454 | 0 | } |
455 | | |
456 | | /* |
457 | | * new_connection |
458 | | * |
459 | | * Do the grunt work of setting up a new context. |
460 | | */ |
461 | | static OM_uint32 |
462 | | kg_new_connection( |
463 | | OM_uint32 *minor_status, |
464 | | krb5_gss_cred_id_t cred, |
465 | | gss_ctx_id_t *context_handle, |
466 | | gss_name_t target_name, |
467 | | gss_OID mech_type, |
468 | | OM_uint32 req_flags, |
469 | | OM_uint32 time_req, |
470 | | gss_channel_bindings_t input_chan_bindings, |
471 | | gss_buffer_t input_token, |
472 | | gss_OID *actual_mech_type, |
473 | | gss_buffer_t output_token, |
474 | | OM_uint32 *ret_flags, |
475 | | OM_uint32 *time_rec, |
476 | | krb5_context context, |
477 | | krb5_gss_ctx_ext_t exts) |
478 | 0 | { |
479 | 0 | OM_uint32 major_status; |
480 | 0 | krb5_error_code code; |
481 | 0 | krb5_creds *k_cred = NULL; |
482 | 0 | krb5_gss_ctx_id_rec *ctx, *ctx_free; |
483 | 0 | krb5_timestamp now; |
484 | 0 | gss_buffer_desc token; |
485 | 0 | krb5_keyblock *keyblock; |
486 | 0 | int cbt_flag = (req_flags & GSS_C_CHANNEL_BOUND_FLAG) != 0; |
487 | |
|
488 | 0 | k5_mutex_assert_locked(&cred->lock); |
489 | 0 | major_status = GSS_S_FAILURE; |
490 | 0 | token.length = 0; |
491 | 0 | token.value = NULL; |
492 | | |
493 | | /* make sure the cred is usable for init */ |
494 | |
|
495 | 0 | if ((cred->usage != GSS_C_INITIATE) && |
496 | 0 | (cred->usage != GSS_C_BOTH)) { |
497 | 0 | *minor_status = 0; |
498 | 0 | return(GSS_S_NO_CRED); |
499 | 0 | } |
500 | | |
501 | | /* complain if the input token is non-null */ |
502 | | |
503 | 0 | if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { |
504 | 0 | *minor_status = 0; |
505 | 0 | return(GSS_S_DEFECTIVE_TOKEN); |
506 | 0 | } |
507 | | |
508 | | /* create the ctx */ |
509 | | |
510 | 0 | if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) |
511 | 0 | == NULL) { |
512 | 0 | *minor_status = ENOMEM; |
513 | 0 | return(GSS_S_FAILURE); |
514 | 0 | } |
515 | | |
516 | | /* fill in the ctx */ |
517 | 0 | memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); |
518 | 0 | ctx->magic = KG_CONTEXT; |
519 | 0 | ctx_free = ctx; |
520 | 0 | if ((code = krb5_auth_con_init(context, &ctx->auth_context))) |
521 | 0 | goto cleanup; |
522 | 0 | krb5_auth_con_setflags(context, ctx->auth_context, |
523 | 0 | KRB5_AUTH_CONTEXT_DO_SEQUENCE); |
524 | | |
525 | | /* limit the encryption types negotiated (if requested) */ |
526 | 0 | if (cred->req_enctypes) { |
527 | 0 | if ((code = krb5_set_default_tgs_enctypes(context, |
528 | 0 | cred->req_enctypes))) { |
529 | 0 | goto cleanup; |
530 | 0 | } |
531 | 0 | } |
532 | | |
533 | 0 | ctx->initiate = 1; |
534 | 0 | ctx->seed_init = 0; |
535 | 0 | ctx->seqstate = 0; |
536 | | |
537 | | /* enforce_ok_as_delegate causes GSS_C_DELEG_FLAG to be treated as |
538 | | * GSS_C_DELEG_POLICY_FLAG (so ok-as-delegate is always enforced). */ |
539 | 0 | if (context->enforce_ok_as_delegate && (req_flags & GSS_C_DELEG_FLAG)) { |
540 | 0 | req_flags &= ~GSS_C_DELEG_FLAG; |
541 | 0 | req_flags |= GSS_C_DELEG_POLICY_FLAG; |
542 | 0 | } |
543 | | |
544 | | /* Don't include GSS_C_CHANNEL_BOUND_FLAG here; we don't want to put it on |
545 | | * the wire, and we only need to know about it for the first token. */ |
546 | 0 | ctx->gss_flags = req_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | |
547 | 0 | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | |
548 | 0 | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG | |
549 | 0 | GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | |
550 | 0 | GSS_C_EXTENDED_ERROR_FLAG); |
551 | 0 | ctx->gss_flags |= GSS_C_TRANS_FLAG; |
552 | 0 | if (!cred->suppress_ci_flags) |
553 | 0 | ctx->gss_flags |= (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG); |
554 | 0 | if (req_flags & GSS_C_DCE_STYLE) |
555 | 0 | ctx->gss_flags |= GSS_C_MUTUAL_FLAG; |
556 | |
|
557 | 0 | if ((code = krb5_timeofday(context, &now))) |
558 | 0 | goto cleanup; |
559 | | |
560 | 0 | if (time_req == 0 || time_req == GSS_C_INDEFINITE) { |
561 | 0 | ctx->krb_times.endtime = 0; |
562 | 0 | } else { |
563 | 0 | ctx->krb_times.endtime = ts_incr(now, time_req); |
564 | 0 | } |
565 | |
|
566 | 0 | if ((code = kg_duplicate_name(context, cred->name, &ctx->here))) |
567 | 0 | goto cleanup; |
568 | | |
569 | 0 | if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name, |
570 | 0 | &ctx->there))) |
571 | 0 | goto cleanup; |
572 | | |
573 | 0 | code = get_credentials(context, cred, ctx->there, now, |
574 | 0 | ctx->krb_times.endtime, &k_cred); |
575 | 0 | if (code) |
576 | 0 | goto cleanup; |
577 | | |
578 | 0 | ctx->krb_times = k_cred->times; |
579 | | |
580 | | /* |
581 | | * GSS_C_DELEG_POLICY_FLAG means to delegate only if the |
582 | | * ok-as-delegate ticket flag is set. |
583 | | */ |
584 | 0 | if ((req_flags & GSS_C_DELEG_POLICY_FLAG) |
585 | 0 | && (k_cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE)) |
586 | 0 | ctx->gss_flags |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG; |
587 | |
|
588 | 0 | if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used) |
589 | 0 | != GSS_S_COMPLETE) { |
590 | 0 | code = *minor_status; |
591 | 0 | goto cleanup; |
592 | 0 | } |
593 | | /* |
594 | | * Now try to make it static if at all possible.... |
595 | | */ |
596 | 0 | ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used); |
597 | |
|
598 | 0 | { |
599 | | /* gsskrb5 v1 */ |
600 | 0 | krb5_int32 seq_temp; |
601 | 0 | if ((code = make_ap_req_v1(context, ctx, |
602 | 0 | cred, k_cred, ctx->here->ad_context, |
603 | 0 | input_chan_bindings, mech_type, cbt_flag, |
604 | 0 | &token, exts))) { |
605 | 0 | if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || |
606 | 0 | (code == KG_EMPTY_CCACHE)) |
607 | 0 | major_status = GSS_S_NO_CRED; |
608 | 0 | if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) |
609 | 0 | major_status = GSS_S_CREDENTIALS_EXPIRED; |
610 | 0 | goto cleanup; |
611 | 0 | } |
612 | | |
613 | 0 | krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp); |
614 | 0 | ctx->seq_send = (uint32_t)seq_temp; |
615 | 0 | code = krb5_auth_con_getsendsubkey(context, ctx->auth_context, |
616 | 0 | &keyblock); |
617 | 0 | if (code != 0) |
618 | 0 | goto cleanup; |
619 | 0 | code = krb5_k_create_key(context, keyblock, &ctx->subkey); |
620 | 0 | krb5_free_keyblock(context, keyblock); |
621 | 0 | if (code != 0) |
622 | 0 | goto cleanup; |
623 | 0 | } |
624 | | |
625 | 0 | ctx->enc = NULL; |
626 | 0 | ctx->seq = NULL; |
627 | 0 | ctx->have_acceptor_subkey = 0; |
628 | 0 | code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype); |
629 | 0 | if (code != 0) |
630 | 0 | goto cleanup; |
631 | | |
632 | 0 | if (!(ctx->gss_flags & GSS_C_MUTUAL_FLAG)) { |
633 | | /* There will be no AP-REP, so set up sequence state now. */ |
634 | 0 | ctx->seq_recv = ctx->seq_send; |
635 | 0 | code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv, |
636 | 0 | (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, |
637 | 0 | (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, |
638 | 0 | ctx->proto); |
639 | 0 | if (code != 0) |
640 | 0 | goto cleanup; |
641 | 0 | } |
642 | | |
643 | | /* compute time_rec */ |
644 | 0 | if (time_rec) { |
645 | 0 | if ((code = krb5_timeofday(context, &now))) |
646 | 0 | goto cleanup; |
647 | 0 | *time_rec = ts_interval(now, ctx->krb_times.endtime); |
648 | 0 | } |
649 | | |
650 | | /* set the other returns */ |
651 | 0 | *output_token = token; |
652 | |
|
653 | 0 | if (ret_flags) |
654 | 0 | *ret_flags = ctx->gss_flags; |
655 | |
|
656 | 0 | if (actual_mech_type) |
657 | 0 | *actual_mech_type = mech_type; |
658 | | |
659 | | /* return successfully */ |
660 | |
|
661 | 0 | *context_handle = (gss_ctx_id_t) ctx; |
662 | 0 | ctx_free = NULL; |
663 | 0 | if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { |
664 | 0 | ctx->established = 0; |
665 | 0 | major_status = GSS_S_CONTINUE_NEEDED; |
666 | 0 | } else { |
667 | 0 | ctx->gss_flags |= GSS_C_PROT_READY_FLAG; |
668 | 0 | ctx->established = 1; |
669 | 0 | major_status = GSS_S_COMPLETE; |
670 | 0 | } |
671 | |
|
672 | 0 | cleanup: |
673 | 0 | krb5_free_creds(context, k_cred); |
674 | 0 | if (ctx_free) { |
675 | 0 | if (ctx_free->auth_context) |
676 | 0 | krb5_auth_con_free(context, ctx_free->auth_context); |
677 | 0 | if (ctx_free->here) |
678 | 0 | kg_release_name(context, &ctx_free->here); |
679 | 0 | if (ctx_free->there) |
680 | 0 | kg_release_name(context, &ctx_free->there); |
681 | 0 | if (ctx_free->subkey) |
682 | 0 | krb5_k_free_key(context, ctx_free->subkey); |
683 | 0 | xfree(ctx_free); |
684 | 0 | } |
685 | |
|
686 | 0 | *minor_status = code; |
687 | 0 | return (major_status); |
688 | 0 | } |
689 | | |
690 | | /* |
691 | | * mutual_auth |
692 | | * |
693 | | * Handle the reply from the acceptor, if we're doing mutual auth. |
694 | | */ |
695 | | static OM_uint32 |
696 | | mutual_auth( |
697 | | OM_uint32 *minor_status, |
698 | | gss_ctx_id_t *context_handle, |
699 | | gss_name_t target_name, |
700 | | gss_OID mech_type, |
701 | | OM_uint32 req_flags, |
702 | | OM_uint32 time_req, |
703 | | gss_channel_bindings_t input_chan_bindings, |
704 | | gss_buffer_t input_token, |
705 | | gss_OID *actual_mech_type, |
706 | | gss_buffer_t output_token, |
707 | | OM_uint32 *ret_flags, |
708 | | OM_uint32 *time_rec, |
709 | | krb5_context context) |
710 | 0 | { |
711 | 0 | OM_uint32 major_status; |
712 | 0 | unsigned char *ptr; |
713 | 0 | krb5_data ap_rep; |
714 | 0 | krb5_ap_rep_enc_part *ap_rep_data; |
715 | 0 | krb5_timestamp now; |
716 | 0 | krb5_gss_ctx_id_rec *ctx; |
717 | 0 | krb5_error *krb_error; |
718 | 0 | krb5_error_code code; |
719 | 0 | krb5int_access kaccess; |
720 | |
|
721 | 0 | major_status = GSS_S_FAILURE; |
722 | |
|
723 | 0 | code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION); |
724 | 0 | if (code) |
725 | 0 | goto fail; |
726 | | |
727 | 0 | ctx = (krb5_gss_ctx_id_t) *context_handle; |
728 | | |
729 | | /* make sure the context is non-established, and that certain |
730 | | arguments are unchanged */ |
731 | |
|
732 | 0 | if ((ctx->established) || |
733 | 0 | ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) { |
734 | 0 | code = KG_CONTEXT_ESTABLISHED; |
735 | 0 | goto fail; |
736 | 0 | } |
737 | | |
738 | 0 | if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) { |
739 | 0 | (void)krb5_gss_delete_sec_context(minor_status, |
740 | 0 | context_handle, NULL); |
741 | 0 | code = 0; |
742 | 0 | major_status = GSS_S_BAD_NAME; |
743 | 0 | goto fail; |
744 | 0 | } |
745 | | |
746 | | /* verify the token and leave the AP_REP message in ap_rep */ |
747 | | |
748 | 0 | if (input_token == GSS_C_NO_BUFFER) { |
749 | 0 | (void)krb5_gss_delete_sec_context(minor_status, |
750 | 0 | context_handle, NULL); |
751 | 0 | code = 0; |
752 | 0 | major_status = GSS_S_DEFECTIVE_TOKEN; |
753 | 0 | goto fail; |
754 | 0 | } |
755 | | |
756 | 0 | ptr = (unsigned char *) input_token->value; |
757 | |
|
758 | 0 | if (ctx->gss_flags & GSS_C_DCE_STYLE) { |
759 | | /* Raw AP-REP */ |
760 | 0 | ap_rep.length = input_token->length; |
761 | 0 | } else if (g_verify_token_header(ctx->mech_used, |
762 | 0 | &(ap_rep.length), |
763 | 0 | &ptr, KG_TOK_CTX_AP_REP, |
764 | 0 | input_token->length, 1)) { |
765 | 0 | if (g_verify_token_header((gss_OID) ctx->mech_used, |
766 | 0 | &(ap_rep.length), |
767 | 0 | &ptr, KG_TOK_CTX_ERROR, |
768 | 0 | input_token->length, 1) == 0) { |
769 | | |
770 | | /* Handle a KRB_ERROR message from the server */ |
771 | |
|
772 | 0 | ap_rep.data = (char *)ptr; |
773 | 0 | code = krb5_rd_error(context, &ap_rep, &krb_error); |
774 | 0 | if (code) |
775 | 0 | goto fail; |
776 | 0 | if (krb_error->error) |
777 | 0 | code = (krb5_error_code)krb_error->error + ERROR_TABLE_BASE_krb5; |
778 | 0 | else |
779 | 0 | code = 0; |
780 | 0 | krb5_free_error(context, krb_error); |
781 | 0 | goto fail; |
782 | 0 | } else { |
783 | 0 | *minor_status = 0; |
784 | 0 | return(GSS_S_DEFECTIVE_TOKEN); |
785 | 0 | } |
786 | 0 | } |
787 | 0 | ap_rep.data = (char *)ptr; |
788 | | |
789 | | /* decode the ap_rep */ |
790 | 0 | if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, |
791 | 0 | &ap_rep_data))) { |
792 | | /* |
793 | | * XXX A hack for backwards compatibility. |
794 | | * To be removed in 1999 -- proven |
795 | | */ |
796 | 0 | krb5_auth_con_setuseruserkey(context, ctx->auth_context, |
797 | 0 | &ctx->subkey->keyblock); |
798 | 0 | if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, |
799 | 0 | &ap_rep_data))) |
800 | 0 | goto fail; |
801 | 0 | } |
802 | | |
803 | | /* store away the sequence number */ |
804 | 0 | ctx->seq_recv = ap_rep_data->seq_number; |
805 | 0 | code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv, |
806 | 0 | (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, |
807 | 0 | (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, |
808 | 0 | ctx->proto); |
809 | 0 | if (code) { |
810 | 0 | krb5_free_ap_rep_enc_part(context, ap_rep_data); |
811 | 0 | goto fail; |
812 | 0 | } |
813 | | |
814 | 0 | if (ap_rep_data->subkey != NULL && |
815 | 0 | (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) || |
816 | 0 | ap_rep_data->subkey->enctype != ctx->subkey->keyblock.enctype)) { |
817 | | /* Keep acceptor's subkey. */ |
818 | 0 | ctx->have_acceptor_subkey = 1; |
819 | 0 | code = krb5_k_create_key(context, ap_rep_data->subkey, |
820 | 0 | &ctx->acceptor_subkey); |
821 | 0 | if (code) { |
822 | 0 | krb5_free_ap_rep_enc_part(context, ap_rep_data); |
823 | 0 | goto fail; |
824 | 0 | } |
825 | 0 | code = kg_setup_keys(context, ctx, ctx->acceptor_subkey, |
826 | 0 | &ctx->acceptor_subkey_cksumtype); |
827 | 0 | if (code) { |
828 | 0 | krb5_free_ap_rep_enc_part(context, ap_rep_data); |
829 | 0 | goto fail; |
830 | 0 | } |
831 | 0 | } |
832 | | /* free the ap_rep_data */ |
833 | 0 | krb5_free_ap_rep_enc_part(context, ap_rep_data); |
834 | |
|
835 | 0 | if (ctx->gss_flags & GSS_C_DCE_STYLE) { |
836 | 0 | krb5_data outbuf; |
837 | |
|
838 | 0 | code = krb5_mk_rep_dce(context, ctx->auth_context, &outbuf); |
839 | 0 | if (code) |
840 | 0 | goto fail; |
841 | | |
842 | 0 | code = data_to_gss(&outbuf, output_token); |
843 | 0 | if (code) |
844 | 0 | goto fail; |
845 | 0 | } |
846 | | |
847 | | /* set established */ |
848 | 0 | ctx->established = 1; |
849 | | |
850 | | /* set returns */ |
851 | |
|
852 | 0 | if (time_rec) { |
853 | 0 | if ((code = krb5_timeofday(context, &now))) |
854 | 0 | goto fail; |
855 | 0 | *time_rec = ts_interval(now, ctx->krb_times.endtime); |
856 | 0 | } |
857 | | |
858 | 0 | if (ret_flags) |
859 | 0 | *ret_flags = ctx->gss_flags; |
860 | |
|
861 | 0 | if (actual_mech_type) |
862 | 0 | *actual_mech_type = mech_type; |
863 | | |
864 | | /* success */ |
865 | |
|
866 | 0 | *minor_status = 0; |
867 | 0 | return GSS_S_COMPLETE; |
868 | | |
869 | 0 | fail: |
870 | 0 | (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); |
871 | |
|
872 | 0 | *minor_status = code; |
873 | 0 | return (major_status); |
874 | 0 | } |
875 | | |
876 | | OM_uint32 |
877 | | krb5_gss_init_sec_context_ext( |
878 | | OM_uint32 *minor_status, |
879 | | gss_cred_id_t claimant_cred_handle, |
880 | | gss_ctx_id_t *context_handle, |
881 | | gss_name_t target_name, |
882 | | gss_OID mech_type, |
883 | | OM_uint32 req_flags, |
884 | | OM_uint32 time_req, |
885 | | gss_channel_bindings_t input_chan_bindings, |
886 | | gss_buffer_t input_token, |
887 | | gss_OID *actual_mech_type, |
888 | | gss_buffer_t output_token, |
889 | | OM_uint32 *ret_flags, |
890 | | OM_uint32 *time_rec, |
891 | | krb5_gss_ctx_ext_t exts) |
892 | 0 | { |
893 | 0 | krb5_context context; |
894 | 0 | gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL; |
895 | 0 | krb5_gss_cred_id_t cred; |
896 | 0 | krb5_error_code kerr; |
897 | 0 | OM_uint32 major_status; |
898 | 0 | OM_uint32 tmp_min_stat; |
899 | |
|
900 | 0 | if (*context_handle == GSS_C_NO_CONTEXT) { |
901 | 0 | kerr = krb5_gss_init_context(&context); |
902 | 0 | if (kerr) { |
903 | 0 | *minor_status = kerr; |
904 | 0 | return GSS_S_FAILURE; |
905 | 0 | } |
906 | 0 | if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) { |
907 | 0 | save_error_info(*minor_status, context); |
908 | 0 | krb5_free_context(context); |
909 | 0 | return GSS_S_FAILURE; |
910 | 0 | } |
911 | 0 | } else { |
912 | 0 | context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context; |
913 | 0 | } |
914 | | |
915 | | /* set up return values so they can be "freed" successfully */ |
916 | | |
917 | 0 | major_status = GSS_S_FAILURE; /* Default major code */ |
918 | 0 | output_token->length = 0; |
919 | 0 | output_token->value = NULL; |
920 | 0 | if (actual_mech_type) |
921 | 0 | *actual_mech_type = NULL; |
922 | | |
923 | | /* verify the mech_type */ |
924 | |
|
925 | 0 | if (mech_type == GSS_C_NULL_OID || g_OID_equal(mech_type, gss_mech_krb5)) { |
926 | 0 | mech_type = (gss_OID) gss_mech_krb5; |
927 | 0 | } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { |
928 | 0 | mech_type = (gss_OID) gss_mech_krb5_old; |
929 | 0 | } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) { |
930 | 0 | mech_type = (gss_OID) gss_mech_krb5_wrong; |
931 | 0 | } else if (g_OID_equal(mech_type, gss_mech_iakerb)) { |
932 | 0 | mech_type = (gss_OID) gss_mech_iakerb; |
933 | 0 | } else { |
934 | 0 | *minor_status = 0; |
935 | 0 | if (*context_handle == GSS_C_NO_CONTEXT) |
936 | 0 | krb5_free_context(context); |
937 | 0 | return(GSS_S_BAD_MECH); |
938 | 0 | } |
939 | | |
940 | | /* is this a new connection or not? */ |
941 | | |
942 | | /*SUPPRESS 29*/ |
943 | 0 | if (*context_handle == GSS_C_NO_CONTEXT) { |
944 | | /* verify the credential, or use the default */ |
945 | | /*SUPPRESS 29*/ |
946 | 0 | if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { |
947 | 0 | major_status = kg_get_defcred(minor_status, &defcred); |
948 | 0 | if (major_status && GSS_ERROR(major_status)) { |
949 | 0 | if (*context_handle == GSS_C_NO_CONTEXT) |
950 | 0 | krb5_free_context(context); |
951 | 0 | return(major_status); |
952 | 0 | } |
953 | 0 | claimant_cred_handle = defcred; |
954 | 0 | } |
955 | | |
956 | 0 | major_status = kg_cred_resolve(minor_status, context, |
957 | 0 | claimant_cred_handle, target_name); |
958 | 0 | if (GSS_ERROR(major_status)) { |
959 | 0 | save_error_info(*minor_status, context); |
960 | 0 | krb5_gss_release_cred(&tmp_min_stat, &defcred); |
961 | 0 | if (*context_handle == GSS_C_NO_CONTEXT) |
962 | 0 | krb5_free_context(context); |
963 | 0 | return(major_status); |
964 | 0 | } |
965 | 0 | cred = (krb5_gss_cred_id_t)claimant_cred_handle; |
966 | |
|
967 | 0 | major_status = kg_new_connection(minor_status, cred, context_handle, |
968 | 0 | target_name, mech_type, req_flags, |
969 | 0 | time_req, input_chan_bindings, |
970 | 0 | input_token, actual_mech_type, |
971 | 0 | output_token, ret_flags, time_rec, |
972 | 0 | context, exts); |
973 | 0 | k5_mutex_unlock(&cred->lock); |
974 | 0 | krb5_gss_release_cred(&tmp_min_stat, &defcred); |
975 | 0 | if (*context_handle == GSS_C_NO_CONTEXT) { |
976 | 0 | save_error_info (*minor_status, context); |
977 | 0 | krb5_free_context(context); |
978 | 0 | } else |
979 | 0 | ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context; |
980 | 0 | } else { |
981 | | /* mutual_auth doesn't care about the credentials */ |
982 | 0 | major_status = mutual_auth(minor_status, context_handle, |
983 | 0 | target_name, mech_type, req_flags, |
984 | 0 | time_req, input_chan_bindings, |
985 | 0 | input_token, actual_mech_type, |
986 | 0 | output_token, ret_flags, time_rec, |
987 | 0 | context); |
988 | | /* If context_handle is now NO_CONTEXT, mutual_auth called |
989 | | delete_sec_context, which would've zapped the krb5 context |
990 | | too. */ |
991 | 0 | } |
992 | | |
993 | 0 | return(major_status); |
994 | 0 | } |
995 | | |
996 | | #ifndef _WIN32 |
997 | | k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER; |
998 | | static int kdc_flag = 0; |
999 | | #endif |
1000 | | |
1001 | | krb5_error_code |
1002 | | krb5_gss_init_context (krb5_context *ctxp) |
1003 | 53 | { |
1004 | 53 | krb5_error_code err; |
1005 | 53 | #ifndef _WIN32 |
1006 | 53 | int is_kdc; |
1007 | 53 | #endif |
1008 | | |
1009 | 53 | err = gss_krb5int_initialize_library(); |
1010 | 53 | if (err) |
1011 | 0 | return err; |
1012 | 53 | #ifndef _WIN32 |
1013 | 53 | k5_mutex_lock(&kg_kdc_flag_mutex); |
1014 | 53 | is_kdc = kdc_flag; |
1015 | 53 | k5_mutex_unlock(&kg_kdc_flag_mutex); |
1016 | | |
1017 | 53 | if (is_kdc) |
1018 | 0 | return krb5int_init_context_kdc(ctxp); |
1019 | 53 | #endif |
1020 | | |
1021 | 53 | return krb5_init_context(ctxp); |
1022 | 53 | } |
1023 | | |
1024 | | #ifndef _WIN32 |
1025 | | OM_uint32 |
1026 | | krb5int_gss_use_kdc_context(OM_uint32 *minor_status, |
1027 | | const gss_OID desired_mech, |
1028 | | const gss_OID desired_object, |
1029 | | gss_buffer_t value) |
1030 | 0 | { |
1031 | 0 | OM_uint32 err; |
1032 | |
|
1033 | 0 | *minor_status = 0; |
1034 | |
|
1035 | 0 | err = gss_krb5int_initialize_library(); |
1036 | 0 | if (err) |
1037 | 0 | return err; |
1038 | 0 | k5_mutex_lock(&kg_kdc_flag_mutex); |
1039 | 0 | kdc_flag = 1; |
1040 | 0 | k5_mutex_unlock(&kg_kdc_flag_mutex); |
1041 | 0 | return GSS_S_COMPLETE; |
1042 | 0 | } |
1043 | | #endif |
1044 | | |
1045 | | OM_uint32 KRB5_CALLCONV |
1046 | | krb5_gss_init_sec_context(OM_uint32 *minor_status, |
1047 | | gss_cred_id_t claimant_cred_handle, |
1048 | | gss_ctx_id_t *context_handle, |
1049 | | gss_name_t target_name, gss_OID mech_type, |
1050 | | OM_uint32 req_flags, OM_uint32 time_req, |
1051 | | gss_channel_bindings_t input_chan_bindings, |
1052 | | gss_buffer_t input_token, gss_OID *actual_mech_type, |
1053 | | gss_buffer_t output_token, OM_uint32 *ret_flags, |
1054 | | OM_uint32 *time_rec) |
1055 | 0 | { |
1056 | 0 | krb5_gss_ctx_ext_rec exts; |
1057 | |
|
1058 | 0 | memset(&exts, 0, sizeof(exts)); |
1059 | |
|
1060 | 0 | return krb5_gss_init_sec_context_ext(minor_status, |
1061 | 0 | claimant_cred_handle, |
1062 | 0 | context_handle, |
1063 | 0 | target_name, |
1064 | 0 | mech_type, |
1065 | 0 | req_flags, |
1066 | 0 | time_req, |
1067 | 0 | input_chan_bindings, |
1068 | 0 | input_token, |
1069 | 0 | actual_mech_type, |
1070 | 0 | output_token, |
1071 | 0 | ret_flags, |
1072 | 0 | time_rec, |
1073 | 0 | &exts); |
1074 | 0 | } |