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