xref: /freebsd/crypto/heimdal/lib/gssapi/spnego/accept_sec_context.c (revision fc773115fa2dbb6c01377f2ed47dabf79a4e361a)
1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * Portions Copyright (c) 2004 PADL Software Pty Ltd.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34ae771770SStanislav Sedov #include "spnego_locl.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson static OM_uint32
send_reject(OM_uint32 * minor_status,gss_buffer_t output_token)37c19800e8SDoug Rabson send_reject (OM_uint32 *minor_status,
38c19800e8SDoug Rabson 	     gss_buffer_t output_token)
39c19800e8SDoug Rabson {
40c19800e8SDoug Rabson     NegotiationToken nt;
41c19800e8SDoug Rabson     size_t size;
42c19800e8SDoug Rabson 
43c19800e8SDoug Rabson     nt.element = choice_NegotiationToken_negTokenResp;
44c19800e8SDoug Rabson 
45c19800e8SDoug Rabson     ALLOC(nt.u.negTokenResp.negResult, 1);
46c19800e8SDoug Rabson     if (nt.u.negTokenResp.negResult == NULL) {
47c19800e8SDoug Rabson 	*minor_status = ENOMEM;
48c19800e8SDoug Rabson 	return GSS_S_FAILURE;
49c19800e8SDoug Rabson     }
50c19800e8SDoug Rabson     *(nt.u.negTokenResp.negResult)  = reject;
51c19800e8SDoug Rabson     nt.u.negTokenResp.supportedMech = NULL;
52c19800e8SDoug Rabson     nt.u.negTokenResp.responseToken = NULL;
53c19800e8SDoug Rabson     nt.u.negTokenResp.mechListMIC   = NULL;
54c19800e8SDoug Rabson 
55c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(NegotiationToken,
56c19800e8SDoug Rabson 		       output_token->value, output_token->length, &nt,
57c19800e8SDoug Rabson 		       &size, *minor_status);
58c19800e8SDoug Rabson     free_NegotiationToken(&nt);
59c19800e8SDoug Rabson     if (*minor_status != 0)
60c19800e8SDoug Rabson 	return GSS_S_FAILURE;
61c19800e8SDoug Rabson 
62c19800e8SDoug Rabson     return GSS_S_BAD_MECH;
63c19800e8SDoug Rabson }
64c19800e8SDoug Rabson 
65c19800e8SDoug Rabson static OM_uint32
acceptor_approved(gss_name_t target_name,gss_OID mech)66c19800e8SDoug Rabson acceptor_approved(gss_name_t target_name, gss_OID mech)
67c19800e8SDoug Rabson {
68c19800e8SDoug Rabson     gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
69c19800e8SDoug Rabson     gss_OID_set oidset;
70c19800e8SDoug Rabson     OM_uint32 junk, ret;
71c19800e8SDoug Rabson 
72c19800e8SDoug Rabson     if (target_name == GSS_C_NO_NAME)
73c19800e8SDoug Rabson 	return GSS_S_COMPLETE;
74c19800e8SDoug Rabson 
75c19800e8SDoug Rabson     gss_create_empty_oid_set(&junk, &oidset);
76c19800e8SDoug Rabson     gss_add_oid_set_member(&junk, mech, &oidset);
77c19800e8SDoug Rabson 
78c19800e8SDoug Rabson     ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,
79c19800e8SDoug Rabson 			   GSS_C_ACCEPT, &cred, NULL, NULL);
80c19800e8SDoug Rabson     gss_release_oid_set(&junk, &oidset);
81c19800e8SDoug Rabson     if (ret != GSS_S_COMPLETE)
82c19800e8SDoug Rabson 	return ret;
83c19800e8SDoug Rabson     gss_release_cred(&junk, &cred);
84c19800e8SDoug Rabson 
85c19800e8SDoug Rabson     return GSS_S_COMPLETE;
86c19800e8SDoug Rabson }
87c19800e8SDoug Rabson 
88c19800e8SDoug Rabson static OM_uint32
send_supported_mechs(OM_uint32 * minor_status,gss_buffer_t output_token)89c19800e8SDoug Rabson send_supported_mechs (OM_uint32 *minor_status,
90c19800e8SDoug Rabson 		      gss_buffer_t output_token)
91c19800e8SDoug Rabson {
92c19800e8SDoug Rabson     NegotiationTokenWin nt;
93ae771770SStanislav Sedov     size_t buf_len = 0;
94c19800e8SDoug Rabson     gss_buffer_desc data;
95c19800e8SDoug Rabson     OM_uint32 ret;
96c19800e8SDoug Rabson 
97c19800e8SDoug Rabson     memset(&nt, 0, sizeof(nt));
98c19800e8SDoug Rabson 
99c19800e8SDoug Rabson     nt.element = choice_NegotiationTokenWin_negTokenInit;
100c19800e8SDoug Rabson     nt.u.negTokenInit.reqFlags = NULL;
101c19800e8SDoug Rabson     nt.u.negTokenInit.mechToken = NULL;
102c19800e8SDoug Rabson     nt.u.negTokenInit.negHints = NULL;
103c19800e8SDoug Rabson 
104c19800e8SDoug Rabson     ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME,
105c19800e8SDoug Rabson 					    acceptor_approved, 1, NULL,
106c19800e8SDoug Rabson 					    &nt.u.negTokenInit.mechTypes, NULL);
107c19800e8SDoug Rabson     if (ret != GSS_S_COMPLETE) {
108c19800e8SDoug Rabson 	return ret;
109c19800e8SDoug Rabson     }
110c19800e8SDoug Rabson 
111c19800e8SDoug Rabson     ALLOC(nt.u.negTokenInit.negHints, 1);
112c19800e8SDoug Rabson     if (nt.u.negTokenInit.negHints == NULL) {
113c19800e8SDoug Rabson 	*minor_status = ENOMEM;
114c19800e8SDoug Rabson 	free_NegotiationTokenWin(&nt);
115c19800e8SDoug Rabson 	return GSS_S_FAILURE;
116c19800e8SDoug Rabson     }
117c19800e8SDoug Rabson 
118c19800e8SDoug Rabson     ALLOC(nt.u.negTokenInit.negHints->hintName, 1);
119c19800e8SDoug Rabson     if (nt.u.negTokenInit.negHints->hintName == NULL) {
120c19800e8SDoug Rabson 	*minor_status = ENOMEM;
121c19800e8SDoug Rabson 	free_NegotiationTokenWin(&nt);
122c19800e8SDoug Rabson 	return GSS_S_FAILURE;
123c19800e8SDoug Rabson     }
124c19800e8SDoug Rabson 
125ae771770SStanislav Sedov     *nt.u.negTokenInit.negHints->hintName = strdup("not_defined_in_RFC4178@please_ignore");
126c19800e8SDoug Rabson     nt.u.negTokenInit.negHints->hintAddress = NULL;
127c19800e8SDoug Rabson 
128c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(NegotiationTokenWin,
129c19800e8SDoug Rabson 		       data.value, data.length, &nt, &buf_len, ret);
130c19800e8SDoug Rabson     free_NegotiationTokenWin(&nt);
131c19800e8SDoug Rabson     if (ret) {
132ae771770SStanislav Sedov 	*minor_status = ret;
133ae771770SStanislav Sedov 	return GSS_S_FAILURE;
134c19800e8SDoug Rabson     }
135ae771770SStanislav Sedov     if (data.length != buf_len) {
136c19800e8SDoug Rabson 	abort();
137ae771770SStanislav Sedov         UNREACHABLE(return GSS_S_FAILURE);
138ae771770SStanislav Sedov     }
139c19800e8SDoug Rabson 
140c19800e8SDoug Rabson     ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);
141c19800e8SDoug Rabson 
142c19800e8SDoug Rabson     free (data.value);
143c19800e8SDoug Rabson 
144c19800e8SDoug Rabson     if (ret != GSS_S_COMPLETE)
145c19800e8SDoug Rabson 	return ret;
146c19800e8SDoug Rabson 
147c19800e8SDoug Rabson     *minor_status = 0;
148c19800e8SDoug Rabson 
149c19800e8SDoug Rabson     return GSS_S_CONTINUE_NEEDED;
150c19800e8SDoug Rabson }
151c19800e8SDoug Rabson 
152c19800e8SDoug Rabson static OM_uint32
send_accept(OM_uint32 * minor_status,gssspnego_ctx context_handle,gss_buffer_t mech_token,int initial_response,gss_buffer_t mech_buf,gss_buffer_t output_token)153c19800e8SDoug Rabson send_accept (OM_uint32 *minor_status,
154c19800e8SDoug Rabson 	     gssspnego_ctx context_handle,
155c19800e8SDoug Rabson 	     gss_buffer_t mech_token,
156c19800e8SDoug Rabson 	     int initial_response,
157c19800e8SDoug Rabson 	     gss_buffer_t mech_buf,
158c19800e8SDoug Rabson 	     gss_buffer_t output_token)
159c19800e8SDoug Rabson {
160c19800e8SDoug Rabson     NegotiationToken nt;
161c19800e8SDoug Rabson     OM_uint32 ret;
162c19800e8SDoug Rabson     gss_buffer_desc mech_mic_buf;
163c19800e8SDoug Rabson     size_t size;
164c19800e8SDoug Rabson 
165c19800e8SDoug Rabson     memset(&nt, 0, sizeof(nt));
166c19800e8SDoug Rabson 
167c19800e8SDoug Rabson     nt.element = choice_NegotiationToken_negTokenResp;
168c19800e8SDoug Rabson 
169c19800e8SDoug Rabson     ALLOC(nt.u.negTokenResp.negResult, 1);
170c19800e8SDoug Rabson     if (nt.u.negTokenResp.negResult == NULL) {
171c19800e8SDoug Rabson 	*minor_status = ENOMEM;
172c19800e8SDoug Rabson 	return GSS_S_FAILURE;
173c19800e8SDoug Rabson     }
174c19800e8SDoug Rabson 
175c19800e8SDoug Rabson     if (context_handle->open) {
176c19800e8SDoug Rabson 	if (mech_token != GSS_C_NO_BUFFER
177c19800e8SDoug Rabson 	    && mech_token->length != 0
178c19800e8SDoug Rabson 	    && mech_buf != GSS_C_NO_BUFFER)
179c19800e8SDoug Rabson 	    *(nt.u.negTokenResp.negResult)  = accept_incomplete;
180c19800e8SDoug Rabson 	else
181c19800e8SDoug Rabson 	    *(nt.u.negTokenResp.negResult)  = accept_completed;
182c19800e8SDoug Rabson     } else {
183c19800e8SDoug Rabson 	if (initial_response && context_handle->require_mic)
184c19800e8SDoug Rabson 	    *(nt.u.negTokenResp.negResult)  = request_mic;
185c19800e8SDoug Rabson 	else
186c19800e8SDoug Rabson 	    *(nt.u.negTokenResp.negResult)  = accept_incomplete;
187c19800e8SDoug Rabson     }
188c19800e8SDoug Rabson 
189c19800e8SDoug Rabson     if (initial_response) {
190c19800e8SDoug Rabson 	ALLOC(nt.u.negTokenResp.supportedMech, 1);
191c19800e8SDoug Rabson 	if (nt.u.negTokenResp.supportedMech == NULL) {
192c19800e8SDoug Rabson 	    free_NegotiationToken(&nt);
193c19800e8SDoug Rabson 	    *minor_status = ENOMEM;
194c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
195c19800e8SDoug Rabson 	}
196c19800e8SDoug Rabson 
197c19800e8SDoug Rabson 	ret = der_get_oid(context_handle->preferred_mech_type->elements,
198c19800e8SDoug Rabson 			  context_handle->preferred_mech_type->length,
199c19800e8SDoug Rabson 			  nt.u.negTokenResp.supportedMech,
200c19800e8SDoug Rabson 			  NULL);
201c19800e8SDoug Rabson 	if (ret) {
202c19800e8SDoug Rabson 	    free_NegotiationToken(&nt);
203c19800e8SDoug Rabson 	    *minor_status = ENOMEM;
204c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
205c19800e8SDoug Rabson 	}
206c19800e8SDoug Rabson     } else {
207c19800e8SDoug Rabson 	nt.u.negTokenResp.supportedMech = NULL;
208c19800e8SDoug Rabson     }
209c19800e8SDoug Rabson 
210c19800e8SDoug Rabson     if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
211c19800e8SDoug Rabson 	ALLOC(nt.u.negTokenResp.responseToken, 1);
212c19800e8SDoug Rabson 	if (nt.u.negTokenResp.responseToken == NULL) {
213c19800e8SDoug Rabson 	    free_NegotiationToken(&nt);
214c19800e8SDoug Rabson 	    *minor_status = ENOMEM;
215c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
216c19800e8SDoug Rabson 	}
217c19800e8SDoug Rabson 	nt.u.negTokenResp.responseToken->length = mech_token->length;
218c19800e8SDoug Rabson 	nt.u.negTokenResp.responseToken->data   = mech_token->value;
219c19800e8SDoug Rabson 	mech_token->length = 0;
220c19800e8SDoug Rabson 	mech_token->value  = NULL;
221c19800e8SDoug Rabson     } else {
222c19800e8SDoug Rabson 	nt.u.negTokenResp.responseToken = NULL;
223c19800e8SDoug Rabson     }
224c19800e8SDoug Rabson 
225c19800e8SDoug Rabson     if (mech_buf != GSS_C_NO_BUFFER) {
226c19800e8SDoug Rabson 	ret = gss_get_mic(minor_status,
227c19800e8SDoug Rabson 			  context_handle->negotiated_ctx_id,
228c19800e8SDoug Rabson 			  0,
229c19800e8SDoug Rabson 			  mech_buf,
230c19800e8SDoug Rabson 			  &mech_mic_buf);
231c19800e8SDoug Rabson 	if (ret == GSS_S_COMPLETE) {
232c19800e8SDoug Rabson 	    ALLOC(nt.u.negTokenResp.mechListMIC, 1);
233c19800e8SDoug Rabson 	    if (nt.u.negTokenResp.mechListMIC == NULL) {
234c19800e8SDoug Rabson 		gss_release_buffer(minor_status, &mech_mic_buf);
235c19800e8SDoug Rabson 		free_NegotiationToken(&nt);
236c19800e8SDoug Rabson 		*minor_status = ENOMEM;
237c19800e8SDoug Rabson 		return GSS_S_FAILURE;
238c19800e8SDoug Rabson 	    }
239c19800e8SDoug Rabson 	    nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;
240c19800e8SDoug Rabson 	    nt.u.negTokenResp.mechListMIC->data   = mech_mic_buf.value;
241c19800e8SDoug Rabson 	} else if (ret == GSS_S_UNAVAILABLE) {
242c19800e8SDoug Rabson 	    nt.u.negTokenResp.mechListMIC = NULL;
243c19800e8SDoug Rabson 	} else {
244c19800e8SDoug Rabson 	    free_NegotiationToken(&nt);
245c19800e8SDoug Rabson 	    return ret;
246c19800e8SDoug Rabson 	}
247c19800e8SDoug Rabson 
248c19800e8SDoug Rabson     } else
249c19800e8SDoug Rabson 	nt.u.negTokenResp.mechListMIC = NULL;
250c19800e8SDoug Rabson 
251c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(NegotiationToken,
252c19800e8SDoug Rabson 		       output_token->value, output_token->length,
253c19800e8SDoug Rabson 		       &nt, &size, ret);
254c19800e8SDoug Rabson     if (ret) {
255c19800e8SDoug Rabson 	free_NegotiationToken(&nt);
256c19800e8SDoug Rabson 	*minor_status = ret;
257c19800e8SDoug Rabson 	return GSS_S_FAILURE;
258c19800e8SDoug Rabson     }
259c19800e8SDoug Rabson 
260c19800e8SDoug Rabson     /*
261c19800e8SDoug Rabson      * The response should not be encapsulated, because
262c19800e8SDoug Rabson      * it is a SubsequentContextToken (note though RFC 1964
263c19800e8SDoug Rabson      * specifies encapsulation for all _Kerberos_ tokens).
264c19800e8SDoug Rabson      */
265c19800e8SDoug Rabson 
266c19800e8SDoug Rabson     if (*(nt.u.negTokenResp.negResult) == accept_completed)
267c19800e8SDoug Rabson 	ret = GSS_S_COMPLETE;
268c19800e8SDoug Rabson     else
269c19800e8SDoug Rabson 	ret = GSS_S_CONTINUE_NEEDED;
270c19800e8SDoug Rabson     free_NegotiationToken(&nt);
271c19800e8SDoug Rabson     return ret;
272c19800e8SDoug Rabson }
273c19800e8SDoug Rabson 
274c19800e8SDoug Rabson 
275c19800e8SDoug Rabson static OM_uint32
verify_mechlist_mic(OM_uint32 * minor_status,gssspnego_ctx context_handle,gss_buffer_t mech_buf,heim_octet_string * mechListMIC)276c19800e8SDoug Rabson verify_mechlist_mic
277c19800e8SDoug Rabson 	   (OM_uint32 *minor_status,
278c19800e8SDoug Rabson 	    gssspnego_ctx context_handle,
279c19800e8SDoug Rabson 	    gss_buffer_t mech_buf,
280c19800e8SDoug Rabson 	    heim_octet_string *mechListMIC
281c19800e8SDoug Rabson 	   )
282c19800e8SDoug Rabson {
283c19800e8SDoug Rabson     OM_uint32 ret;
284c19800e8SDoug Rabson     gss_buffer_desc mic_buf;
285c19800e8SDoug Rabson 
286c19800e8SDoug Rabson     if (context_handle->verified_mic) {
287c19800e8SDoug Rabson 	/* This doesn't make sense, we've already verified it? */
288c19800e8SDoug Rabson 	*minor_status = 0;
289c19800e8SDoug Rabson 	return GSS_S_DUPLICATE_TOKEN;
290c19800e8SDoug Rabson     }
291c19800e8SDoug Rabson 
292c19800e8SDoug Rabson     if (mechListMIC == NULL) {
293c19800e8SDoug Rabson 	*minor_status = 0;
294c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
295c19800e8SDoug Rabson     }
296c19800e8SDoug Rabson 
297c19800e8SDoug Rabson     mic_buf.length = mechListMIC->length;
298c19800e8SDoug Rabson     mic_buf.value  = mechListMIC->data;
299c19800e8SDoug Rabson 
300c19800e8SDoug Rabson     ret = gss_verify_mic(minor_status,
301c19800e8SDoug Rabson 			 context_handle->negotiated_ctx_id,
302c19800e8SDoug Rabson 			 mech_buf,
303c19800e8SDoug Rabson 			 &mic_buf,
304c19800e8SDoug Rabson 			 NULL);
305c19800e8SDoug Rabson 
306c19800e8SDoug Rabson     if (ret != GSS_S_COMPLETE)
307c19800e8SDoug Rabson 	ret = GSS_S_DEFECTIVE_TOKEN;
308c19800e8SDoug Rabson 
309c19800e8SDoug Rabson     return ret;
310c19800e8SDoug Rabson }
311c19800e8SDoug Rabson 
312c19800e8SDoug Rabson static OM_uint32
select_mech(OM_uint32 * minor_status,MechType * mechType,int verify_p,gss_OID * mech_p)313c19800e8SDoug Rabson select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p,
314c19800e8SDoug Rabson 	    gss_OID *mech_p)
315c19800e8SDoug Rabson {
316c19800e8SDoug Rabson     char mechbuf[64];
317c19800e8SDoug Rabson     size_t mech_len;
318c19800e8SDoug Rabson     gss_OID_desc oid;
31933f12199SDoug Rabson     gss_OID oidp;
32033f12199SDoug Rabson     gss_OID_set mechs;
321ae771770SStanislav Sedov     size_t i;
322c19800e8SDoug Rabson     OM_uint32 ret, junk;
323c19800e8SDoug Rabson 
324c19800e8SDoug Rabson     ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
325c19800e8SDoug Rabson 		       sizeof(mechbuf),
326c19800e8SDoug Rabson 		       mechType,
327c19800e8SDoug Rabson 		       &mech_len);
328c19800e8SDoug Rabson     if (ret) {
329c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
330c19800e8SDoug Rabson     }
331c19800e8SDoug Rabson 
332c19800e8SDoug Rabson     oid.length   = mech_len;
333c19800e8SDoug Rabson     oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
334c19800e8SDoug Rabson 
335c19800e8SDoug Rabson     if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
336c19800e8SDoug Rabson 	return GSS_S_BAD_MECH;
337c19800e8SDoug Rabson     }
338c19800e8SDoug Rabson 
339c19800e8SDoug Rabson     *minor_status = 0;
340c19800e8SDoug Rabson 
341c19800e8SDoug Rabson     /* Translate broken MS Kebreros OID */
34233f12199SDoug Rabson     if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc))
34333f12199SDoug Rabson 	    oidp = &_gss_spnego_krb5_mechanism_oid_desc;
34433f12199SDoug Rabson     else
34533f12199SDoug Rabson 	    oidp = &oid;
346c19800e8SDoug Rabson 
34733f12199SDoug Rabson 
34833f12199SDoug Rabson     ret = gss_indicate_mechs(&junk, &mechs);
34933f12199SDoug Rabson     if (ret)
35033f12199SDoug Rabson 	    return (ret);
35133f12199SDoug Rabson 
35233f12199SDoug Rabson     for (i = 0; i < mechs->count; i++)
35333f12199SDoug Rabson 	    if (gss_oid_equal(&mechs->elements[i], oidp))
35433f12199SDoug Rabson 		    break;
35533f12199SDoug Rabson 
35633f12199SDoug Rabson     if (i == mechs->count) {
35733f12199SDoug Rabson 	    gss_release_oid_set(&junk, &mechs);
358c19800e8SDoug Rabson 	    return GSS_S_BAD_MECH;
359c19800e8SDoug Rabson     }
36033f12199SDoug Rabson     gss_release_oid_set(&junk, &mechs);
36133f12199SDoug Rabson 
36233f12199SDoug Rabson     ret = gss_duplicate_oid(minor_status,
36333f12199SDoug Rabson 			    &oid, /* possibly this should be oidp */
36433f12199SDoug Rabson 			    mech_p);
365c19800e8SDoug Rabson 
366c19800e8SDoug Rabson     if (verify_p) {
367c19800e8SDoug Rabson 	gss_name_t name = GSS_C_NO_NAME;
368c19800e8SDoug Rabson 	gss_buffer_desc namebuf;
369c19800e8SDoug Rabson 	char *str = NULL, *host, hostname[MAXHOSTNAMELEN];
370c19800e8SDoug Rabson 
371c19800e8SDoug Rabson 	host = getenv("GSSAPI_SPNEGO_NAME");
372c19800e8SDoug Rabson 	if (host == NULL || issuid()) {
373ae771770SStanislav Sedov 	    int rv;
374c19800e8SDoug Rabson 	    if (gethostname(hostname, sizeof(hostname)) != 0) {
375c19800e8SDoug Rabson 		*minor_status = errno;
376c19800e8SDoug Rabson 		return GSS_S_FAILURE;
377c19800e8SDoug Rabson 	    }
378ae771770SStanislav Sedov 	    rv = asprintf(&str, "host@%s", hostname);
379ae771770SStanislav Sedov 	    if (rv < 0 || str == NULL) {
380ae771770SStanislav Sedov 		*minor_status = ENOMEM;
381ae771770SStanislav Sedov 		return GSS_S_FAILURE;
382ae771770SStanislav Sedov 	    }
383c19800e8SDoug Rabson 	    host = str;
384c19800e8SDoug Rabson 	}
385c19800e8SDoug Rabson 
386c19800e8SDoug Rabson 	namebuf.length = strlen(host);
387c19800e8SDoug Rabson 	namebuf.value = host;
388c19800e8SDoug Rabson 
389c19800e8SDoug Rabson 	ret = gss_import_name(minor_status, &namebuf,
390c19800e8SDoug Rabson 			      GSS_C_NT_HOSTBASED_SERVICE, &name);
391c19800e8SDoug Rabson 	if (str)
392c19800e8SDoug Rabson 	    free(str);
393c19800e8SDoug Rabson 	if (ret != GSS_S_COMPLETE)
394c19800e8SDoug Rabson 	    return ret;
395c19800e8SDoug Rabson 
396c19800e8SDoug Rabson 	ret = acceptor_approved(name, *mech_p);
397c19800e8SDoug Rabson 	gss_release_name(&junk, &name);
398c19800e8SDoug Rabson     }
399c19800e8SDoug Rabson 
400c19800e8SDoug Rabson     return ret;
401c19800e8SDoug Rabson }
402c19800e8SDoug Rabson 
403c19800e8SDoug Rabson 
404c19800e8SDoug Rabson static OM_uint32
acceptor_complete(OM_uint32 * minor_status,gssspnego_ctx ctx,int * get_mic,gss_buffer_t mech_buf,gss_buffer_t mech_input_token,gss_buffer_t mech_output_token,heim_octet_string * mic,gss_buffer_t output_token)405c19800e8SDoug Rabson acceptor_complete(OM_uint32 * minor_status,
406c19800e8SDoug Rabson 		  gssspnego_ctx ctx,
407c19800e8SDoug Rabson 		  int *get_mic,
408c19800e8SDoug Rabson 		  gss_buffer_t mech_buf,
409c19800e8SDoug Rabson 		  gss_buffer_t mech_input_token,
410c19800e8SDoug Rabson 		  gss_buffer_t mech_output_token,
411c19800e8SDoug Rabson 		  heim_octet_string *mic,
412c19800e8SDoug Rabson 		  gss_buffer_t output_token)
413c19800e8SDoug Rabson {
414c19800e8SDoug Rabson     OM_uint32 ret;
415c19800e8SDoug Rabson     int require_mic, verify_mic;
416c19800e8SDoug Rabson 
417c19800e8SDoug Rabson     ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic);
418c19800e8SDoug Rabson     if (ret)
419c19800e8SDoug Rabson 	return ret;
420c19800e8SDoug Rabson 
421c19800e8SDoug Rabson     ctx->require_mic = require_mic;
422c19800e8SDoug Rabson 
423c19800e8SDoug Rabson     if (mic != NULL)
424c19800e8SDoug Rabson 	require_mic = 1;
425c19800e8SDoug Rabson 
426c19800e8SDoug Rabson     if (ctx->open && require_mic) {
427c19800e8SDoug Rabson 	if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
428c19800e8SDoug Rabson 	    verify_mic = 1;
429c19800e8SDoug Rabson 	    *get_mic = 0;
430c19800e8SDoug Rabson 	} else if (mech_output_token != GSS_C_NO_BUFFER &&
431c19800e8SDoug Rabson 		   mech_output_token->length == 0) { /* Odd */
432c19800e8SDoug Rabson 	    *get_mic = verify_mic = 1;
433c19800e8SDoug Rabson 	} else { /* Even/One */
434c19800e8SDoug Rabson 	    verify_mic = 0;
435c19800e8SDoug Rabson 	    *get_mic = 1;
436c19800e8SDoug Rabson 	}
437c19800e8SDoug Rabson 
438ae771770SStanislav Sedov 	if (verify_mic || *get_mic) {
439c19800e8SDoug Rabson 	    int eret;
440ae771770SStanislav Sedov 	    size_t buf_len = 0;
441c19800e8SDoug Rabson 
442c19800e8SDoug Rabson 	    ASN1_MALLOC_ENCODE(MechTypeList,
443c19800e8SDoug Rabson 			       mech_buf->value, mech_buf->length,
444c19800e8SDoug Rabson 			       &ctx->initiator_mech_types, &buf_len, eret);
445c19800e8SDoug Rabson 	    if (eret) {
446c19800e8SDoug Rabson 		*minor_status = eret;
447c19800e8SDoug Rabson 		return GSS_S_FAILURE;
448c19800e8SDoug Rabson 	    }
449ae771770SStanislav Sedov 	    heim_assert(mech_buf->length == buf_len, "Internal ASN.1 error");
450ae771770SStanislav Sedov 	    UNREACHABLE(return GSS_S_FAILURE);
451c19800e8SDoug Rabson 	}
452c19800e8SDoug Rabson 
453c19800e8SDoug Rabson 	if (verify_mic) {
454c19800e8SDoug Rabson 	    ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);
455c19800e8SDoug Rabson 	    if (ret) {
456ae771770SStanislav Sedov 		if (*get_mic)
457c19800e8SDoug Rabson 		    send_reject (minor_status, output_token);
458c19800e8SDoug Rabson 		return ret;
459c19800e8SDoug Rabson 	    }
460c19800e8SDoug Rabson 	    ctx->verified_mic = 1;
461c19800e8SDoug Rabson 	}
462c19800e8SDoug Rabson     } else
463ae771770SStanislav Sedov 	*get_mic = 0;
464c19800e8SDoug Rabson 
465c19800e8SDoug Rabson     return GSS_S_COMPLETE;
466c19800e8SDoug Rabson }
467c19800e8SDoug Rabson 
468c19800e8SDoug Rabson 
469ae771770SStanislav Sedov static OM_uint32 GSSAPI_CALLCONV
acceptor_start(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)470c19800e8SDoug Rabson acceptor_start
471c19800e8SDoug Rabson 	   (OM_uint32 * minor_status,
472c19800e8SDoug Rabson 	    gss_ctx_id_t * context_handle,
473c19800e8SDoug Rabson 	    const gss_cred_id_t acceptor_cred_handle,
474c19800e8SDoug Rabson 	    const gss_buffer_t input_token_buffer,
475c19800e8SDoug Rabson 	    const gss_channel_bindings_t input_chan_bindings,
476c19800e8SDoug Rabson 	    gss_name_t * src_name,
477c19800e8SDoug Rabson 	    gss_OID * mech_type,
478c19800e8SDoug Rabson 	    gss_buffer_t output_token,
479c19800e8SDoug Rabson 	    OM_uint32 * ret_flags,
480c19800e8SDoug Rabson 	    OM_uint32 * time_rec,
481c19800e8SDoug Rabson 	    gss_cred_id_t *delegated_cred_handle
482c19800e8SDoug Rabson 	   )
483c19800e8SDoug Rabson {
484ae771770SStanislav Sedov     OM_uint32 ret, junk;
485c19800e8SDoug Rabson     NegotiationToken nt;
486c19800e8SDoug Rabson     size_t nt_len;
487c19800e8SDoug Rabson     NegTokenInit *ni;
488c19800e8SDoug Rabson     gss_buffer_desc data;
489c19800e8SDoug Rabson     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
490c19800e8SDoug Rabson     gss_buffer_desc mech_output_token;
491c19800e8SDoug Rabson     gss_buffer_desc mech_buf;
492c19800e8SDoug Rabson     gss_OID preferred_mech_type = GSS_C_NO_OID;
493c19800e8SDoug Rabson     gssspnego_ctx ctx;
494c19800e8SDoug Rabson     int get_mic = 0;
495c19800e8SDoug Rabson     int first_ok = 0;
496c19800e8SDoug Rabson 
497c19800e8SDoug Rabson     mech_output_token.value = NULL;
498c19800e8SDoug Rabson     mech_output_token.length = 0;
499c19800e8SDoug Rabson     mech_buf.value = NULL;
500c19800e8SDoug Rabson 
501c19800e8SDoug Rabson     if (input_token_buffer->length == 0)
502c19800e8SDoug Rabson 	return send_supported_mechs (minor_status, output_token);
503c19800e8SDoug Rabson 
504c19800e8SDoug Rabson     ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);
505c19800e8SDoug Rabson     if (ret != GSS_S_COMPLETE)
506c19800e8SDoug Rabson 	return ret;
507c19800e8SDoug Rabson 
508c19800e8SDoug Rabson     ctx = (gssspnego_ctx)*context_handle;
509c19800e8SDoug Rabson 
510c19800e8SDoug Rabson     /*
511c19800e8SDoug Rabson      * The GSS-API encapsulation is only present on the initial
512c19800e8SDoug Rabson      * context token (negTokenInit).
513c19800e8SDoug Rabson      */
514c19800e8SDoug Rabson     ret = gss_decapsulate_token (input_token_buffer,
515c19800e8SDoug Rabson 				 GSS_SPNEGO_MECHANISM,
516c19800e8SDoug Rabson 				 &data);
517c19800e8SDoug Rabson     if (ret)
518c19800e8SDoug Rabson 	return ret;
519c19800e8SDoug Rabson 
520c19800e8SDoug Rabson     ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len);
521c19800e8SDoug Rabson     gss_release_buffer(minor_status, &data);
522c19800e8SDoug Rabson     if (ret) {
523c19800e8SDoug Rabson 	*minor_status = ret;
524c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
525c19800e8SDoug Rabson     }
526c19800e8SDoug Rabson     if (nt.element != choice_NegotiationToken_negTokenInit) {
527c19800e8SDoug Rabson 	*minor_status = 0;
528c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
529c19800e8SDoug Rabson     }
530c19800e8SDoug Rabson     ni = &nt.u.negTokenInit;
531c19800e8SDoug Rabson 
532c19800e8SDoug Rabson     if (ni->mechTypes.len < 1) {
533c19800e8SDoug Rabson 	free_NegotiationToken(&nt);
534c19800e8SDoug Rabson 	*minor_status = 0;
535c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
536c19800e8SDoug Rabson     }
537c19800e8SDoug Rabson 
538c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
539c19800e8SDoug Rabson 
540c19800e8SDoug Rabson     ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types);
541c19800e8SDoug Rabson     if (ret) {
542c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
543c19800e8SDoug Rabson 	free_NegotiationToken(&nt);
544c19800e8SDoug Rabson 	*minor_status = ret;
545c19800e8SDoug Rabson 	return GSS_S_FAILURE;
546c19800e8SDoug Rabson     }
547c19800e8SDoug Rabson 
548c19800e8SDoug Rabson     /*
549c19800e8SDoug Rabson      * First we try the opportunistic token if we have support for it,
550c19800e8SDoug Rabson      * don't try to verify we have credential for the token,
551ae771770SStanislav Sedov      * gss_accept_sec_context() will (hopefully) tell us that.
552c19800e8SDoug Rabson      * If that failes,
553c19800e8SDoug Rabson      */
554c19800e8SDoug Rabson 
555c19800e8SDoug Rabson     ret = select_mech(minor_status,
556c19800e8SDoug Rabson 		      &ni->mechTypes.val[0],
557c19800e8SDoug Rabson 		      0,
558c19800e8SDoug Rabson 		      &preferred_mech_type);
559c19800e8SDoug Rabson 
560c19800e8SDoug Rabson     if (ret == 0 && ni->mechToken != NULL) {
561c19800e8SDoug Rabson 	gss_buffer_desc ibuf;
562c19800e8SDoug Rabson 
563c19800e8SDoug Rabson 	ibuf.length = ni->mechToken->length;
564c19800e8SDoug Rabson 	ibuf.value = ni->mechToken->data;
565c19800e8SDoug Rabson 	mech_input_token = &ibuf;
566c19800e8SDoug Rabson 
567c19800e8SDoug Rabson 	if (ctx->mech_src_name != GSS_C_NO_NAME)
568ae771770SStanislav Sedov 	    gss_release_name(&junk, &ctx->mech_src_name);
569c19800e8SDoug Rabson 
570ae771770SStanislav Sedov 	ret = gss_accept_sec_context(minor_status,
571c19800e8SDoug Rabson 				     &ctx->negotiated_ctx_id,
572ae771770SStanislav Sedov 				     acceptor_cred_handle,
573c19800e8SDoug Rabson 				     mech_input_token,
574c19800e8SDoug Rabson 				     input_chan_bindings,
575c19800e8SDoug Rabson 				     &ctx->mech_src_name,
576c19800e8SDoug Rabson 				     &ctx->negotiated_mech_type,
577c19800e8SDoug Rabson 				     &mech_output_token,
578c19800e8SDoug Rabson 				     &ctx->mech_flags,
579c19800e8SDoug Rabson 				     &ctx->mech_time_rec,
580ae771770SStanislav Sedov 				     delegated_cred_handle);
581ae771770SStanislav Sedov 
582c19800e8SDoug Rabson 	if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
583c19800e8SDoug Rabson 	    ctx->preferred_mech_type = preferred_mech_type;
584c19800e8SDoug Rabson 	    if (ret == GSS_S_COMPLETE)
585c19800e8SDoug Rabson 		ctx->open = 1;
586c19800e8SDoug Rabson 
587c19800e8SDoug Rabson 	    ret = acceptor_complete(minor_status,
588c19800e8SDoug Rabson 				    ctx,
589c19800e8SDoug Rabson 				    &get_mic,
590c19800e8SDoug Rabson 				    &mech_buf,
591c19800e8SDoug Rabson 				    mech_input_token,
592c19800e8SDoug Rabson 				    &mech_output_token,
593c19800e8SDoug Rabson 				    ni->mechListMIC,
594c19800e8SDoug Rabson 				    output_token);
595c19800e8SDoug Rabson 	    if (ret != GSS_S_COMPLETE)
596c19800e8SDoug Rabson 		goto out;
597c19800e8SDoug Rabson 
598c19800e8SDoug Rabson 	    first_ok = 1;
599ae771770SStanislav Sedov 	} else {
600ae771770SStanislav Sedov 	    gss_mg_collect_error(preferred_mech_type, ret, *minor_status);
601c19800e8SDoug Rabson 	}
602c19800e8SDoug Rabson     }
603c19800e8SDoug Rabson 
604c19800e8SDoug Rabson     /*
605c19800e8SDoug Rabson      * If opportunistic token failed, lets try the other mechs.
606c19800e8SDoug Rabson      */
607c19800e8SDoug Rabson 
608*fc773115SCy Schubert     if (!first_ok) {
609ae771770SStanislav Sedov 	size_t j;
610ae771770SStanislav Sedov 
611ae771770SStanislav Sedov 	preferred_mech_type = GSS_C_NO_OID;
612c19800e8SDoug Rabson 
613c19800e8SDoug Rabson 	/* Call glue layer to find first mech we support */
614ae771770SStanislav Sedov 	for (j = 1; j < ni->mechTypes.len; ++j) {
615c19800e8SDoug Rabson 	    ret = select_mech(minor_status,
616ae771770SStanislav Sedov 			      &ni->mechTypes.val[j],
617c19800e8SDoug Rabson 			      1,
618c19800e8SDoug Rabson 			      &preferred_mech_type);
619c19800e8SDoug Rabson 	    if (ret == 0)
620c19800e8SDoug Rabson 		break;
621c19800e8SDoug Rabson 	}
622c19800e8SDoug Rabson     }
623c19800e8SDoug Rabson 
624c19800e8SDoug Rabson     ctx->preferred_mech_type = preferred_mech_type;
625ed549cb0SCy Schubert 
626ed549cb0SCy Schubert     if (preferred_mech_type == GSS_C_NO_OID) {
627ed549cb0SCy Schubert         send_reject(minor_status, output_token);
628ed549cb0SCy Schubert         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
629ed549cb0SCy Schubert         free_NegotiationToken(&nt);
630ed549cb0SCy Schubert         return ret;
631c19800e8SDoug Rabson     }
632c19800e8SDoug Rabson 
633c19800e8SDoug Rabson     /*
634c19800e8SDoug Rabson      * The initial token always have a response
635c19800e8SDoug Rabson      */
636c19800e8SDoug Rabson 
637c19800e8SDoug Rabson     ret = send_accept (minor_status,
638c19800e8SDoug Rabson 		       ctx,
639c19800e8SDoug Rabson 		       &mech_output_token,
640c19800e8SDoug Rabson 		       1,
641c19800e8SDoug Rabson 		       get_mic ? &mech_buf : NULL,
642c19800e8SDoug Rabson 		       output_token);
643c19800e8SDoug Rabson     if (ret)
644c19800e8SDoug Rabson 	goto out;
645c19800e8SDoug Rabson 
646c19800e8SDoug Rabson out:
647c19800e8SDoug Rabson     if (mech_output_token.value != NULL)
648ae771770SStanislav Sedov 	gss_release_buffer(&junk, &mech_output_token);
649c19800e8SDoug Rabson     if (mech_buf.value != NULL) {
650c19800e8SDoug Rabson 	free(mech_buf.value);
651c19800e8SDoug Rabson 	mech_buf.value = NULL;
652c19800e8SDoug Rabson     }
653c19800e8SDoug Rabson     free_NegotiationToken(&nt);
654c19800e8SDoug Rabson 
655c19800e8SDoug Rabson 
656c19800e8SDoug Rabson     if (ret == GSS_S_COMPLETE) {
657c19800e8SDoug Rabson 	if (src_name != NULL && ctx->mech_src_name != NULL) {
658c19800e8SDoug Rabson 	    spnego_name name;
659c19800e8SDoug Rabson 
660c19800e8SDoug Rabson 	    name = calloc(1, sizeof(*name));
661c19800e8SDoug Rabson 	    if (name) {
662c19800e8SDoug Rabson 		name->mech = ctx->mech_src_name;
663c19800e8SDoug Rabson 		ctx->mech_src_name = NULL;
664c19800e8SDoug Rabson 		*src_name = (gss_name_t)name;
665c19800e8SDoug Rabson 	    }
666c19800e8SDoug Rabson 	}
667c19800e8SDoug Rabson     }
668c19800e8SDoug Rabson 
669c19800e8SDoug Rabson     if (mech_type != NULL)
670c19800e8SDoug Rabson 	*mech_type = ctx->negotiated_mech_type;
671c19800e8SDoug Rabson     if (ret_flags != NULL)
672c19800e8SDoug Rabson 	*ret_flags = ctx->mech_flags;
673c19800e8SDoug Rabson     if (time_rec != NULL)
674c19800e8SDoug Rabson 	*time_rec = ctx->mech_time_rec;
675c19800e8SDoug Rabson 
676c19800e8SDoug Rabson     if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
677c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
678c19800e8SDoug Rabson  	return ret;
679c19800e8SDoug Rabson     }
680c19800e8SDoug Rabson 
681ae771770SStanislav Sedov     _gss_spnego_internal_delete_sec_context(&junk, context_handle,
682c19800e8SDoug Rabson 					    GSS_C_NO_BUFFER);
683c19800e8SDoug Rabson 
684c19800e8SDoug Rabson     return ret;
685c19800e8SDoug Rabson }
686c19800e8SDoug Rabson 
687c19800e8SDoug Rabson 
688ae771770SStanislav Sedov static OM_uint32 GSSAPI_CALLCONV
acceptor_continue(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)689c19800e8SDoug Rabson acceptor_continue
690c19800e8SDoug Rabson 	   (OM_uint32 * minor_status,
691c19800e8SDoug Rabson 	    gss_ctx_id_t * context_handle,
692c19800e8SDoug Rabson 	    const gss_cred_id_t acceptor_cred_handle,
693c19800e8SDoug Rabson 	    const gss_buffer_t input_token_buffer,
694c19800e8SDoug Rabson 	    const gss_channel_bindings_t input_chan_bindings,
695c19800e8SDoug Rabson 	    gss_name_t * src_name,
696c19800e8SDoug Rabson 	    gss_OID * mech_type,
697c19800e8SDoug Rabson 	    gss_buffer_t output_token,
698c19800e8SDoug Rabson 	    OM_uint32 * ret_flags,
699c19800e8SDoug Rabson 	    OM_uint32 * time_rec,
700c19800e8SDoug Rabson 	    gss_cred_id_t *delegated_cred_handle
701c19800e8SDoug Rabson 	   )
702c19800e8SDoug Rabson {
703c19800e8SDoug Rabson     OM_uint32 ret, ret2, minor;
704c19800e8SDoug Rabson     NegotiationToken nt;
705c19800e8SDoug Rabson     size_t nt_len;
706c19800e8SDoug Rabson     NegTokenResp *na;
707c19800e8SDoug Rabson     unsigned int negResult = accept_incomplete;
708c19800e8SDoug Rabson     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
709c19800e8SDoug Rabson     gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
710c19800e8SDoug Rabson     gss_buffer_desc mech_buf;
711c19800e8SDoug Rabson     gssspnego_ctx ctx;
712c19800e8SDoug Rabson 
713c19800e8SDoug Rabson     mech_buf.value = NULL;
714c19800e8SDoug Rabson 
715c19800e8SDoug Rabson     ctx = (gssspnego_ctx)*context_handle;
716c19800e8SDoug Rabson 
717c19800e8SDoug Rabson     /*
718c19800e8SDoug Rabson      * The GSS-API encapsulation is only present on the initial
719c19800e8SDoug Rabson      * context token (negTokenInit).
720c19800e8SDoug Rabson      */
721c19800e8SDoug Rabson 
722c19800e8SDoug Rabson     ret = decode_NegotiationToken(input_token_buffer->value,
723c19800e8SDoug Rabson 				  input_token_buffer->length,
724c19800e8SDoug Rabson 				  &nt, &nt_len);
725c19800e8SDoug Rabson     if (ret) {
726c19800e8SDoug Rabson 	*minor_status = ret;
727c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
728c19800e8SDoug Rabson     }
729c19800e8SDoug Rabson     if (nt.element != choice_NegotiationToken_negTokenResp) {
730c19800e8SDoug Rabson 	*minor_status = 0;
731c19800e8SDoug Rabson 	return GSS_S_DEFECTIVE_TOKEN;
732c19800e8SDoug Rabson     }
733c19800e8SDoug Rabson     na = &nt.u.negTokenResp;
734c19800e8SDoug Rabson 
735c19800e8SDoug Rabson     if (na->negResult != NULL) {
736c19800e8SDoug Rabson 	negResult = *(na->negResult);
737c19800e8SDoug Rabson     }
738c19800e8SDoug Rabson 
739c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
740c19800e8SDoug Rabson 
741c19800e8SDoug Rabson     {
742c19800e8SDoug Rabson 	gss_buffer_desc ibuf, obuf;
743c19800e8SDoug Rabson 	int require_mic, get_mic = 0;
744c19800e8SDoug Rabson 	int require_response;
745c19800e8SDoug Rabson 	heim_octet_string *mic;
746c19800e8SDoug Rabson 
747c19800e8SDoug Rabson 	if (na->responseToken != NULL) {
748c19800e8SDoug Rabson 	    ibuf.length = na->responseToken->length;
749c19800e8SDoug Rabson 	    ibuf.value = na->responseToken->data;
750c19800e8SDoug Rabson 	    mech_input_token = &ibuf;
751c19800e8SDoug Rabson 	} else {
752c19800e8SDoug Rabson 	    ibuf.value = NULL;
753c19800e8SDoug Rabson 	    ibuf.length = 0;
754c19800e8SDoug Rabson 	}
755c19800e8SDoug Rabson 
756c19800e8SDoug Rabson 	if (mech_input_token != GSS_C_NO_BUFFER) {
757c19800e8SDoug Rabson 
758c19800e8SDoug Rabson 	    if (ctx->mech_src_name != GSS_C_NO_NAME)
759c19800e8SDoug Rabson 		gss_release_name(&minor, &ctx->mech_src_name);
760c19800e8SDoug Rabson 
761c19800e8SDoug Rabson 	    ret = gss_accept_sec_context(&minor,
762c19800e8SDoug Rabson 					 &ctx->negotiated_ctx_id,
763ae771770SStanislav Sedov 					 acceptor_cred_handle,
764c19800e8SDoug Rabson 					 mech_input_token,
765c19800e8SDoug Rabson 					 input_chan_bindings,
766c19800e8SDoug Rabson 					 &ctx->mech_src_name,
767c19800e8SDoug Rabson 					 &ctx->negotiated_mech_type,
768c19800e8SDoug Rabson 					 &obuf,
769c19800e8SDoug Rabson 					 &ctx->mech_flags,
770c19800e8SDoug Rabson 					 &ctx->mech_time_rec,
771ae771770SStanislav Sedov 					 delegated_cred_handle);
772ae771770SStanislav Sedov 
773c19800e8SDoug Rabson 	    if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
774c19800e8SDoug Rabson 		mech_output_token = &obuf;
775c19800e8SDoug Rabson 	    }
776c19800e8SDoug Rabson 	    if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
777c19800e8SDoug Rabson 		free_NegotiationToken(&nt);
778ae771770SStanislav Sedov 		gss_mg_collect_error(ctx->negotiated_mech_type, ret, minor);
779c19800e8SDoug Rabson 		send_reject (minor_status, output_token);
780c19800e8SDoug Rabson 		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
781c19800e8SDoug Rabson 		return ret;
782c19800e8SDoug Rabson 	    }
783c19800e8SDoug Rabson 	    if (ret == GSS_S_COMPLETE)
784c19800e8SDoug Rabson 		ctx->open = 1;
785c19800e8SDoug Rabson 	} else
786c19800e8SDoug Rabson 	    ret = GSS_S_COMPLETE;
787c19800e8SDoug Rabson 
788c19800e8SDoug Rabson 	ret2 = _gss_spnego_require_mechlist_mic(minor_status,
789c19800e8SDoug Rabson 						ctx,
790c19800e8SDoug Rabson 						&require_mic);
791c19800e8SDoug Rabson 	if (ret2)
792c19800e8SDoug Rabson 	    goto out;
793c19800e8SDoug Rabson 
794c19800e8SDoug Rabson 	ctx->require_mic = require_mic;
795c19800e8SDoug Rabson 
796c19800e8SDoug Rabson 	mic = na->mechListMIC;
797c19800e8SDoug Rabson 	if (mic != NULL)
798c19800e8SDoug Rabson 	    require_mic = 1;
799c19800e8SDoug Rabson 
800c19800e8SDoug Rabson 	if (ret == GSS_S_COMPLETE)
801c19800e8SDoug Rabson 	    ret = acceptor_complete(minor_status,
802c19800e8SDoug Rabson 				    ctx,
803c19800e8SDoug Rabson 				    &get_mic,
804c19800e8SDoug Rabson 				    &mech_buf,
805c19800e8SDoug Rabson 				    mech_input_token,
806c19800e8SDoug Rabson 				    mech_output_token,
807c19800e8SDoug Rabson 				    na->mechListMIC,
808c19800e8SDoug Rabson 				    output_token);
809c19800e8SDoug Rabson 
810c19800e8SDoug Rabson 	if (ctx->mech_flags & GSS_C_DCE_STYLE)
811c19800e8SDoug Rabson 	    require_response = (negResult != accept_completed);
812c19800e8SDoug Rabson 	else
813c19800e8SDoug Rabson 	    require_response = 0;
814c19800e8SDoug Rabson 
815c19800e8SDoug Rabson 	/*
816c19800e8SDoug Rabson 	 * Check whether we need to send a result: there should be only
817c19800e8SDoug Rabson 	 * one accept_completed response sent in the entire negotiation
818c19800e8SDoug Rabson 	 */
819c19800e8SDoug Rabson 	if ((mech_output_token != GSS_C_NO_BUFFER &&
820c19800e8SDoug Rabson 	     mech_output_token->length != 0)
821c19800e8SDoug Rabson 	    || (ctx->open && negResult == accept_incomplete)
822c19800e8SDoug Rabson 	    || require_response
823c19800e8SDoug Rabson 	    || get_mic) {
824c19800e8SDoug Rabson 	    ret2 = send_accept (minor_status,
825c19800e8SDoug Rabson 				ctx,
826c19800e8SDoug Rabson 				mech_output_token,
827c19800e8SDoug Rabson 				0,
828c19800e8SDoug Rabson 				get_mic ? &mech_buf : NULL,
829c19800e8SDoug Rabson 				output_token);
830c19800e8SDoug Rabson 	    if (ret2)
831c19800e8SDoug Rabson 		goto out;
832c19800e8SDoug Rabson 	}
833c19800e8SDoug Rabson 
834c19800e8SDoug Rabson      out:
835c19800e8SDoug Rabson 	if (ret2 != GSS_S_COMPLETE)
836c19800e8SDoug Rabson 	    ret = ret2;
837c19800e8SDoug Rabson 	if (mech_output_token != NULL)
838c19800e8SDoug Rabson 	    gss_release_buffer(&minor, mech_output_token);
839c19800e8SDoug Rabson 	if (mech_buf.value != NULL)
840c19800e8SDoug Rabson 	    free(mech_buf.value);
841c19800e8SDoug Rabson 	free_NegotiationToken(&nt);
842c19800e8SDoug Rabson     }
843c19800e8SDoug Rabson 
844c19800e8SDoug Rabson     if (ret == GSS_S_COMPLETE) {
845c19800e8SDoug Rabson 	if (src_name != NULL && ctx->mech_src_name != NULL) {
846c19800e8SDoug Rabson 	    spnego_name name;
847c19800e8SDoug Rabson 
848c19800e8SDoug Rabson 	    name = calloc(1, sizeof(*name));
849c19800e8SDoug Rabson 	    if (name) {
850c19800e8SDoug Rabson 		name->mech = ctx->mech_src_name;
851c19800e8SDoug Rabson 		ctx->mech_src_name = NULL;
852c19800e8SDoug Rabson 		*src_name = (gss_name_t)name;
853c19800e8SDoug Rabson 	    }
854c19800e8SDoug Rabson 	}
855c19800e8SDoug Rabson     }
856c19800e8SDoug Rabson 
857c19800e8SDoug Rabson     if (mech_type != NULL)
858c19800e8SDoug Rabson 	*mech_type = ctx->negotiated_mech_type;
859c19800e8SDoug Rabson     if (ret_flags != NULL)
860c19800e8SDoug Rabson 	*ret_flags = ctx->mech_flags;
861c19800e8SDoug Rabson     if (time_rec != NULL)
862c19800e8SDoug Rabson 	*time_rec = ctx->mech_time_rec;
863c19800e8SDoug Rabson 
864c19800e8SDoug Rabson     if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
865c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
866c19800e8SDoug Rabson  	return ret;
867c19800e8SDoug Rabson     }
868c19800e8SDoug Rabson 
869c19800e8SDoug Rabson     _gss_spnego_internal_delete_sec_context(&minor, context_handle,
870c19800e8SDoug Rabson 				   GSS_C_NO_BUFFER);
871c19800e8SDoug Rabson 
872c19800e8SDoug Rabson     return ret;
873c19800e8SDoug Rabson }
874c19800e8SDoug Rabson 
875ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_spnego_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)876c19800e8SDoug Rabson _gss_spnego_accept_sec_context
877c19800e8SDoug Rabson 	   (OM_uint32 * minor_status,
878c19800e8SDoug Rabson 	    gss_ctx_id_t * context_handle,
879c19800e8SDoug Rabson 	    const gss_cred_id_t acceptor_cred_handle,
880c19800e8SDoug Rabson 	    const gss_buffer_t input_token_buffer,
881c19800e8SDoug Rabson 	    const gss_channel_bindings_t input_chan_bindings,
882c19800e8SDoug Rabson 	    gss_name_t * src_name,
883c19800e8SDoug Rabson 	    gss_OID * mech_type,
884c19800e8SDoug Rabson 	    gss_buffer_t output_token,
885c19800e8SDoug Rabson 	    OM_uint32 * ret_flags,
886c19800e8SDoug Rabson 	    OM_uint32 * time_rec,
887c19800e8SDoug Rabson 	    gss_cred_id_t *delegated_cred_handle
888c19800e8SDoug Rabson 	   )
889c19800e8SDoug Rabson {
890c19800e8SDoug Rabson     _gss_accept_sec_context_t *func;
891c19800e8SDoug Rabson 
892c19800e8SDoug Rabson     *minor_status = 0;
893c19800e8SDoug Rabson 
894c19800e8SDoug Rabson     output_token->length = 0;
895c19800e8SDoug Rabson     output_token->value  = NULL;
896c19800e8SDoug Rabson 
897c19800e8SDoug Rabson     if (src_name != NULL)
898c19800e8SDoug Rabson 	*src_name = GSS_C_NO_NAME;
899c19800e8SDoug Rabson     if (mech_type != NULL)
900c19800e8SDoug Rabson 	*mech_type = GSS_C_NO_OID;
901c19800e8SDoug Rabson     if (ret_flags != NULL)
902c19800e8SDoug Rabson 	*ret_flags = 0;
903c19800e8SDoug Rabson     if (time_rec != NULL)
904c19800e8SDoug Rabson 	*time_rec = 0;
905c19800e8SDoug Rabson     if (delegated_cred_handle != NULL)
906c19800e8SDoug Rabson 	*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
907c19800e8SDoug Rabson 
908c19800e8SDoug Rabson 
909c19800e8SDoug Rabson     if (*context_handle == GSS_C_NO_CONTEXT)
910c19800e8SDoug Rabson 	func = acceptor_start;
911c19800e8SDoug Rabson     else
912c19800e8SDoug Rabson 	func = acceptor_continue;
913c19800e8SDoug Rabson 
914c19800e8SDoug Rabson 
915c19800e8SDoug Rabson     return (*func)(minor_status, context_handle, acceptor_cred_handle,
916c19800e8SDoug Rabson 		   input_token_buffer, input_chan_bindings,
917c19800e8SDoug Rabson 		   src_name, mech_type, output_token, ret_flags,
918c19800e8SDoug Rabson 		   time_rec, delegated_cred_handle);
919c19800e8SDoug Rabson }
920