fix typo
[heimdal.git] / lib / gssapi / krb5 / init_sec_context.c
blobf71474149f0daab24724382ac138d6da71007aa0
1 /*
2 * Copyright (c) 1997 - 2001 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_keyblock *subkey;
115 krb5_error_code kret;
117 memset (&creds, 0, sizeof(creds));
118 krb5_data_zero (fwd_data);
120 kret = krb5_generate_subkey (gssapi_krb5_context, &cred->session, &subkey);
121 if (kret)
122 goto out;
124 kret = krb5_auth_con_setlocalsubkey(gssapi_krb5_context, ac, subkey);
125 krb5_free_keyblock (gssapi_krb5_context, subkey);
126 if (kret)
127 goto out;
129 kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
130 if (kret)
131 goto out;
133 kret = krb5_build_principal(gssapi_krb5_context,
134 &creds.server,
135 strlen(creds.client->realm),
136 creds.client->realm,
137 KRB5_TGS_NAME,
138 creds.client->realm,
139 NULL);
140 if (kret)
141 goto out;
143 creds.times.endtime = 0;
145 fwd_flags.i = 0;
146 fwd_flags.b.forwarded = 1;
147 fwd_flags.b.forwardable = 1;
149 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
150 target_name->name.name_string.len < 2)
151 goto out;
153 kret = krb5_get_forwarded_creds(gssapi_krb5_context,
155 ccache,
156 fwd_flags.i,
157 target_name->name.name_string.val[1],
158 &creds,
159 fwd_data);
161 out:
162 if (kret)
163 *flags &= ~GSS_C_DELEG_FLAG;
164 else
165 *flags |= GSS_C_DELEG_FLAG;
167 if (creds.client)
168 krb5_free_principal(gssapi_krb5_context, creds.client);
169 if (creds.server)
170 krb5_free_principal(gssapi_krb5_context, creds.server);
174 * first stage of init-sec-context
177 static OM_uint32
178 init_auth
179 (OM_uint32 * minor_status,
180 const gss_cred_id_t initiator_cred_handle,
181 gss_ctx_id_t * context_handle,
182 const gss_name_t target_name,
183 const gss_OID mech_type,
184 OM_uint32 req_flags,
185 OM_uint32 time_req,
186 const gss_channel_bindings_t input_chan_bindings,
187 const gss_buffer_t input_token,
188 gss_OID * actual_mech_type,
189 gss_buffer_t output_token,
190 OM_uint32 * ret_flags,
191 OM_uint32 * time_rec
194 OM_uint32 ret = GSS_S_FAILURE;
195 krb5_error_code kret;
196 krb5_flags ap_options;
197 krb5_creds this_cred, *cred;
198 krb5_data outbuf;
199 krb5_ccache ccache;
200 u_int32_t flags;
201 Authenticator *auth;
202 krb5_data authenticator;
203 Checksum cksum;
204 krb5_enctype enctype;
205 krb5_data fwd_data;
207 output_token->length = 0;
208 output_token->value = NULL;
210 krb5_data_zero(&outbuf);
211 krb5_data_zero(&fwd_data);
213 *minor_status = 0;
215 *context_handle = malloc(sizeof(**context_handle));
216 if (*context_handle == NULL) {
217 *minor_status = ENOMEM;
218 return GSS_S_FAILURE;
221 (*context_handle)->auth_context = NULL;
222 (*context_handle)->source = NULL;
223 (*context_handle)->target = NULL;
224 (*context_handle)->flags = 0;
225 (*context_handle)->more_flags = 0;
226 (*context_handle)->ticket = NULL;
228 kret = krb5_auth_con_init (gssapi_krb5_context,
229 &(*context_handle)->auth_context);
230 if (kret) {
231 *minor_status = kret;
232 ret = GSS_S_FAILURE;
233 goto failure;
236 kret = set_addresses ((*context_handle)->auth_context,
237 input_chan_bindings);
238 if (kret) {
239 *minor_status = kret;
240 ret = GSS_S_BAD_BINDINGS;
241 goto failure;
245 int32_t tmp;
247 krb5_auth_con_getflags(gssapi_krb5_context,
248 (*context_handle)->auth_context,
249 &tmp);
250 tmp |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
251 krb5_auth_con_setflags(gssapi_krb5_context,
252 (*context_handle)->auth_context,
253 tmp);
256 if (actual_mech_type)
257 *actual_mech_type = GSS_KRB5_MECHANISM;
259 if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
260 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
261 if (kret) {
262 *minor_status = kret;
263 ret = GSS_S_FAILURE;
264 goto failure;
266 } else
267 ccache = initiator_cred_handle->ccache;
269 kret = krb5_cc_get_principal (gssapi_krb5_context,
270 ccache,
271 &(*context_handle)->source);
272 if (kret) {
273 *minor_status = kret;
274 ret = GSS_S_FAILURE;
275 goto failure;
278 kret = krb5_copy_principal (gssapi_krb5_context,
279 target_name,
280 &(*context_handle)->target);
281 if (kret) {
282 *minor_status = kret;
283 ret = GSS_S_FAILURE;
284 goto failure;
287 memset(&this_cred, 0, sizeof(this_cred));
288 this_cred.client = (*context_handle)->source;
289 this_cred.server = (*context_handle)->target;
290 if (time_req) {
291 krb5_timestamp ts;
293 krb5_timeofday (gssapi_krb5_context, &ts);
294 this_cred.times.endtime = ts + time_req;
295 } else
296 this_cred.times.endtime = 0;
297 this_cred.session.keytype = 0;
299 kret = krb5_get_credentials (gssapi_krb5_context,
300 KRB5_TC_MATCH_KEYTYPE,
301 ccache,
302 &this_cred,
303 &cred);
305 if (kret) {
306 *minor_status = kret;
307 ret = GSS_S_FAILURE;
308 goto failure;
311 krb5_auth_con_setkey(gssapi_krb5_context,
312 (*context_handle)->auth_context,
313 &cred->session);
315 flags = 0;
316 ap_options = 0;
317 if (req_flags & GSS_C_DELEG_FLAG)
318 do_delegation ((*context_handle)->auth_context,
319 ccache, cred, target_name, &fwd_data, &flags);
321 if (req_flags & GSS_C_MUTUAL_FLAG) {
322 flags |= GSS_C_MUTUAL_FLAG;
323 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
326 if (req_flags & GSS_C_REPLAY_FLAG)
327 ; /* XXX */
328 if (req_flags & GSS_C_SEQUENCE_FLAG)
329 ; /* XXX */
330 if (req_flags & GSS_C_ANON_FLAG)
331 ; /* XXX */
332 flags |= GSS_C_CONF_FLAG;
333 flags |= GSS_C_INTEG_FLAG;
334 flags |= GSS_C_SEQUENCE_FLAG;
335 flags |= GSS_C_TRANS_FLAG;
337 if (ret_flags)
338 *ret_flags = flags;
339 (*context_handle)->flags = flags;
340 (*context_handle)->more_flags = LOCAL;
342 kret = gssapi_krb5_create_8003_checksum (input_chan_bindings,
343 flags,
344 &fwd_data,
345 &cksum);
346 krb5_data_free (&fwd_data);
347 if (kret) {
348 *minor_status = kret;
349 ret = GSS_S_FAILURE;
350 goto failure;
353 #if 1
354 enctype = (*context_handle)->auth_context->keyblock->keytype;
355 #else
356 if ((*context_handle)->auth_context->enctype)
357 enctype = (*context_handle)->auth_context->enctype;
358 else {
359 kret = krb5_keytype_to_enctype(gssapi_krb5_context,
360 (*context_handle)->auth_context->keyblock->keytype,
361 &enctype);
362 if (kret)
363 return kret;
365 #endif
367 kret = krb5_build_authenticator (gssapi_krb5_context,
368 (*context_handle)->auth_context,
369 enctype,
370 cred,
371 &cksum,
372 &auth,
373 &authenticator,
374 KRB5_KU_AP_REQ_AUTH);
376 if (kret) {
377 *minor_status = kret;
378 ret = GSS_S_FAILURE;
379 goto failure;
382 kret = krb5_build_ap_req (gssapi_krb5_context,
383 enctype,
384 cred,
385 ap_options,
386 authenticator,
387 &outbuf);
389 if (kret) {
390 *minor_status = kret;
391 ret = GSS_S_FAILURE;
392 goto failure;
395 ret = gssapi_krb5_encapsulate (&outbuf, output_token, "\x01\x00");
396 if (ret) {
397 *minor_status = kret;
398 goto failure;
401 krb5_data_free (&outbuf);
403 if (flags & GSS_C_MUTUAL_FLAG) {
404 return GSS_S_CONTINUE_NEEDED;
405 } else {
406 (*context_handle)->more_flags |= OPEN;
407 return GSS_S_COMPLETE;
410 failure:
411 krb5_auth_con_free (gssapi_krb5_context,
412 (*context_handle)->auth_context);
413 if((*context_handle)->source)
414 krb5_free_principal (gssapi_krb5_context,
415 (*context_handle)->source);
416 if((*context_handle)->target)
417 krb5_free_principal (gssapi_krb5_context,
418 (*context_handle)->target);
419 free (*context_handle);
420 krb5_data_free (&outbuf);
421 *context_handle = GSS_C_NO_CONTEXT;
422 return ret;
425 static OM_uint32
426 repl_mutual
427 (OM_uint32 * minor_status,
428 const gss_cred_id_t initiator_cred_handle,
429 gss_ctx_id_t * context_handle,
430 const gss_name_t target_name,
431 const gss_OID mech_type,
432 OM_uint32 req_flags,
433 OM_uint32 time_req,
434 const gss_channel_bindings_t input_chan_bindings,
435 const gss_buffer_t input_token,
436 gss_OID * actual_mech_type,
437 gss_buffer_t output_token,
438 OM_uint32 * ret_flags,
439 OM_uint32 * time_rec
442 OM_uint32 ret;
443 krb5_error_code kret;
444 krb5_data indata;
445 krb5_ap_rep_enc_part *repl;
447 ret = gssapi_krb5_decapsulate (input_token, &indata, "\x02\x00");
448 if (ret) {
449 /* XXX - Handle AP_ERROR */
450 return GSS_S_FAILURE;
453 kret = krb5_rd_rep (gssapi_krb5_context,
454 (*context_handle)->auth_context,
455 &indata,
456 &repl);
457 if (kret)
458 return GSS_S_FAILURE;
459 krb5_free_ap_rep_enc_part (gssapi_krb5_context,
460 repl);
462 output_token->length = 0;
464 (*context_handle)->more_flags |= OPEN;
466 return GSS_S_COMPLETE;
470 * gss_init_sec_context
473 OM_uint32 gss_init_sec_context
474 (OM_uint32 * minor_status,
475 const gss_cred_id_t initiator_cred_handle,
476 gss_ctx_id_t * context_handle,
477 const gss_name_t target_name,
478 const gss_OID mech_type,
479 OM_uint32 req_flags,
480 OM_uint32 time_req,
481 const gss_channel_bindings_t input_chan_bindings,
482 const gss_buffer_t input_token,
483 gss_OID * actual_mech_type,
484 gss_buffer_t output_token,
485 OM_uint32 * ret_flags,
486 OM_uint32 * time_rec
489 gssapi_krb5_init ();
491 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
492 return init_auth (minor_status,
493 initiator_cred_handle,
494 context_handle,
495 target_name,
496 mech_type,
497 req_flags,
498 time_req,
499 input_chan_bindings,
500 input_token,
501 actual_mech_type,
502 output_token,
503 ret_flags,
504 time_rec);
505 else
506 return repl_mutual(minor_status,
507 initiator_cred_handle,
508 context_handle,
509 target_name,
510 mech_type,
511 req_flags,
512 time_req,
513 input_chan_bindings,
514 input_token,
515 actual_mech_type,
516 output_token,
517 ret_flags,
518 time_rec);