move failure testing into build function
[heimdal.git] / lib / gssapi / krb5 / init_sec_context.c
blobefd5ae9c4f006f618de0c5195b81220a2eaa5262
1 /*
2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "gssapi_locl.h"
36 RCSID("$Id$");
39 * copy the addresses from `input_chan_bindings' (if any) to
40 * the auth context `ac'
43 static OM_uint32
44 set_addresses (krb5_auth_context ac,
45 const gss_channel_bindings_t input_chan_bindings)
47 /* Port numbers are expected to be in application_data.value,
48 * initator's port first */
50 krb5_address initiator_addr, acceptor_addr;
51 krb5_error_code kret;
53 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
54 || input_chan_bindings->application_data.length !=
55 2 * sizeof(ac->local_port))
56 return 0;
58 memset(&initiator_addr, 0, sizeof(initiator_addr));
59 memset(&acceptor_addr, 0, sizeof(acceptor_addr));
61 ac->local_port =
62 *(int16_t *) input_chan_bindings->application_data.value;
64 ac->remote_port =
65 *((int16_t *) input_chan_bindings->application_data.value + 1);
67 kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
68 &input_chan_bindings->acceptor_address,
69 ac->remote_port,
70 &acceptor_addr);
71 if (kret)
72 return kret;
74 kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
75 &input_chan_bindings->initiator_address,
76 ac->local_port,
77 &initiator_addr);
78 if (kret) {
79 krb5_free_address (gssapi_krb5_context, &acceptor_addr);
80 return kret;
83 kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
84 ac,
85 &initiator_addr, /* local address */
86 &acceptor_addr); /* remote address */
88 krb5_free_address (gssapi_krb5_context, &initiator_addr);
89 krb5_free_address (gssapi_krb5_context, &acceptor_addr);
91 #if 0
92 free(input_chan_bindings->application_data.value);
93 input_chan_bindings->application_data.value = NULL;
94 input_chan_bindings->application_data.length = 0;
95 #endif
97 return kret;
101 * handle delegated creds in init-sec-context
104 static void
105 do_delegation (krb5_auth_context ac,
106 krb5_ccache ccache,
107 krb5_creds *cred,
108 const gss_name_t target_name,
109 krb5_data *fwd_data,
110 int *flags)
112 krb5_creds creds;
113 krb5_kdc_flags fwd_flags;
114 krb5_error_code kret;
116 memset (&creds, 0, sizeof(creds));
117 krb5_data_zero (fwd_data);
119 kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
120 if (kret)
121 goto out;
123 kret = krb5_build_principal(gssapi_krb5_context,
124 &creds.server,
125 strlen(creds.client->realm),
126 creds.client->realm,
127 KRB5_TGS_NAME,
128 creds.client->realm,
129 NULL);
130 if (kret)
131 goto out;
133 creds.times.endtime = 0;
135 fwd_flags.i = 0;
136 fwd_flags.b.forwarded = 1;
137 fwd_flags.b.forwardable = 1;
139 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
140 target_name->name.name_string.len < 2)
141 goto out;
143 kret = krb5_get_forwarded_creds(gssapi_krb5_context,
145 ccache,
146 fwd_flags.i,
147 target_name->name.name_string.val[1],
148 &creds,
149 fwd_data);
151 out:
152 if (kret)
153 *flags &= ~GSS_C_DELEG_FLAG;
154 else
155 *flags |= GSS_C_DELEG_FLAG;
157 if (creds.client)
158 krb5_free_principal(gssapi_krb5_context, creds.client);
159 if (creds.server)
160 krb5_free_principal(gssapi_krb5_context, creds.server);
164 * first stage of init-sec-context
167 static OM_uint32
168 init_auth
169 (OM_uint32 * minor_status,
170 const gss_cred_id_t initiator_cred_handle,
171 gss_ctx_id_t * context_handle,
172 const gss_name_t target_name,
173 const gss_OID mech_type,
174 OM_uint32 req_flags,
175 OM_uint32 time_req,
176 const gss_channel_bindings_t input_chan_bindings,
177 const gss_buffer_t input_token,
178 gss_OID * actual_mech_type,
179 gss_buffer_t output_token,
180 OM_uint32 * ret_flags,
181 OM_uint32 * time_rec
184 OM_uint32 ret = GSS_S_FAILURE;
185 krb5_error_code kret;
186 krb5_flags ap_options;
187 krb5_creds this_cred, *cred;
188 krb5_data outbuf;
189 krb5_ccache ccache;
190 u_int32_t flags;
191 Authenticator *auth;
192 krb5_data authenticator;
193 Checksum cksum;
194 krb5_enctype enctype;
195 krb5_data fwd_data;
197 krb5_data_zero(&outbuf);
198 krb5_data_zero(&fwd_data);
200 *minor_status = 0;
202 *context_handle = malloc(sizeof(**context_handle));
203 if (*context_handle == NULL) {
204 *minor_status = ENOMEM;
205 return GSS_S_FAILURE;
208 (*context_handle)->auth_context = NULL;
209 (*context_handle)->source = NULL;
210 (*context_handle)->target = NULL;
211 (*context_handle)->flags = 0;
212 (*context_handle)->more_flags = 0;
213 (*context_handle)->ticket = NULL;
214 (*context_handle)->lifetime = GSS_C_INDEFINITE;
216 kret = krb5_auth_con_init (gssapi_krb5_context,
217 &(*context_handle)->auth_context);
218 if (kret) {
219 gssapi_krb5_set_error_string ();
220 *minor_status = kret;
221 ret = GSS_S_FAILURE;
222 goto failure;
225 kret = set_addresses ((*context_handle)->auth_context,
226 input_chan_bindings);
227 if (kret) {
228 *minor_status = kret;
229 ret = GSS_S_BAD_BINDINGS;
230 goto failure;
234 int32_t tmp;
236 krb5_auth_con_getflags(gssapi_krb5_context,
237 (*context_handle)->auth_context,
238 &tmp);
239 tmp |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
240 krb5_auth_con_setflags(gssapi_krb5_context,
241 (*context_handle)->auth_context,
242 tmp);
245 if (actual_mech_type)
246 *actual_mech_type = GSS_KRB5_MECHANISM;
248 if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
249 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
250 if (kret) {
251 gssapi_krb5_set_error_string ();
252 *minor_status = kret;
253 ret = GSS_S_FAILURE;
254 goto failure;
256 } else
257 ccache = initiator_cred_handle->ccache;
259 kret = krb5_cc_get_principal (gssapi_krb5_context,
260 ccache,
261 &(*context_handle)->source);
262 if (kret) {
263 gssapi_krb5_set_error_string ();
264 *minor_status = kret;
265 ret = GSS_S_FAILURE;
266 goto failure;
269 kret = krb5_copy_principal (gssapi_krb5_context,
270 target_name,
271 &(*context_handle)->target);
272 if (kret) {
273 gssapi_krb5_set_error_string ();
274 *minor_status = kret;
275 ret = GSS_S_FAILURE;
276 goto failure;
279 ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
280 if (ret)
281 goto failure;
284 memset(&this_cred, 0, sizeof(this_cred));
285 this_cred.client = (*context_handle)->source;
286 this_cred.server = (*context_handle)->target;
287 if (time_req && time_req != GSS_C_INDEFINITE) {
288 krb5_timestamp ts;
290 krb5_timeofday (gssapi_krb5_context, &ts);
291 this_cred.times.endtime = ts + time_req;
292 } else
293 this_cred.times.endtime = 0;
294 this_cred.session.keytype = 0;
296 kret = krb5_get_credentials (gssapi_krb5_context,
297 KRB5_TC_MATCH_KEYTYPE,
298 ccache,
299 &this_cred,
300 &cred);
302 if (kret) {
303 gssapi_krb5_set_error_string ();
304 *minor_status = kret;
305 ret = GSS_S_FAILURE;
306 goto failure;
309 (*context_handle)->lifetime = cred->times.endtime;
311 krb5_auth_con_setkey(gssapi_krb5_context,
312 (*context_handle)->auth_context,
313 &cred->session);
315 kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context,
316 (*context_handle)->auth_context,
317 &cred->session);
318 if(kret) {
319 gssapi_krb5_set_error_string ();
320 *minor_status = kret;
321 ret = GSS_S_FAILURE;
322 goto failure;
325 flags = 0;
326 ap_options = 0;
327 if (req_flags & GSS_C_DELEG_FLAG)
328 do_delegation ((*context_handle)->auth_context,
329 ccache, cred, target_name, &fwd_data, &flags);
331 if (req_flags & GSS_C_MUTUAL_FLAG) {
332 flags |= GSS_C_MUTUAL_FLAG;
333 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
336 if (req_flags & GSS_C_REPLAY_FLAG)
337 ; /* XXX */
338 if (req_flags & GSS_C_SEQUENCE_FLAG)
339 ; /* XXX */
340 if (req_flags & GSS_C_ANON_FLAG)
341 ; /* XXX */
342 flags |= GSS_C_CONF_FLAG;
343 flags |= GSS_C_INTEG_FLAG;
344 flags |= GSS_C_SEQUENCE_FLAG;
345 flags |= GSS_C_TRANS_FLAG;
347 if (ret_flags)
348 *ret_flags = flags;
349 (*context_handle)->flags = flags;
350 (*context_handle)->more_flags |= LOCAL;
352 ret = gssapi_krb5_create_8003_checksum (minor_status,
353 input_chan_bindings,
354 flags,
355 &fwd_data,
356 &cksum);
357 krb5_data_free (&fwd_data);
358 if (ret)
359 goto failure;
361 #if 1
362 enctype = (*context_handle)->auth_context->keyblock->keytype;
363 #else
364 if ((*context_handle)->auth_context->enctype)
365 enctype = (*context_handle)->auth_context->enctype;
366 else {
367 kret = krb5_keytype_to_enctype(gssapi_krb5_context,
368 (*context_handle)->auth_context->keyblock->keytype,
369 &enctype);
370 if (kret)
371 return kret;
373 #endif
375 kret = krb5_build_authenticator (gssapi_krb5_context,
376 (*context_handle)->auth_context,
377 enctype,
378 cred,
379 &cksum,
380 &auth,
381 &authenticator,
382 KRB5_KU_AP_REQ_AUTH);
384 if (kret) {
385 gssapi_krb5_set_error_string ();
386 *minor_status = kret;
387 ret = GSS_S_FAILURE;
388 goto failure;
391 kret = krb5_build_ap_req (gssapi_krb5_context,
392 enctype,
393 cred,
394 ap_options,
395 authenticator,
396 &outbuf);
398 if (kret) {
399 gssapi_krb5_set_error_string ();
400 *minor_status = kret;
401 ret = GSS_S_FAILURE;
402 goto failure;
405 ret = gssapi_krb5_encapsulate (minor_status, &outbuf, output_token,
406 "\x01\x00");
407 if (ret)
408 goto failure;
410 krb5_data_free (&outbuf);
412 if (flags & GSS_C_MUTUAL_FLAG) {
413 return GSS_S_CONTINUE_NEEDED;
414 } else {
415 if (time_rec)
416 *time_rec = (*context_handle)->lifetime;
418 (*context_handle)->more_flags |= OPEN;
419 return GSS_S_COMPLETE;
422 failure:
423 krb5_auth_con_free (gssapi_krb5_context,
424 (*context_handle)->auth_context);
425 if((*context_handle)->source)
426 krb5_free_principal (gssapi_krb5_context,
427 (*context_handle)->source);
428 if((*context_handle)->target)
429 krb5_free_principal (gssapi_krb5_context,
430 (*context_handle)->target);
431 free (*context_handle);
432 krb5_data_free (&outbuf);
433 *context_handle = GSS_C_NO_CONTEXT;
434 return ret;
437 static OM_uint32
438 repl_mutual
439 (OM_uint32 * minor_status,
440 const gss_cred_id_t initiator_cred_handle,
441 gss_ctx_id_t * context_handle,
442 const gss_name_t target_name,
443 const gss_OID mech_type,
444 OM_uint32 req_flags,
445 OM_uint32 time_req,
446 const gss_channel_bindings_t input_chan_bindings,
447 const gss_buffer_t input_token,
448 gss_OID * actual_mech_type,
449 gss_buffer_t output_token,
450 OM_uint32 * ret_flags,
451 OM_uint32 * time_rec
454 OM_uint32 ret;
455 krb5_error_code kret;
456 krb5_data indata;
457 krb5_ap_rep_enc_part *repl;
459 output_token->length = 0;
460 output_token->value = NULL;
462 if (actual_mech_type)
463 *actual_mech_type = GSS_KRB5_MECHANISM;
465 ret = gssapi_krb5_decapsulate (minor_status, input_token, &indata,
466 "\x02\x00");
467 if (ret)
468 /* XXX - Handle AP_ERROR */
469 return ret;
471 kret = krb5_rd_rep (gssapi_krb5_context,
472 (*context_handle)->auth_context,
473 &indata,
474 &repl);
475 if (kret) {
476 gssapi_krb5_set_error_string ();
477 *minor_status = kret;
478 return GSS_S_FAILURE;
480 krb5_free_ap_rep_enc_part (gssapi_krb5_context,
481 repl);
483 (*context_handle)->more_flags |= OPEN;
485 if (time_rec)
486 *time_rec = (*context_handle)->lifetime;
487 if (ret_flags)
488 *ret_flags = (*context_handle)->flags;
490 *minor_status = 0;
491 return GSS_S_COMPLETE;
495 * gss_init_sec_context
498 OM_uint32 gss_init_sec_context
499 (OM_uint32 * minor_status,
500 const gss_cred_id_t initiator_cred_handle,
501 gss_ctx_id_t * context_handle,
502 const gss_name_t target_name,
503 const gss_OID mech_type,
504 OM_uint32 req_flags,
505 OM_uint32 time_req,
506 const gss_channel_bindings_t input_chan_bindings,
507 const gss_buffer_t input_token,
508 gss_OID * actual_mech_type,
509 gss_buffer_t output_token,
510 OM_uint32 * ret_flags,
511 OM_uint32 * time_rec
514 GSSAPI_KRB5_INIT ();
516 output_token->length = 0;
517 output_token->value = NULL;
519 if (ret_flags)
520 *ret_flags = 0;
521 if (time_rec)
522 *time_rec = 0;
524 if (target_name == GSS_C_NO_NAME) {
525 if (actual_mech_type)
526 *actual_mech_type = GSS_C_NO_OID;
527 *minor_status = 0;
528 return GSS_S_BAD_NAME;
531 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
532 return init_auth (minor_status,
533 initiator_cred_handle,
534 context_handle,
535 target_name,
536 mech_type,
537 req_flags,
538 time_req,
539 input_chan_bindings,
540 input_token,
541 actual_mech_type,
542 output_token,
543 ret_flags,
544 time_rec);
545 else
546 return repl_mutual(minor_status,
547 initiator_cred_handle,
548 context_handle,
549 target_name,
550 mech_type,
551 req_flags,
552 time_req,
553 input_chan_bindings,
554 input_token,
555 actual_mech_type,
556 output_token,
557 ret_flags,
558 time_rec);