1178825Sdfr/*
2178825Sdfr * Copyright (c) 2004, PADL Software Pty Ltd.
3178825Sdfr * All rights reserved.
4178825Sdfr *
5178825Sdfr * Redistribution and use in source and binary forms, with or without
6178825Sdfr * modification, are permitted provided that the following conditions
7178825Sdfr * are met:
8178825Sdfr *
9178825Sdfr * 1. Redistributions of source code must retain the above copyright
10178825Sdfr *    notice, this list of conditions and the following disclaimer.
11178825Sdfr *
12178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
13178825Sdfr *    notice, this list of conditions and the following disclaimer in the
14178825Sdfr *    documentation and/or other materials provided with the distribution.
15178825Sdfr *
16178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors
17178825Sdfr *    may be used to endorse or promote products derived from this software
18178825Sdfr *    without specific prior written permission.
19178825Sdfr *
20178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30178825Sdfr * SUCH DAMAGE.
31178825Sdfr */
32178825Sdfr
33233294Sstas#include "spnego_locl.h"
34178825Sdfr
35178825Sdfrstatic OM_uint32
36178825Sdfrspnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs)
37178825Sdfr{
38178825Sdfr    OM_uint32 ret, junk;
39178825Sdfr    gss_OID_set m;
40233294Sstas    size_t i;
41178825Sdfr
42178825Sdfr    ret = gss_indicate_mechs(minor_status, &m);
43178825Sdfr    if (ret != GSS_S_COMPLETE)
44178825Sdfr	return ret;
45178825Sdfr
46178825Sdfr    ret = gss_create_empty_oid_set(minor_status, mechs);
47178825Sdfr    if (ret != GSS_S_COMPLETE) {
48178825Sdfr	gss_release_oid_set(&junk, &m);
49178825Sdfr	return ret;
50178825Sdfr    }
51178825Sdfr
52178825Sdfr    for (i = 0; i < m->count; i++) {
53178825Sdfr	if (gss_oid_equal(&m->elements[i], GSS_SPNEGO_MECHANISM))
54178825Sdfr	    continue;
55178825Sdfr
56178825Sdfr	ret = gss_add_oid_set_member(minor_status, &m->elements[i], mechs);
57178825Sdfr	if (ret) {
58178825Sdfr	    gss_release_oid_set(&junk, &m);
59178825Sdfr	    gss_release_oid_set(&junk, mechs);
60178825Sdfr	    return ret;
61178825Sdfr	}
62178825Sdfr    }
63233294Sstas    gss_release_oid_set(&junk, &m);
64178825Sdfr    return ret;
65178825Sdfr}
66178825Sdfr
67178825Sdfr
68178825Sdfr
69233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_process_context_token
70178825Sdfr           (OM_uint32 *minor_status,
71178825Sdfr            const gss_ctx_id_t context_handle,
72178825Sdfr            const gss_buffer_t token_buffer
73178825Sdfr           )
74178825Sdfr{
75178825Sdfr    gss_ctx_id_t context ;
76178825Sdfr    gssspnego_ctx ctx;
77178825Sdfr    OM_uint32 ret;
78178825Sdfr
79178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT)
80178825Sdfr	return GSS_S_NO_CONTEXT;
81178825Sdfr
82178825Sdfr    context = context_handle;
83178825Sdfr    ctx = (gssspnego_ctx)context_handle;
84178825Sdfr
85178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
86178825Sdfr
87178825Sdfr    ret = gss_process_context_token(minor_status,
88178825Sdfr				    ctx->negotiated_ctx_id,
89178825Sdfr				    token_buffer);
90178825Sdfr    if (ret != GSS_S_COMPLETE) {
91178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
92178825Sdfr	return ret;
93178825Sdfr    }
94178825Sdfr
95178825Sdfr    ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
96178825Sdfr
97178825Sdfr    return _gss_spnego_internal_delete_sec_context(minor_status,
98178825Sdfr					   &context,
99178825Sdfr					   GSS_C_NO_BUFFER);
100178825Sdfr}
101178825Sdfr
102233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_delete_sec_context
103178825Sdfr           (OM_uint32 *minor_status,
104178825Sdfr            gss_ctx_id_t *context_handle,
105178825Sdfr            gss_buffer_t output_token
106178825Sdfr           )
107178825Sdfr{
108178825Sdfr    gssspnego_ctx ctx;
109178825Sdfr
110178825Sdfr    if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
111178825Sdfr	return GSS_S_NO_CONTEXT;
112178825Sdfr
113178825Sdfr    ctx = (gssspnego_ctx)*context_handle;
114178825Sdfr
115178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
116178825Sdfr
117178825Sdfr    return _gss_spnego_internal_delete_sec_context(minor_status,
118178825Sdfr						   context_handle,
119178825Sdfr						   output_token);
120178825Sdfr}
121178825Sdfr
122233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_context_time
123178825Sdfr           (OM_uint32 *minor_status,
124178825Sdfr            const gss_ctx_id_t context_handle,
125178825Sdfr            OM_uint32 *time_rec
126178825Sdfr           )
127178825Sdfr{
128178825Sdfr    gssspnego_ctx ctx;
129178825Sdfr    *minor_status = 0;
130178825Sdfr
131178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
132178825Sdfr	return GSS_S_NO_CONTEXT;
133178825Sdfr    }
134178825Sdfr
135178825Sdfr    ctx = (gssspnego_ctx)context_handle;
136178825Sdfr
137178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
138178825Sdfr	return GSS_S_NO_CONTEXT;
139178825Sdfr    }
140178825Sdfr
141178825Sdfr    return gss_context_time(minor_status,
142178825Sdfr			    ctx->negotiated_ctx_id,
143178825Sdfr			    time_rec);
144178825Sdfr}
145178825Sdfr
146233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_get_mic
147178825Sdfr           (OM_uint32 *minor_status,
148178825Sdfr            const gss_ctx_id_t context_handle,
149178825Sdfr            gss_qop_t qop_req,
150178825Sdfr            const gss_buffer_t message_buffer,
151178825Sdfr            gss_buffer_t message_token
152178825Sdfr           )
153178825Sdfr{
154178825Sdfr    gssspnego_ctx ctx;
155178825Sdfr
156178825Sdfr    *minor_status = 0;
157178825Sdfr
158178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
159178825Sdfr	return GSS_S_NO_CONTEXT;
160178825Sdfr    }
161178825Sdfr
162178825Sdfr    ctx = (gssspnego_ctx)context_handle;
163178825Sdfr
164178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
165178825Sdfr	return GSS_S_NO_CONTEXT;
166178825Sdfr    }
167178825Sdfr
168178825Sdfr    return gss_get_mic(minor_status, ctx->negotiated_ctx_id,
169178825Sdfr		       qop_req, message_buffer, message_token);
170178825Sdfr}
171178825Sdfr
172233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_verify_mic
173178825Sdfr           (OM_uint32 * minor_status,
174178825Sdfr            const gss_ctx_id_t context_handle,
175178825Sdfr            const gss_buffer_t message_buffer,
176178825Sdfr            const gss_buffer_t token_buffer,
177178825Sdfr            gss_qop_t * qop_state
178178825Sdfr           )
179178825Sdfr{
180178825Sdfr    gssspnego_ctx ctx;
181178825Sdfr
182178825Sdfr    *minor_status = 0;
183178825Sdfr
184178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
185178825Sdfr	return GSS_S_NO_CONTEXT;
186178825Sdfr    }
187178825Sdfr
188178825Sdfr    ctx = (gssspnego_ctx)context_handle;
189178825Sdfr
190178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
191178825Sdfr	return GSS_S_NO_CONTEXT;
192178825Sdfr    }
193178825Sdfr
194178825Sdfr    return gss_verify_mic(minor_status,
195178825Sdfr			  ctx->negotiated_ctx_id,
196178825Sdfr			  message_buffer,
197178825Sdfr			  token_buffer,
198178825Sdfr			  qop_state);
199178825Sdfr}
200178825Sdfr
201233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap
202178825Sdfr           (OM_uint32 * minor_status,
203178825Sdfr            const gss_ctx_id_t context_handle,
204178825Sdfr            int conf_req_flag,
205178825Sdfr            gss_qop_t qop_req,
206178825Sdfr            const gss_buffer_t input_message_buffer,
207178825Sdfr            int * conf_state,
208178825Sdfr            gss_buffer_t output_message_buffer
209178825Sdfr           )
210178825Sdfr{
211178825Sdfr    gssspnego_ctx ctx;
212178825Sdfr
213178825Sdfr    *minor_status = 0;
214178825Sdfr
215178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
216178825Sdfr	return GSS_S_NO_CONTEXT;
217178825Sdfr    }
218178825Sdfr
219178825Sdfr    ctx = (gssspnego_ctx)context_handle;
220178825Sdfr
221178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
222178825Sdfr	return GSS_S_NO_CONTEXT;
223178825Sdfr    }
224178825Sdfr
225178825Sdfr    return gss_wrap(minor_status,
226178825Sdfr		    ctx->negotiated_ctx_id,
227178825Sdfr		    conf_req_flag,
228178825Sdfr		    qop_req,
229178825Sdfr		    input_message_buffer,
230178825Sdfr		    conf_state,
231178825Sdfr		    output_message_buffer);
232178825Sdfr}
233178825Sdfr
234233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_unwrap
235178825Sdfr           (OM_uint32 * minor_status,
236178825Sdfr            const gss_ctx_id_t context_handle,
237178825Sdfr            const gss_buffer_t input_message_buffer,
238178825Sdfr            gss_buffer_t output_message_buffer,
239178825Sdfr            int * conf_state,
240178825Sdfr            gss_qop_t * qop_state
241178825Sdfr           )
242178825Sdfr{
243178825Sdfr    gssspnego_ctx ctx;
244178825Sdfr
245178825Sdfr    *minor_status = 0;
246178825Sdfr
247178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
248178825Sdfr	return GSS_S_NO_CONTEXT;
249178825Sdfr    }
250178825Sdfr
251178825Sdfr    ctx = (gssspnego_ctx)context_handle;
252178825Sdfr
253178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
254178825Sdfr	return GSS_S_NO_CONTEXT;
255178825Sdfr    }
256178825Sdfr
257178825Sdfr    return gss_unwrap(minor_status,
258178825Sdfr		      ctx->negotiated_ctx_id,
259178825Sdfr		      input_message_buffer,
260178825Sdfr		      output_message_buffer,
261178825Sdfr		      conf_state,
262178825Sdfr		      qop_state);
263178825Sdfr}
264178825Sdfr
265233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_compare_name
266178825Sdfr           (OM_uint32 *minor_status,
267178825Sdfr            const gss_name_t name1,
268178825Sdfr            const gss_name_t name2,
269178825Sdfr            int * name_equal
270178825Sdfr           )
271178825Sdfr{
272178825Sdfr    spnego_name n1 = (spnego_name)name1;
273178825Sdfr    spnego_name n2 = (spnego_name)name2;
274178825Sdfr
275178825Sdfr    *name_equal = 0;
276178825Sdfr
277178825Sdfr    if (!gss_oid_equal(&n1->type, &n2->type))
278178825Sdfr	return GSS_S_COMPLETE;
279178825Sdfr    if (n1->value.length != n2->value.length)
280178825Sdfr	return GSS_S_COMPLETE;
281178825Sdfr    if (memcmp(n1->value.value, n2->value.value, n2->value.length) != 0)
282178825Sdfr	return GSS_S_COMPLETE;
283178825Sdfr
284178825Sdfr    *name_equal = 1;
285178825Sdfr
286178825Sdfr    return GSS_S_COMPLETE;
287178825Sdfr}
288178825Sdfr
289233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_display_name
290178825Sdfr           (OM_uint32 * minor_status,
291178825Sdfr            const gss_name_t input_name,
292178825Sdfr            gss_buffer_t output_name_buffer,
293178825Sdfr            gss_OID * output_name_type
294178825Sdfr           )
295178825Sdfr{
296178825Sdfr    spnego_name name = (spnego_name)input_name;
297178825Sdfr
298178825Sdfr    *minor_status = 0;
299178825Sdfr
300178825Sdfr    if (name == NULL || name->mech == GSS_C_NO_NAME)
301178825Sdfr	return GSS_S_FAILURE;
302178825Sdfr
303178825Sdfr    return gss_display_name(minor_status, name->mech,
304178825Sdfr			    output_name_buffer, output_name_type);
305178825Sdfr}
306178825Sdfr
307233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_import_name
308178825Sdfr           (OM_uint32 * minor_status,
309178825Sdfr            const gss_buffer_t name_buffer,
310178825Sdfr            const gss_OID name_type,
311178825Sdfr            gss_name_t * output_name
312178825Sdfr           )
313178825Sdfr{
314178825Sdfr    spnego_name name;
315178825Sdfr    OM_uint32 maj_stat;
316178825Sdfr
317178825Sdfr    *minor_status = 0;
318178825Sdfr
319178825Sdfr    name = calloc(1, sizeof(*name));
320178825Sdfr    if (name == NULL) {
321178825Sdfr	*minor_status = ENOMEM;
322178825Sdfr	return GSS_S_FAILURE;
323178825Sdfr    }
324233294Sstas
325178825Sdfr    maj_stat = _gss_copy_oid(minor_status, name_type, &name->type);
326178825Sdfr    if (maj_stat) {
327178825Sdfr	free(name);
328178825Sdfr	return GSS_S_FAILURE;
329178825Sdfr    }
330233294Sstas
331178825Sdfr    maj_stat = _gss_copy_buffer(minor_status, name_buffer, &name->value);
332178825Sdfr    if (maj_stat) {
333178825Sdfr	gss_name_t rname = (gss_name_t)name;
334178825Sdfr	_gss_spnego_release_name(minor_status, &rname);
335178825Sdfr	return GSS_S_FAILURE;
336178825Sdfr    }
337178825Sdfr    name->mech = GSS_C_NO_NAME;
338178825Sdfr    *output_name = (gss_name_t)name;
339178825Sdfr
340178825Sdfr    return GSS_S_COMPLETE;
341178825Sdfr}
342178825Sdfr
343233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_export_name
344178825Sdfr           (OM_uint32  * minor_status,
345178825Sdfr            const gss_name_t input_name,
346178825Sdfr            gss_buffer_t exported_name
347178825Sdfr           )
348178825Sdfr{
349178825Sdfr    spnego_name name;
350178825Sdfr    *minor_status = 0;
351178825Sdfr
352178825Sdfr    if (input_name == GSS_C_NO_NAME)
353178825Sdfr	return GSS_S_BAD_NAME;
354178825Sdfr
355178825Sdfr    name = (spnego_name)input_name;
356178825Sdfr    if (name->mech == GSS_C_NO_NAME)
357178825Sdfr	return GSS_S_BAD_NAME;
358178825Sdfr
359178825Sdfr    return gss_export_name(minor_status, name->mech, exported_name);
360178825Sdfr}
361178825Sdfr
362233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_release_name
363178825Sdfr           (OM_uint32 * minor_status,
364178825Sdfr            gss_name_t * input_name
365178825Sdfr           )
366178825Sdfr{
367178825Sdfr    *minor_status = 0;
368178825Sdfr
369178825Sdfr    if (*input_name != GSS_C_NO_NAME) {
370178825Sdfr	OM_uint32 junk;
371178825Sdfr	spnego_name name = (spnego_name)*input_name;
372178825Sdfr	_gss_free_oid(&junk, &name->type);
373178825Sdfr	gss_release_buffer(&junk, &name->value);
374178825Sdfr	if (name->mech != GSS_C_NO_NAME)
375178825Sdfr	    gss_release_name(&junk, &name->mech);
376178825Sdfr	free(name);
377178825Sdfr
378178825Sdfr	*input_name = GSS_C_NO_NAME;
379178825Sdfr    }
380178825Sdfr    return GSS_S_COMPLETE;
381178825Sdfr}
382178825Sdfr
383233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_context (
384178825Sdfr            OM_uint32 * minor_status,
385178825Sdfr            const gss_ctx_id_t context_handle,
386178825Sdfr            gss_name_t * src_name,
387178825Sdfr            gss_name_t * targ_name,
388178825Sdfr            OM_uint32 * lifetime_rec,
389178825Sdfr            gss_OID * mech_type,
390178825Sdfr            OM_uint32 * ctx_flags,
391178825Sdfr            int * locally_initiated,
392178825Sdfr            int * open_context
393178825Sdfr           )
394178825Sdfr{
395178825Sdfr    gssspnego_ctx ctx;
396233294Sstas    OM_uint32 maj_stat, junk;
397233294Sstas    gss_name_t src_mn, targ_mn;
398178825Sdfr
399178825Sdfr    *minor_status = 0;
400178825Sdfr
401233294Sstas    if (context_handle == GSS_C_NO_CONTEXT)
402178825Sdfr	return GSS_S_NO_CONTEXT;
403178825Sdfr
404178825Sdfr    ctx = (gssspnego_ctx)context_handle;
405178825Sdfr
406233294Sstas    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
407178825Sdfr	return GSS_S_NO_CONTEXT;
408178825Sdfr
409233294Sstas    maj_stat = gss_inquire_context(minor_status,
410233294Sstas				   ctx->negotiated_ctx_id,
411233294Sstas				   &src_mn,
412233294Sstas				   &targ_mn,
413233294Sstas				   lifetime_rec,
414233294Sstas				   mech_type,
415233294Sstas				   ctx_flags,
416233294Sstas				   locally_initiated,
417233294Sstas				   open_context);
418233294Sstas    if (maj_stat != GSS_S_COMPLETE)
419233294Sstas	return maj_stat;
420233294Sstas
421233294Sstas    if (src_name) {
422233294Sstas	spnego_name name = calloc(1, sizeof(*name));
423233294Sstas	if (name == NULL)
424233294Sstas	    goto enomem;
425233294Sstas	name->mech = src_mn;
426233294Sstas	*src_name = (gss_name_t)name;
427233294Sstas    } else
428233294Sstas	gss_release_name(&junk, &src_mn);
429233294Sstas
430233294Sstas    if (targ_name) {
431233294Sstas	spnego_name name = calloc(1, sizeof(*name));
432233294Sstas	if (name == NULL) {
433233294Sstas	    gss_release_name(minor_status, src_name);
434233294Sstas	    goto enomem;
435233294Sstas	}
436233294Sstas	name->mech = targ_mn;
437233294Sstas	*targ_name = (gss_name_t)name;
438233294Sstas    } else
439233294Sstas	gss_release_name(&junk, &targ_mn);
440233294Sstas
441233294Sstas    return GSS_S_COMPLETE;
442233294Sstas
443233294Sstasenomem:
444233294Sstas    gss_release_name(&junk, &targ_mn);
445233294Sstas    gss_release_name(&junk, &src_mn);
446233294Sstas    *minor_status = ENOMEM;
447233294Sstas    return GSS_S_FAILURE;
448178825Sdfr}
449178825Sdfr
450233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap_size_limit (
451178825Sdfr            OM_uint32 * minor_status,
452178825Sdfr            const gss_ctx_id_t context_handle,
453178825Sdfr            int conf_req_flag,
454178825Sdfr            gss_qop_t qop_req,
455178825Sdfr            OM_uint32 req_output_size,
456178825Sdfr            OM_uint32 * max_input_size
457178825Sdfr           )
458178825Sdfr{
459178825Sdfr    gssspnego_ctx ctx;
460178825Sdfr
461178825Sdfr    *minor_status = 0;
462178825Sdfr
463178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
464178825Sdfr	return GSS_S_NO_CONTEXT;
465178825Sdfr    }
466178825Sdfr
467178825Sdfr    ctx = (gssspnego_ctx)context_handle;
468178825Sdfr
469178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
470178825Sdfr	return GSS_S_NO_CONTEXT;
471178825Sdfr    }
472178825Sdfr
473178825Sdfr    return gss_wrap_size_limit(minor_status,
474178825Sdfr			       ctx->negotiated_ctx_id,
475178825Sdfr			       conf_req_flag,
476178825Sdfr			       qop_req,
477178825Sdfr			       req_output_size,
478178825Sdfr			       max_input_size);
479178825Sdfr}
480178825Sdfr
481233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_export_sec_context (
482178825Sdfr            OM_uint32 * minor_status,
483178825Sdfr            gss_ctx_id_t * context_handle,
484178825Sdfr            gss_buffer_t interprocess_token
485178825Sdfr           )
486178825Sdfr{
487178825Sdfr    gssspnego_ctx ctx;
488178825Sdfr    OM_uint32 ret;
489178825Sdfr
490178825Sdfr    *minor_status = 0;
491178825Sdfr
492178825Sdfr    if (context_handle == NULL) {
493178825Sdfr	return GSS_S_NO_CONTEXT;
494178825Sdfr    }
495178825Sdfr
496178825Sdfr    ctx = (gssspnego_ctx)*context_handle;
497178825Sdfr
498178825Sdfr    if (ctx == NULL)
499178825Sdfr	return GSS_S_NO_CONTEXT;
500178825Sdfr
501178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
502178825Sdfr
503178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
504178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
505178825Sdfr	return GSS_S_NO_CONTEXT;
506178825Sdfr    }
507178825Sdfr
508178825Sdfr    ret = gss_export_sec_context(minor_status,
509178825Sdfr				 &ctx->negotiated_ctx_id,
510178825Sdfr				 interprocess_token);
511178825Sdfr    if (ret == GSS_S_COMPLETE) {
512178825Sdfr	ret = _gss_spnego_internal_delete_sec_context(minor_status,
513178825Sdfr					     context_handle,
514178825Sdfr					     GSS_C_NO_BUFFER);
515178825Sdfr	if (ret == GSS_S_COMPLETE)
516178825Sdfr	    return GSS_S_COMPLETE;
517178825Sdfr    }
518178825Sdfr
519178825Sdfr    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
520178825Sdfr
521178825Sdfr    return ret;
522178825Sdfr}
523178825Sdfr
524233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_import_sec_context (
525178825Sdfr            OM_uint32 * minor_status,
526178825Sdfr            const gss_buffer_t interprocess_token,
527178825Sdfr            gss_ctx_id_t *context_handle
528178825Sdfr           )
529178825Sdfr{
530178825Sdfr    OM_uint32 ret, minor;
531178825Sdfr    gss_ctx_id_t context;
532178825Sdfr    gssspnego_ctx ctx;
533178825Sdfr
534178825Sdfr    ret = _gss_spnego_alloc_sec_context(minor_status, &context);
535178825Sdfr    if (ret != GSS_S_COMPLETE) {
536178825Sdfr	return ret;
537178825Sdfr    }
538178825Sdfr    ctx = (gssspnego_ctx)context;
539178825Sdfr
540178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
541178825Sdfr
542178825Sdfr    ret = gss_import_sec_context(minor_status,
543178825Sdfr				 interprocess_token,
544178825Sdfr				 &ctx->negotiated_ctx_id);
545178825Sdfr    if (ret != GSS_S_COMPLETE) {
546178825Sdfr	_gss_spnego_internal_delete_sec_context(&minor, context_handle, GSS_C_NO_BUFFER);
547178825Sdfr	return ret;
548178825Sdfr    }
549178825Sdfr
550178825Sdfr    ctx->open = 1;
551178825Sdfr    /* don't bother filling in the rest of the fields */
552178825Sdfr
553178825Sdfr    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
554178825Sdfr
555178825Sdfr    *context_handle = (gss_ctx_id_t)ctx;
556178825Sdfr
557178825Sdfr    return GSS_S_COMPLETE;
558178825Sdfr}
559178825Sdfr
560233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_names_for_mech (
561178825Sdfr            OM_uint32 * minor_status,
562178825Sdfr            const gss_OID mechanism,
563178825Sdfr            gss_OID_set * name_types
564178825Sdfr           )
565178825Sdfr{
566178825Sdfr    gss_OID_set mechs, names, n;
567178825Sdfr    OM_uint32 ret, junk;
568233294Sstas    size_t i, j;
569178825Sdfr
570178825Sdfr    *name_types = NULL;
571178825Sdfr
572178825Sdfr    ret = spnego_supported_mechs(minor_status, &mechs);
573178825Sdfr    if (ret != GSS_S_COMPLETE)
574178825Sdfr	return ret;
575178825Sdfr
576178825Sdfr    ret = gss_create_empty_oid_set(minor_status, &names);
577178825Sdfr    if (ret != GSS_S_COMPLETE)
578178825Sdfr	goto out;
579178825Sdfr
580178825Sdfr    for (i = 0; i < mechs->count; i++) {
581178825Sdfr	ret = gss_inquire_names_for_mech(minor_status,
582178825Sdfr					 &mechs->elements[i],
583178825Sdfr					 &n);
584178825Sdfr	if (ret)
585178825Sdfr	    continue;
586178825Sdfr
587178825Sdfr	for (j = 0; j < n->count; j++)
588178825Sdfr	    gss_add_oid_set_member(minor_status,
589178825Sdfr				   &n->elements[j],
590178825Sdfr				   &names);
591178825Sdfr	gss_release_oid_set(&junk, &n);
592178825Sdfr    }
593178825Sdfr
594178825Sdfr    ret = GSS_S_COMPLETE;
595178825Sdfr    *name_types = names;
596178825Sdfrout:
597178825Sdfr
598178825Sdfr    gss_release_oid_set(&junk, &mechs);
599178825Sdfr
600233294Sstas    return ret;
601178825Sdfr}
602178825Sdfr
603233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_mechs_for_name (
604178825Sdfr            OM_uint32 * minor_status,
605178825Sdfr            const gss_name_t input_name,
606178825Sdfr            gss_OID_set * mech_types
607178825Sdfr           )
608178825Sdfr{
609178825Sdfr    OM_uint32 ret, junk;
610178825Sdfr
611178825Sdfr    ret = gss_create_empty_oid_set(minor_status, mech_types);
612178825Sdfr    if (ret)
613178825Sdfr	return ret;
614178825Sdfr
615178825Sdfr    ret = gss_add_oid_set_member(minor_status,
616178825Sdfr				 GSS_SPNEGO_MECHANISM,
617178825Sdfr				 mech_types);
618178825Sdfr    if (ret)
619178825Sdfr	gss_release_oid_set(&junk, mech_types);
620178825Sdfr
621178825Sdfr    return ret;
622178825Sdfr}
623178825Sdfr
624233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_canonicalize_name (
625178825Sdfr            OM_uint32 * minor_status,
626178825Sdfr            const gss_name_t input_name,
627178825Sdfr            const gss_OID mech_type,
628178825Sdfr            gss_name_t * output_name
629178825Sdfr           )
630178825Sdfr{
631178825Sdfr    /* XXX */
632178825Sdfr    return gss_duplicate_name(minor_status, input_name, output_name);
633178825Sdfr}
634178825Sdfr
635233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_duplicate_name (
636178825Sdfr            OM_uint32 * minor_status,
637178825Sdfr            const gss_name_t src_name,
638178825Sdfr            gss_name_t * dest_name
639178825Sdfr           )
640178825Sdfr{
641178825Sdfr    return gss_duplicate_name(minor_status, src_name, dest_name);
642178825Sdfr}
643178825Sdfr
644233294Sstas#if 0
645233294SstasOM_uint32 GSSAPI_CALLCONV
646233294Sstas_gss_spnego_wrap_iov(OM_uint32 * minor_status,
647233294Sstas		     gss_ctx_id_t  context_handle,
648233294Sstas		     int conf_req_flag,
649233294Sstas		     gss_qop_t qop_req,
650233294Sstas		     int * conf_state,
651233294Sstas		     gss_iov_buffer_desc *iov,
652233294Sstas		     int iov_count)
653178825Sdfr{
654233294Sstas    gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
655178825Sdfr
656178825Sdfr    *minor_status = 0;
657178825Sdfr
658233294Sstas    if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
659178825Sdfr	return GSS_S_NO_CONTEXT;
660178825Sdfr
661233294Sstas    return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id,
662233294Sstas			conf_req_flag, qop_req, conf_state,
663233294Sstas			iov, iov_count);
664178825Sdfr}
665178825Sdfr
666233294SstasOM_uint32 GSSAPI_CALLCONV
667233294Sstas_gss_spnego_unwrap_iov(OM_uint32 *minor_status,
668233294Sstas		       gss_ctx_id_t context_handle,
669233294Sstas		       int *conf_state,
670233294Sstas		       gss_qop_t *qop_state,
671233294Sstas		       gss_iov_buffer_desc *iov,
672233294Sstas		       int iov_count)
673178825Sdfr{
674233294Sstas    gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
675178825Sdfr
676178825Sdfr    *minor_status = 0;
677178825Sdfr
678233294Sstas    if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
679178825Sdfr	return GSS_S_NO_CONTEXT;
680178825Sdfr
681233294Sstas    return gss_unwrap_iov(minor_status,
682233294Sstas			  ctx->negotiated_ctx_id,
683233294Sstas			  conf_state, qop_state,
684233294Sstas			  iov, iov_count);
685178825Sdfr}
686178825Sdfr
687233294SstasOM_uint32 GSSAPI_CALLCONV
688233294Sstas_gss_spnego_wrap_iov_length(OM_uint32 * minor_status,
689233294Sstas			    gss_ctx_id_t context_handle,
690233294Sstas			    int conf_req_flag,
691233294Sstas			    gss_qop_t qop_req,
692233294Sstas			    int *conf_state,
693233294Sstas			    gss_iov_buffer_desc *iov,
694233294Sstas			    int iov_count)
695178825Sdfr{
696233294Sstas    gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
697178825Sdfr
698178825Sdfr    *minor_status = 0;
699178825Sdfr
700233294Sstas    if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
701178825Sdfr	return GSS_S_NO_CONTEXT;
702178825Sdfr
703233294Sstas    return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id,
704233294Sstas			       conf_req_flag, qop_req, conf_state,
705233294Sstas			       iov, iov_count);
706178825Sdfr}
707178825Sdfr
708233294Sstas#endif
709178825Sdfr
710178825Sdfr#if 0
711233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token
712178825Sdfr           (OM_uint32 * minor_status,
713178825Sdfr            const gss_ctx_id_t context_handle,
714178825Sdfr	    gss_buffer_t input_message_buffer)
715178825Sdfr{
716178825Sdfr    gssspnego_ctx ctx;
717178825Sdfr
718178825Sdfr    *minor_status = 0;
719178825Sdfr
720178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
721178825Sdfr	return GSS_S_NO_CONTEXT;
722178825Sdfr    }
723178825Sdfr
724178825Sdfr    ctx = (gssspnego_ctx)context_handle;
725178825Sdfr
726178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
727178825Sdfr	return GSS_S_NO_CONTEXT;
728178825Sdfr    }
729178825Sdfr
730178825Sdfr    return gss_complete_auth_token(minor_status,
731178825Sdfr				   ctx->negotiated_ctx_id,
732178825Sdfr				   input_message_buffer);
733178825Sdfr}
734178825Sdfr#endif
735178825Sdfr
736233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid
737178825Sdfr           (OM_uint32 * minor_status,
738178825Sdfr            const gss_ctx_id_t context_handle,
739178825Sdfr            const gss_OID desired_object,
740178825Sdfr            gss_buffer_set_t *data_set)
741178825Sdfr{
742178825Sdfr    gssspnego_ctx ctx;
743178825Sdfr
744178825Sdfr    *minor_status = 0;
745178825Sdfr
746178825Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
747178825Sdfr	return GSS_S_NO_CONTEXT;
748178825Sdfr    }
749178825Sdfr
750178825Sdfr    ctx = (gssspnego_ctx)context_handle;
751178825Sdfr
752178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
753178825Sdfr	return GSS_S_NO_CONTEXT;
754178825Sdfr    }
755178825Sdfr
756178825Sdfr    return gss_inquire_sec_context_by_oid(minor_status,
757178825Sdfr					  ctx->negotiated_ctx_id,
758178825Sdfr					  desired_object,
759178825Sdfr					  data_set);
760178825Sdfr}
761178825Sdfr
762233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_set_sec_context_option
763178825Sdfr           (OM_uint32 * minor_status,
764178825Sdfr            gss_ctx_id_t * context_handle,
765178825Sdfr            const gss_OID desired_object,
766178825Sdfr            const gss_buffer_t value)
767178825Sdfr{
768178825Sdfr    gssspnego_ctx ctx;
769178825Sdfr
770178825Sdfr    *minor_status = 0;
771178825Sdfr
772178825Sdfr    if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
773178825Sdfr	return GSS_S_NO_CONTEXT;
774178825Sdfr    }
775178825Sdfr
776233294Sstas    ctx = (gssspnego_ctx)*context_handle;
777178825Sdfr
778178825Sdfr    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
779178825Sdfr	return GSS_S_NO_CONTEXT;
780178825Sdfr    }
781178825Sdfr
782178825Sdfr    return gss_set_sec_context_option(minor_status,
783178825Sdfr				      &ctx->negotiated_ctx_id,
784178825Sdfr				      desired_object,
785178825Sdfr				      value);
786178825Sdfr}
787178825Sdfr
788233294Sstas
789233294SstasOM_uint32 GSSAPI_CALLCONV
790233294Sstas_gss_spnego_pseudo_random(OM_uint32 *minor_status,
791233294Sstas			  gss_ctx_id_t context_handle,
792233294Sstas			  int prf_key,
793233294Sstas			  const gss_buffer_t prf_in,
794233294Sstas			  ssize_t desired_output_len,
795233294Sstas			  gss_buffer_t prf_out)
796233294Sstas{
797233294Sstas    gssspnego_ctx ctx;
798233294Sstas
799233294Sstas    *minor_status = 0;
800233294Sstas
801233294Sstas    if (context_handle == GSS_C_NO_CONTEXT)
802233294Sstas	return GSS_S_NO_CONTEXT;
803233294Sstas
804233294Sstas    ctx = (gssspnego_ctx)context_handle;
805233294Sstas
806233294Sstas    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
807233294Sstas	return GSS_S_NO_CONTEXT;
808233294Sstas
809233294Sstas    return gss_pseudo_random(minor_status,
810233294Sstas			     ctx->negotiated_ctx_id,
811233294Sstas			     prf_key,
812233294Sstas			     prf_in,
813233294Sstas			     desired_output_len,
814233294Sstas			     prf_out);
815233294Sstas}
816