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