Release 0.3c
[heimdal.git] / lib / gssapi / init_sec_context.c
blob34ef08d638ce1508ffbf3c2220fd40a8e340ff25
1 /*
2 * Copyright (c) 1997 - 2000 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 outbuf.length = 0;
211 outbuf.data = NULL;
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 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
260 if (kret) {
261 *minor_status = kret;
262 ret = GSS_S_FAILURE;
263 goto failure;
266 kret = krb5_cc_get_principal (gssapi_krb5_context,
267 ccache,
268 &(*context_handle)->source);
269 if (kret) {
270 *minor_status = kret;
271 ret = GSS_S_FAILURE;
272 goto failure;
275 kret = krb5_copy_principal (gssapi_krb5_context,
276 target_name,
277 &(*context_handle)->target);
278 if (kret) {
279 *minor_status = kret;
280 ret = GSS_S_FAILURE;
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) {
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 *minor_status = kret;
304 ret = GSS_S_FAILURE;
305 goto failure;
308 krb5_auth_con_setkey(gssapi_krb5_context,
309 (*context_handle)->auth_context,
310 &cred->session);
312 flags = 0;
313 ap_options = 0;
314 if (req_flags & GSS_C_DELEG_FLAG)
315 do_delegation ((*context_handle)->auth_context,
316 ccache, cred, target_name, &fwd_data, &flags);
318 if (req_flags & GSS_C_MUTUAL_FLAG) {
319 flags |= GSS_C_MUTUAL_FLAG;
320 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
323 if (req_flags & GSS_C_REPLAY_FLAG)
324 ; /* XXX */
325 if (req_flags & GSS_C_SEQUENCE_FLAG)
326 ; /* XXX */
327 if (req_flags & GSS_C_ANON_FLAG)
328 ; /* XXX */
329 flags |= GSS_C_CONF_FLAG;
330 flags |= GSS_C_INTEG_FLAG;
331 flags |= GSS_C_SEQUENCE_FLAG;
332 flags |= GSS_C_TRANS_FLAG;
334 if (ret_flags)
335 *ret_flags = flags;
336 (*context_handle)->flags = flags;
337 (*context_handle)->more_flags = LOCAL;
339 kret = gssapi_krb5_create_8003_checksum (input_chan_bindings,
340 flags,
341 &fwd_data,
342 &cksum);
343 krb5_data_free (&fwd_data);
344 if (kret) {
345 *minor_status = kret;
346 ret = GSS_S_FAILURE;
347 goto failure;
350 #if 1
351 enctype = (*context_handle)->auth_context->keyblock->keytype;
352 #else
353 if ((*context_handle)->auth_context->enctype)
354 enctype = (*context_handle)->auth_context->enctype;
355 else {
356 kret = krb5_keytype_to_enctype(gssapi_krb5_context,
357 (*context_handle)->auth_context->keyblock->keytype,
358 &enctype);
359 if (kret)
360 return kret;
362 #endif
364 kret = krb5_build_authenticator (gssapi_krb5_context,
365 (*context_handle)->auth_context,
366 enctype,
367 cred,
368 &cksum,
369 &auth,
370 &authenticator);
372 if (kret) {
373 *minor_status = kret;
374 ret = GSS_S_FAILURE;
375 goto failure;
378 kret = krb5_build_ap_req (gssapi_krb5_context,
379 enctype,
380 cred,
381 ap_options,
382 authenticator,
383 &outbuf);
385 if (kret) {
386 *minor_status = kret;
387 ret = GSS_S_FAILURE;
388 goto failure;
391 ret = gssapi_krb5_encapsulate (&outbuf, output_token, "\x01\x00");
392 if (ret) {
393 *minor_status = kret;
394 goto failure;
397 krb5_data_free (&outbuf);
399 if (flags & GSS_C_MUTUAL_FLAG) {
400 return GSS_S_CONTINUE_NEEDED;
401 } else {
402 (*context_handle)->more_flags |= OPEN;
403 return GSS_S_COMPLETE;
406 failure:
407 krb5_auth_con_free (gssapi_krb5_context,
408 (*context_handle)->auth_context);
409 if((*context_handle)->source)
410 krb5_free_principal (gssapi_krb5_context,
411 (*context_handle)->source);
412 if((*context_handle)->target)
413 krb5_free_principal (gssapi_krb5_context,
414 (*context_handle)->target);
415 free (*context_handle);
416 krb5_data_free (&outbuf);
417 *context_handle = GSS_C_NO_CONTEXT;
418 return ret;
421 static OM_uint32
422 repl_mutual
423 (OM_uint32 * minor_status,
424 const gss_cred_id_t initiator_cred_handle,
425 gss_ctx_id_t * context_handle,
426 const gss_name_t target_name,
427 const gss_OID mech_type,
428 OM_uint32 req_flags,
429 OM_uint32 time_req,
430 const gss_channel_bindings_t input_chan_bindings,
431 const gss_buffer_t input_token,
432 gss_OID * actual_mech_type,
433 gss_buffer_t output_token,
434 OM_uint32 * ret_flags,
435 OM_uint32 * time_rec
438 OM_uint32 ret;
439 krb5_error_code kret;
440 krb5_data indata;
441 krb5_ap_rep_enc_part *repl;
443 ret = gssapi_krb5_decapsulate (input_token, &indata, "\x02\x00");
444 if (ret) {
445 /* XXX - Handle AP_ERROR */
446 return GSS_S_FAILURE;
449 kret = krb5_rd_rep (gssapi_krb5_context,
450 (*context_handle)->auth_context,
451 &indata,
452 &repl);
453 if (kret)
454 return GSS_S_FAILURE;
455 krb5_free_ap_rep_enc_part (gssapi_krb5_context,
456 repl);
458 output_token->length = 0;
460 (*context_handle)->more_flags |= OPEN;
462 return GSS_S_COMPLETE;
466 * gss_init_sec_context
469 OM_uint32 gss_init_sec_context
470 (OM_uint32 * minor_status,
471 const gss_cred_id_t initiator_cred_handle,
472 gss_ctx_id_t * context_handle,
473 const gss_name_t target_name,
474 const gss_OID mech_type,
475 OM_uint32 req_flags,
476 OM_uint32 time_req,
477 const gss_channel_bindings_t input_chan_bindings,
478 const gss_buffer_t input_token,
479 gss_OID * actual_mech_type,
480 gss_buffer_t output_token,
481 OM_uint32 * ret_flags,
482 OM_uint32 * time_rec
485 gssapi_krb5_init ();
487 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
488 return init_auth (minor_status,
489 initiator_cred_handle,
490 context_handle,
491 target_name,
492 mech_type,
493 req_flags,
494 time_req,
495 input_chan_bindings,
496 input_token,
497 actual_mech_type,
498 output_token,
499 ret_flags,
500 time_rec);
501 else
502 return repl_mutual(minor_status,
503 initiator_cred_handle,
504 context_handle,
505 target_name,
506 mech_type,
507 req_flags,
508 time_req,
509 input_chan_bindings,
510 input_token,
511 actual_mech_type,
512 output_token,
513 ret_flags,
514 time_rec);