2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "krb5/gsskrb5_locl.h"
39 * copy the addresses from `input_chan_bindings' (if any) to
40 * the auth context `ac'
44 set_addresses (krb5_context context
,
46 const gss_channel_bindings_t input_chan_bindings
)
48 /* Port numbers are expected to be in application_data.value,
49 * initator's port first */
51 krb5_address initiator_addr
, acceptor_addr
;
54 if (input_chan_bindings
== GSS_C_NO_CHANNEL_BINDINGS
55 || input_chan_bindings
->application_data
.length
!=
56 2 * sizeof(ac
->local_port
))
59 memset(&initiator_addr
, 0, sizeof(initiator_addr
));
60 memset(&acceptor_addr
, 0, sizeof(acceptor_addr
));
63 *(int16_t *) input_chan_bindings
->application_data
.value
;
66 *((int16_t *) input_chan_bindings
->application_data
.value
+ 1);
68 kret
= _gsskrb5i_address_to_krb5addr(context
,
69 input_chan_bindings
->acceptor_addrtype
,
70 &input_chan_bindings
->acceptor_address
,
76 kret
= _gsskrb5i_address_to_krb5addr(context
,
77 input_chan_bindings
->initiator_addrtype
,
78 &input_chan_bindings
->initiator_address
,
82 krb5_free_address (context
, &acceptor_addr
);
86 kret
= krb5_auth_con_setaddrs(context
,
88 &initiator_addr
, /* local address */
89 &acceptor_addr
); /* remote address */
91 krb5_free_address (context
, &initiator_addr
);
92 krb5_free_address (context
, &acceptor_addr
);
95 free(input_chan_bindings
->application_data
.value
);
96 input_chan_bindings
->application_data
.value
= NULL
;
97 input_chan_bindings
->application_data
.length
= 0;
105 OM_uint32
* minor_status
,
106 gss_ctx_id_t
* context_handle
,
107 krb5_context context
,
108 const gss_channel_bindings_t input_chan_bindings
,
109 enum gss_ctx_id_t_state state
)
111 krb5_error_code kret
;
114 *context_handle
= NULL
;
116 ctx
= malloc(sizeof(*ctx
));
118 *minor_status
= ENOMEM
;
119 return GSS_S_FAILURE
;
121 ctx
->auth_context
= NULL
;
127 ctx
->service_keyblock
= NULL
;
129 krb5_data_zero(&ctx
->fwd_data
);
130 ctx
->lifetime
= GSS_C_INDEFINITE
;
132 HEIMDAL_MUTEX_init(&ctx
->ctx_id_mutex
);
134 kret
= krb5_auth_con_init (context
, &ctx
->auth_context
);
136 *minor_status
= kret
;
138 HEIMDAL_MUTEX_destroy(&ctx
->ctx_id_mutex
);
140 return GSS_S_FAILURE
;
143 kret
= set_addresses(context
, ctx
->auth_context
, input_chan_bindings
);
145 *minor_status
= kret
;
147 HEIMDAL_MUTEX_destroy(&ctx
->ctx_id_mutex
);
149 krb5_auth_con_free(context
, ctx
->auth_context
);
151 return GSS_S_BAD_BINDINGS
;
155 * We need a sequence number
158 krb5_auth_con_addflags(context
,
160 KRB5_AUTH_CONTEXT_DO_SEQUENCE
|
161 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED
,
164 *context_handle
= (gss_ctx_id_t
)ctx
;
166 return GSS_S_COMPLETE
;
172 OM_uint32
* minor_status
,
173 krb5_context context
,
176 krb5_const_principal target_name
,
178 OM_uint32
* time_rec
,
182 krb5_error_code kret
;
183 krb5_creds this_cred
;
184 OM_uint32 lifetime_rec
;
188 memset(&this_cred
, 0, sizeof(this_cred
));
189 this_cred
.client
= ctx
->source
;
190 this_cred
.server
= ctx
->target
;
192 if (time_req
&& time_req
!= GSS_C_INDEFINITE
) {
195 krb5_timeofday (context
, &ts
);
196 this_cred
.times
.endtime
= ts
+ time_req
;
198 this_cred
.times
.endtime
= 0;
201 this_cred
.session
.keytype
= KEYTYPE_NULL
;
203 kret
= krb5_get_credentials(context
,
209 *minor_status
= kret
;
210 return GSS_S_FAILURE
;
213 ctx
->lifetime
= (*cred
)->times
.endtime
;
215 ret
= _gsskrb5_lifetime_left(minor_status
, context
,
216 ctx
->lifetime
, &lifetime_rec
);
219 if (lifetime_rec
== 0) {
221 return GSS_S_CONTEXT_EXPIRED
;
224 if (time_rec
) *time_rec
= lifetime_rec
;
226 return GSS_S_COMPLETE
;
230 gsskrb5_initiator_ready(
231 OM_uint32
* minor_status
,
233 krb5_context context
)
238 OM_uint32 flags
= ctx
->flags
;
240 krb5_auth_getremoteseqnumber (context
,
244 _gsskrb5i_is_cfx(ctx
, &is_cfx
);
246 ret
= _gssapi_msg_order_create(minor_status
,
248 _gssapi_msg_order_f(flags
),
249 seq_number
, 0, is_cfx
);
252 ctx
->state
= INITIATOR_READY
;
253 ctx
->more_flags
|= OPEN
;
255 return GSS_S_COMPLETE
;
259 * handle delegated creds in init-sec-context
263 do_delegation (krb5_context context
,
264 krb5_auth_context ac
,
267 krb5_const_principal name
,
272 KDCOptions fwd_flags
;
273 krb5_error_code kret
;
275 memset (&creds
, 0, sizeof(creds
));
276 krb5_data_zero (fwd_data
);
278 kret
= krb5_cc_get_principal(context
, ccache
, &creds
.client
);
282 kret
= krb5_build_principal(context
,
284 strlen(creds
.client
->realm
),
292 creds
.times
.endtime
= 0;
294 memset(&fwd_flags
, 0, sizeof(fwd_flags
));
295 fwd_flags
.forwarded
= 1;
296 fwd_flags
.forwardable
= 1;
298 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
299 name
->name
.name_string
.len
< 2)
302 kret
= krb5_get_forwarded_creds(context
,
305 KDCOptions2int(fwd_flags
),
306 name
->name
.name_string
.val
[1],
312 *flags
&= ~GSS_C_DELEG_FLAG
;
314 *flags
|= GSS_C_DELEG_FLAG
;
317 krb5_free_principal(context
, creds
.client
);
319 krb5_free_principal(context
, creds
.server
);
323 * first stage of init-sec-context
328 (OM_uint32
* minor_status
,
331 krb5_context context
,
332 krb5_const_principal name
,
333 const gss_OID mech_type
,
336 const gss_channel_bindings_t input_chan_bindings
,
337 const gss_buffer_t input_token
,
338 gss_OID
* actual_mech_type
,
339 gss_buffer_t output_token
,
340 OM_uint32
* ret_flags
,
344 OM_uint32 ret
= GSS_S_FAILURE
;
345 krb5_error_code kret
;
346 krb5_flags ap_options
;
347 krb5_creds
*kcred
= NULL
;
349 krb5_ccache ccache
= NULL
;
351 krb5_data authenticator
;
353 krb5_enctype enctype
;
355 OM_uint32 lifetime_rec
;
357 krb5_data_zero(&outbuf
);
358 krb5_data_zero(&fwd_data
);
362 if (actual_mech_type
)
363 *actual_mech_type
= GSS_KRB5_MECHANISM
;
366 kret
= krb5_cc_default (context
, &ccache
);
368 *minor_status
= kret
;
373 ccache
= cred
->ccache
;
375 kret
= krb5_cc_get_principal (context
, ccache
, &ctx
->source
);
377 *minor_status
= kret
;
382 kret
= krb5_copy_principal (context
, name
, &ctx
->target
);
384 *minor_status
= kret
;
389 ret
= _gss_DES3_get_mic_compat(minor_status
, ctx
, context
);
395 * This is hideous glue for (NFS) clients that wants to limit the
396 * available enctypes to what it can support (encryption in
397 * kernel). If there is no enctypes selected for this credential,
398 * reset it to the default set of enctypes.
401 krb5_enctype
*enctypes
= NULL
;
403 if (cred
&& cred
->enctypes
)
404 enctypes
= cred
->enctypes
;
405 krb5_set_default_in_tkt_etypes(context
, enctypes
);
408 ret
= gsskrb5_get_creds(minor_status
,
419 ctx
->lifetime
= kcred
->times
.endtime
;
421 ret
= _gsskrb5_lifetime_left(minor_status
,
429 if (lifetime_rec
== 0) {
431 ret
= GSS_S_CONTEXT_EXPIRED
;
435 krb5_auth_con_setkey(context
,
439 kret
= krb5_auth_con_generatelocalsubkey(context
,
443 *minor_status
= kret
;
449 * If the credential doesn't have ok-as-delegate, check what local
450 * policy say about ok-as-delegate, default is FALSE that makes
451 * code ignore the KDC setting and follow what the application
452 * requested. If it is TRUE, strip of the GSS_C_DELEG_FLAG if the
453 * KDC doesn't set ok-as-delegate.
455 if (!kcred
->flags
.b
.ok_as_delegate
) {
456 krb5_boolean delegate
;
458 krb5_appdefault_boolean(context
,
459 "gssapi", name
->realm
,
460 "ok-as-delegate", FALSE
, &delegate
);
462 req_flags
&= ~GSS_C_DELEG_FLAG
;
467 if (req_flags
& GSS_C_DELEG_FLAG
)
468 do_delegation (context
,
470 ccache
, kcred
, name
, &fwd_data
, &flags
);
472 if (req_flags
& GSS_C_MUTUAL_FLAG
) {
473 flags
|= GSS_C_MUTUAL_FLAG
;
474 ap_options
|= AP_OPTS_MUTUAL_REQUIRED
;
477 if (req_flags
& GSS_C_REPLAY_FLAG
)
478 flags
|= GSS_C_REPLAY_FLAG
;
479 if (req_flags
& GSS_C_SEQUENCE_FLAG
)
480 flags
|= GSS_C_SEQUENCE_FLAG
;
481 if (req_flags
& GSS_C_ANON_FLAG
)
483 if (req_flags
& GSS_C_DCE_STYLE
) {
484 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
485 flags
|= GSS_C_DCE_STYLE
| GSS_C_MUTUAL_FLAG
;
486 ap_options
|= AP_OPTS_MUTUAL_REQUIRED
;
488 if (req_flags
& GSS_C_IDENTIFY_FLAG
)
489 flags
|= GSS_C_IDENTIFY_FLAG
;
490 if (req_flags
& GSS_C_EXTENDED_ERROR_FLAG
)
491 flags
|= GSS_C_EXTENDED_ERROR_FLAG
;
493 if (req_flags
& GSS_C_CONF_FLAG
) {
494 flags
|= GSS_C_CONF_FLAG
;
496 if (req_flags
& GSS_C_INTEG_FLAG
) {
497 flags
|= GSS_C_INTEG_FLAG
;
499 if (cred
== NULL
|| !(cred
->cred_flags
& GSS_CF_NO_CI_FLAGS
)) {
500 flags
|= GSS_C_CONF_FLAG
;
501 flags
|= GSS_C_INTEG_FLAG
;
503 flags
|= GSS_C_TRANS_FLAG
;
508 ctx
->more_flags
|= LOCAL
;
510 ret
= _gsskrb5_create_8003_checksum (minor_status
,
515 krb5_data_free (&fwd_data
);
519 enctype
= ctx
->auth_context
->keyblock
->keytype
;
521 kret
= krb5_build_authenticator (context
,
528 KRB5_KU_AP_REQ_AUTH
);
531 *minor_status
= kret
;
536 kret
= krb5_build_ap_req (context
,
544 *minor_status
= kret
;
549 ret
= _gsskrb5_encapsulate (minor_status
, &outbuf
, output_token
,
550 (u_char
*)"\x01\x00", GSS_KRB5_MECHANISM
);
554 krb5_data_free (&outbuf
);
555 krb5_free_creds(context
, kcred
);
556 free_Checksum(&cksum
);
558 krb5_cc_close(context
, ccache
);
560 if (flags
& GSS_C_MUTUAL_FLAG
) {
561 ctx
->state
= INITIATOR_WAIT_FOR_MUTAL
;
562 return GSS_S_CONTINUE_NEEDED
;
565 return gsskrb5_initiator_ready(minor_status
, ctx
, context
);
568 krb5_free_creds(context
, kcred
);
569 if (ccache
&& cred
== NULL
)
570 krb5_cc_close(context
, ccache
);
578 (OM_uint32
* minor_status
,
580 krb5_context context
,
581 const gss_OID mech_type
,
584 const gss_channel_bindings_t input_chan_bindings
,
585 const gss_buffer_t input_token
,
586 gss_OID
* actual_mech_type
,
587 gss_buffer_t output_token
,
588 OM_uint32
* ret_flags
,
593 krb5_error_code kret
;
595 krb5_ap_rep_enc_part
*repl
;
598 output_token
->length
= 0;
599 output_token
->value
= NULL
;
601 if (actual_mech_type
)
602 *actual_mech_type
= GSS_KRB5_MECHANISM
;
604 if (ctx
->flags
& GSS_C_DCE_STYLE
) {
605 /* There is no OID wrapping. */
606 indata
.length
= input_token
->length
;
607 indata
.data
= input_token
->value
;
609 ret
= _gsskrb5_decapsulate (minor_status
,
615 /* XXX - Handle AP_ERROR */
620 kret
= krb5_rd_rep (context
,
625 *minor_status
= kret
;
626 return GSS_S_FAILURE
;
628 krb5_free_ap_rep_enc_part (context
,
631 _gsskrb5i_is_cfx(ctx
, &is_cfx
);
633 krb5_keyblock
*key
= NULL
;
635 kret
= krb5_auth_con_getremotesubkey(context
,
638 if (kret
== 0 && key
!= NULL
) {
639 ctx
->more_flags
|= ACCEPTOR_SUBKEY
;
640 krb5_free_keyblock (context
, key
);
647 ret
= _gsskrb5_lifetime_left(minor_status
,
652 ret
= GSS_S_COMPLETE
;
655 *ret_flags
= ctx
->flags
;
657 if (req_flags
& GSS_C_DCE_STYLE
) {
661 /* Do don't do sequence number for the mk-rep */
662 krb5_auth_con_removeflags(context
,
664 KRB5_AUTH_CONTEXT_DO_SEQUENCE
,
667 kret
= krb5_mk_rep(context
,
671 *minor_status
= kret
;
672 return GSS_S_FAILURE
;
675 output_token
->length
= outbuf
.length
;
676 output_token
->value
= outbuf
.data
;
678 krb5_auth_con_removeflags(context
,
680 KRB5_AUTH_CONTEXT_DO_SEQUENCE
,
684 return gsskrb5_initiator_ready(minor_status
, ctx
, context
);
688 * gss_init_sec_context
691 OM_uint32 _gsskrb5_init_sec_context
692 (OM_uint32
* minor_status
,
693 const gss_cred_id_t cred_handle
,
694 gss_ctx_id_t
* context_handle
,
695 const gss_name_t target_name
,
696 const gss_OID mech_type
,
699 const gss_channel_bindings_t input_chan_bindings
,
700 const gss_buffer_t input_token
,
701 gss_OID
* actual_mech_type
,
702 gss_buffer_t output_token
,
703 OM_uint32
* ret_flags
,
707 krb5_context context
;
708 gsskrb5_cred cred
= (gsskrb5_cred
)cred_handle
;
709 krb5_const_principal name
= (krb5_const_principal
)target_name
;
713 GSSAPI_KRB5_INIT (&context
);
715 output_token
->length
= 0;
716 output_token
->value
= NULL
;
718 if (context_handle
== NULL
) {
720 return GSS_S_FAILURE
| GSS_S_CALL_BAD_STRUCTURE
;
728 if (target_name
== GSS_C_NO_NAME
) {
729 if (actual_mech_type
)
730 *actual_mech_type
= GSS_C_NO_OID
;
732 return GSS_S_BAD_NAME
;
735 if (mech_type
!= GSS_C_NO_OID
&&
736 !gss_oid_equal(mech_type
, GSS_KRB5_MECHANISM
))
737 return GSS_S_BAD_MECH
;
739 if (input_token
== GSS_C_NO_BUFFER
|| input_token
->length
== 0) {
742 if (*context_handle
!= GSS_C_NO_CONTEXT
) {
744 return GSS_S_FAILURE
| GSS_S_CALL_BAD_STRUCTURE
;
747 ret
= _gsskrb5_create_ctx(minor_status
,
756 if (*context_handle
== GSS_C_NO_CONTEXT
) {
758 return GSS_S_FAILURE
| GSS_S_CALL_BAD_STRUCTURE
;
761 ctx
= (gsskrb5_ctx
) *context_handle
;
763 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
765 switch (ctx
->state
) {
766 case INITIATOR_START
:
767 ret
= init_auth(minor_status
,
782 case INITIATOR_WAIT_FOR_MUTAL
:
783 ret
= repl_mutual(minor_status
,
796 case INITIATOR_READY
:
798 * If we get there, the caller have called
799 * gss_init_sec_context() one time too many.
802 ret
= GSS_S_BAD_STATUS
;
806 ret
= GSS_S_BAD_STATUS
;
809 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
811 /* destroy context in case of error */
812 if (GSS_ERROR(ret
)) {
814 _gsskrb5_delete_sec_context(&min2
, context_handle
, GSS_C_NO_BUFFER
);