1 /* $NetBSD: compat.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $ */
4 * Copyright (c) 2004, PADL Software Pty Ltd.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of PADL Software nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include "spnego_locl.h"
38 * Apparently Microsoft got the OID wrong, and used
39 * 1.2.840.48018.1.2.2 instead. We need both this and
40 * the correct Kerberos OID here in order to deal with
41 * this. Because this is manifest in SPNEGO only I'd
42 * prefer to deal with this here rather than inside the
45 gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc
=
46 {9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")};
48 gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc
=
49 {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
52 * Allocate a SPNEGO context handle
54 OM_uint32 GSSAPI_CALLCONV
55 _gss_spnego_alloc_sec_context (OM_uint32
* minor_status
,
56 gss_ctx_id_t
*context_handle
)
60 ctx
= calloc(1, sizeof(*ctx
));
62 *minor_status
= ENOMEM
;
66 ctx
->initiator_mech_types
.len
= 0;
67 ctx
->initiator_mech_types
.val
= NULL
;
68 ctx
->preferred_mech_type
= GSS_C_NO_OID
;
69 ctx
->negotiated_mech_type
= GSS_C_NO_OID
;
70 ctx
->negotiated_ctx_id
= GSS_C_NO_CONTEXT
;
73 * Cache these so we can return them before returning
74 * GSS_S_COMPLETE, even if the mechanism has itself
78 ctx
->mech_time_rec
= 0;
79 ctx
->mech_src_name
= GSS_C_NO_NAME
;
84 ctx
->verified_mic
= 0;
86 HEIMDAL_MUTEX_init(&ctx
->ctx_id_mutex
);
88 *context_handle
= (gss_ctx_id_t
)ctx
;
90 return GSS_S_COMPLETE
;
94 * Free a SPNEGO context handle. The caller must have acquired
95 * the lock before this is called.
97 OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context
98 (OM_uint32
*minor_status
,
99 gss_ctx_id_t
*context_handle
,
100 gss_buffer_t output_token
104 OM_uint32 ret
, minor
;
108 if (context_handle
== NULL
) {
109 return GSS_S_NO_CONTEXT
;
112 if (output_token
!= GSS_C_NO_BUFFER
) {
113 output_token
->length
= 0;
114 output_token
->value
= NULL
;
117 ctx
= (gssspnego_ctx
)*context_handle
;
118 *context_handle
= GSS_C_NO_CONTEXT
;
121 return GSS_S_NO_CONTEXT
;
124 if (ctx
->initiator_mech_types
.val
!= NULL
)
125 free_MechTypeList(&ctx
->initiator_mech_types
);
127 gss_release_oid(&minor
, &ctx
->preferred_mech_type
);
128 ctx
->negotiated_mech_type
= GSS_C_NO_OID
;
130 gss_release_name(&minor
, &ctx
->target_name
);
131 gss_release_name(&minor
, &ctx
->mech_src_name
);
133 if (ctx
->negotiated_ctx_id
!= GSS_C_NO_CONTEXT
) {
134 ret
= gss_delete_sec_context(minor_status
,
135 &ctx
->negotiated_ctx_id
,
137 ctx
->negotiated_ctx_id
= GSS_C_NO_CONTEXT
;
139 ret
= GSS_S_COMPLETE
;
142 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
143 HEIMDAL_MUTEX_destroy(&ctx
->ctx_id_mutex
);
151 * For compatability with the Windows SPNEGO implementation, the
152 * default is to ignore the mechListMIC unless CFX is used and
153 * a non-preferred mechanism was negotiated
156 OM_uint32 GSSAPI_CALLCONV
157 _gss_spnego_require_mechlist_mic(OM_uint32
*minor_status
,
161 gss_buffer_set_t buffer_set
= GSS_C_NO_BUFFER_SET
;
168 return GSS_S_COMPLETE
;
171 if (ctx
->require_mic
) {
172 /* Acceptor requested it: mandatory to honour */
174 return GSS_S_COMPLETE
;
178 * Check whether peer indicated implicit support for updated SPNEGO
179 * (eg. in the Kerberos case by using CFX)
181 if (gss_inquire_sec_context_by_oid(&minor
, ctx
->negotiated_ctx_id
,
182 GSS_C_PEER_HAS_UPDATED_SPNEGO
,
183 &buffer_set
) == GSS_S_COMPLETE
) {
185 gss_release_buffer_set(&minor
, &buffer_set
);
188 /* Safe-to-omit MIC rules follow */
190 if (gss_oid_equal(ctx
->negotiated_mech_type
, ctx
->preferred_mech_type
)) {
192 } else if (gss_oid_equal(ctx
->negotiated_mech_type
, &_gss_spnego_krb5_mechanism_oid_desc
) &&
193 gss_oid_equal(ctx
->preferred_mech_type
, &_gss_spnego_mskrb_mechanism_oid_desc
)) {
198 return GSS_S_COMPLETE
;
202 add_mech_type(gss_OID mech_type
,
203 int includeMSCompatOID
,
204 MechTypeList
*mechtypelist
)
209 if (gss_oid_equal(mech_type
, GSS_SPNEGO_MECHANISM
))
212 if (includeMSCompatOID
&&
213 gss_oid_equal(mech_type
, &_gss_spnego_krb5_mechanism_oid_desc
)) {
214 ret
= der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc
.elements
,
215 _gss_spnego_mskrb_mechanism_oid_desc
.length
,
220 ret
= add_MechTypeList(mechtypelist
, &mech
);
221 free_MechType(&mech
);
225 ret
= der_get_oid(mech_type
->elements
, mech_type
->length
, &mech
, NULL
);
228 ret
= add_MechTypeList(mechtypelist
, &mech
);
229 free_MechType(&mech
);
234 OM_uint32 GSSAPI_CALLCONV
235 _gss_spnego_indicate_mechtypelist (OM_uint32
*minor_status
,
236 gss_name_t target_name
,
237 OM_uint32 (*func
)(gss_name_t
, gss_OID
),
238 int includeMSCompatOID
,
239 const gss_cred_id_t cred_handle
,
240 MechTypeList
*mechtypelist
,
241 gss_OID
*preferred_mech
)
243 gss_OID_set supported_mechs
= GSS_C_NO_OID_SET
;
244 gss_OID first_mech
= GSS_C_NO_OID
;
248 mechtypelist
->len
= 0;
249 mechtypelist
->val
= NULL
;
252 ret
= gss_inquire_cred(minor_status
,
259 ret
= gss_indicate_mechs(minor_status
, &supported_mechs
);
262 if (ret
!= GSS_S_COMPLETE
) {
266 if (supported_mechs
->count
== 0) {
267 *minor_status
= ENOENT
;
268 gss_release_oid_set(minor_status
, &supported_mechs
);
269 return GSS_S_FAILURE
;
272 ret
= (*func
)(target_name
, GSS_KRB5_MECHANISM
);
273 if (ret
== GSS_S_COMPLETE
) {
274 ret
= add_mech_type(GSS_KRB5_MECHANISM
,
278 first_mech
= GSS_KRB5_MECHANISM
;
280 ret
= GSS_S_COMPLETE
;
282 for (i
= 0; i
< supported_mechs
->count
; i
++) {
284 if (gss_oid_equal(&supported_mechs
->elements
[i
], GSS_SPNEGO_MECHANISM
))
286 if (gss_oid_equal(&supported_mechs
->elements
[i
], GSS_KRB5_MECHANISM
))
289 subret
= (*func
)(target_name
, &supported_mechs
->elements
[i
]);
290 if (subret
!= GSS_S_COMPLETE
)
293 ret
= add_mech_type(&supported_mechs
->elements
[i
],
301 if (first_mech
== GSS_C_NO_OID
)
302 first_mech
= &supported_mechs
->elements
[i
];
305 if (mechtypelist
->len
== 0) {
306 gss_release_oid_set(minor_status
, &supported_mechs
);
308 return GSS_S_BAD_MECH
;
311 if (preferred_mech
!= NULL
) {
312 ret
= gss_duplicate_oid(minor_status
, first_mech
, preferred_mech
);
313 if (ret
!= GSS_S_COMPLETE
)
314 free_MechTypeList(mechtypelist
);
316 gss_release_oid_set(minor_status
, &supported_mechs
);