Line data Source code
1 : /*
2 : * Copyright (c) 2004, PADL Software Pty Ltd.
3 : * All rights reserved.
4 : *
5 : * Redistribution and use in source and binary forms, with or without
6 : * modification, are permitted provided that the following conditions
7 : * are met:
8 : *
9 : * 1. Redistributions of source code must retain the above copyright
10 : * notice, this list of conditions and the following disclaimer.
11 : *
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * 3. Neither the name of PADL Software nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : #include "spnego_locl.h"
34 :
35 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_process_context_token
36 : (OM_uint32 *minor_status,
37 : gss_const_ctx_id_t context_handle,
38 : const gss_buffer_t token_buffer
39 : )
40 : {
41 0 : gss_ctx_id_t context;
42 0 : gssspnego_ctx ctx;
43 0 : OM_uint32 ret;
44 :
45 0 : if (context_handle == GSS_C_NO_CONTEXT)
46 0 : return GSS_S_NO_CONTEXT;
47 :
48 0 : context = (gss_ctx_id_t)context_handle;
49 0 : ctx = (gssspnego_ctx)context_handle;
50 :
51 0 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
52 :
53 0 : ret = gss_process_context_token(minor_status,
54 0 : ctx->negotiated_ctx_id,
55 : token_buffer);
56 0 : if (ret != GSS_S_COMPLETE) {
57 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
58 0 : return ret;
59 : }
60 :
61 0 : ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
62 :
63 0 : return _gss_spnego_internal_delete_sec_context(minor_status,
64 : &context,
65 : GSS_C_NO_BUFFER);
66 : }
67 :
68 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_delete_sec_context
69 : (OM_uint32 *minor_status,
70 : gss_ctx_id_t *context_handle,
71 : gss_buffer_t output_token
72 : )
73 : {
74 0 : gssspnego_ctx ctx;
75 :
76 0 : if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
77 0 : return GSS_S_NO_CONTEXT;
78 :
79 0 : ctx = (gssspnego_ctx)*context_handle;
80 :
81 0 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
82 :
83 0 : return _gss_spnego_internal_delete_sec_context(minor_status,
84 : context_handle,
85 : output_token);
86 : }
87 :
88 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_context_time
89 : (OM_uint32 *minor_status,
90 : gss_const_ctx_id_t context_handle,
91 : OM_uint32 *time_rec
92 : )
93 : {
94 0 : gssspnego_ctx ctx;
95 0 : *minor_status = 0;
96 :
97 0 : if (context_handle == GSS_C_NO_CONTEXT) {
98 0 : return GSS_S_NO_CONTEXT;
99 : }
100 :
101 0 : ctx = (gssspnego_ctx)context_handle;
102 :
103 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
104 0 : return GSS_S_NO_CONTEXT;
105 : }
106 :
107 0 : return gss_context_time(minor_status,
108 0 : ctx->negotiated_ctx_id,
109 : time_rec);
110 : }
111 :
112 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_get_mic
113 : (OM_uint32 *minor_status,
114 : gss_const_ctx_id_t context_handle,
115 : gss_qop_t qop_req,
116 : const gss_buffer_t message_buffer,
117 : gss_buffer_t message_token
118 : )
119 : {
120 0 : gssspnego_ctx ctx;
121 :
122 0 : *minor_status = 0;
123 :
124 0 : if (context_handle == GSS_C_NO_CONTEXT) {
125 0 : return GSS_S_NO_CONTEXT;
126 : }
127 :
128 0 : ctx = (gssspnego_ctx)context_handle;
129 :
130 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
131 0 : return GSS_S_NO_CONTEXT;
132 : }
133 :
134 0 : return gss_get_mic(minor_status, ctx->negotiated_ctx_id,
135 : qop_req, message_buffer, message_token);
136 : }
137 :
138 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_verify_mic
139 : (OM_uint32 * minor_status,
140 : gss_const_ctx_id_t context_handle,
141 : const gss_buffer_t message_buffer,
142 : const gss_buffer_t token_buffer,
143 : gss_qop_t * qop_state
144 : )
145 : {
146 0 : gssspnego_ctx ctx;
147 :
148 0 : *minor_status = 0;
149 :
150 0 : if (context_handle == GSS_C_NO_CONTEXT) {
151 0 : return GSS_S_NO_CONTEXT;
152 : }
153 :
154 0 : ctx = (gssspnego_ctx)context_handle;
155 :
156 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
157 0 : return GSS_S_NO_CONTEXT;
158 : }
159 :
160 0 : return gss_verify_mic(minor_status,
161 0 : ctx->negotiated_ctx_id,
162 : message_buffer,
163 : token_buffer,
164 : qop_state);
165 : }
166 :
167 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap
168 : (OM_uint32 * minor_status,
169 : gss_const_ctx_id_t context_handle,
170 : int conf_req_flag,
171 : gss_qop_t qop_req,
172 : const gss_buffer_t input_message_buffer,
173 : int * conf_state,
174 : gss_buffer_t output_message_buffer
175 : )
176 : {
177 0 : gssspnego_ctx ctx;
178 :
179 0 : *minor_status = 0;
180 :
181 0 : if (context_handle == GSS_C_NO_CONTEXT) {
182 0 : return GSS_S_NO_CONTEXT;
183 : }
184 :
185 0 : ctx = (gssspnego_ctx)context_handle;
186 :
187 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
188 0 : return GSS_S_NO_CONTEXT;
189 : }
190 :
191 0 : return gss_wrap(minor_status,
192 0 : ctx->negotiated_ctx_id,
193 : conf_req_flag,
194 : qop_req,
195 : input_message_buffer,
196 : conf_state,
197 : output_message_buffer);
198 : }
199 :
200 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_unwrap
201 : (OM_uint32 * minor_status,
202 : gss_const_ctx_id_t context_handle,
203 : const gss_buffer_t input_message_buffer,
204 : gss_buffer_t output_message_buffer,
205 : int * conf_state,
206 : gss_qop_t * qop_state
207 : )
208 : {
209 0 : gssspnego_ctx ctx;
210 :
211 0 : *minor_status = 0;
212 :
213 0 : if (context_handle == GSS_C_NO_CONTEXT) {
214 0 : return GSS_S_NO_CONTEXT;
215 : }
216 :
217 0 : ctx = (gssspnego_ctx)context_handle;
218 :
219 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
220 0 : return GSS_S_NO_CONTEXT;
221 : }
222 :
223 0 : return gss_unwrap(minor_status,
224 0 : ctx->negotiated_ctx_id,
225 : input_message_buffer,
226 : output_message_buffer,
227 : conf_state,
228 : qop_state);
229 : }
230 :
231 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_context (
232 : OM_uint32 * minor_status,
233 : gss_const_ctx_id_t context_handle,
234 : gss_name_t * src_name,
235 : gss_name_t * targ_name,
236 : OM_uint32 * lifetime_rec,
237 : gss_OID * mech_type,
238 : OM_uint32 * ctx_flags,
239 : int * locally_initiated,
240 : int * open_context
241 : )
242 : {
243 0 : gssspnego_ctx ctx;
244 0 : OM_uint32 maj_stat;
245 :
246 0 : *minor_status = 0;
247 :
248 0 : if (context_handle == GSS_C_NO_CONTEXT)
249 0 : return GSS_S_NO_CONTEXT;
250 :
251 0 : ctx = (gssspnego_ctx)context_handle;
252 :
253 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
254 0 : return GSS_S_NO_CONTEXT;
255 :
256 0 : maj_stat = gss_inquire_context(minor_status,
257 0 : ctx->negotiated_ctx_id,
258 : src_name,
259 : targ_name,
260 : lifetime_rec,
261 : mech_type,
262 : ctx_flags,
263 : locally_initiated,
264 : open_context);
265 :
266 0 : if (open_context)
267 0 : *open_context = gssspnego_ctx_complete_p(ctx);
268 :
269 0 : return maj_stat;
270 : }
271 :
272 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap_size_limit (
273 : OM_uint32 * minor_status,
274 : gss_const_ctx_id_t context_handle,
275 : int conf_req_flag,
276 : gss_qop_t qop_req,
277 : OM_uint32 req_output_size,
278 : OM_uint32 * max_input_size
279 : )
280 : {
281 0 : gssspnego_ctx ctx;
282 :
283 0 : *minor_status = 0;
284 :
285 0 : if (context_handle == GSS_C_NO_CONTEXT) {
286 0 : return GSS_S_NO_CONTEXT;
287 : }
288 :
289 0 : ctx = (gssspnego_ctx)context_handle;
290 :
291 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
292 0 : return GSS_S_NO_CONTEXT;
293 : }
294 :
295 0 : return gss_wrap_size_limit(minor_status,
296 0 : ctx->negotiated_ctx_id,
297 : conf_req_flag,
298 : qop_req,
299 : req_output_size,
300 : max_input_size);
301 : }
302 :
303 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_export_sec_context (
304 : OM_uint32 * minor_status,
305 : gss_ctx_id_t * context_handle,
306 : gss_buffer_t interprocess_token
307 : )
308 : {
309 0 : gssspnego_ctx ctx;
310 0 : OM_uint32 major_status;
311 :
312 0 : *minor_status = 0;
313 :
314 0 : if (context_handle == NULL)
315 0 : return GSS_S_NO_CONTEXT;
316 :
317 0 : ctx = (gssspnego_ctx)*context_handle;
318 :
319 0 : if (ctx == NULL)
320 0 : return GSS_S_NO_CONTEXT;
321 :
322 0 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
323 :
324 : /*
325 : * Partial context export is only supported on the acceptor side, as we
326 : * cannot represent the initiator function pointer state in an exported
327 : * token, and also because it is mostly useful for acceptors which need
328 : * to manage multiple initiator states.
329 : */
330 0 : if (ctx->flags.local && !gssspnego_ctx_complete_p(ctx)) {
331 0 : major_status = GSS_S_NO_CONTEXT;
332 0 : goto out;
333 : }
334 :
335 0 : major_status = _gss_spnego_export_sec_context_internal(minor_status,
336 : ctx,
337 : interprocess_token);
338 :
339 0 : out:
340 0 : if (major_status == GSS_S_COMPLETE)
341 0 : major_status = _gss_spnego_internal_delete_sec_context(minor_status,
342 : context_handle,
343 : GSS_C_NO_BUFFER);
344 : else
345 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
346 :
347 0 : return major_status;
348 : }
349 :
350 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_import_sec_context (
351 : OM_uint32 * minor_status,
352 : const gss_buffer_t interprocess_token,
353 : gss_ctx_id_t *context_handle
354 : )
355 : {
356 0 : return _gss_spnego_import_sec_context_internal(minor_status,
357 : interprocess_token,
358 : (gssspnego_ctx *)context_handle);
359 : }
360 :
361 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_names_for_mech (
362 : OM_uint32 * minor_status,
363 : const gss_OID mechanism,
364 : gss_OID_set * name_types
365 : )
366 : {
367 0 : gss_OID_set mechs, names, n;
368 0 : OM_uint32 ret, junk;
369 0 : size_t i, j;
370 :
371 0 : *name_types = NULL;
372 :
373 0 : ret = _gss_spnego_indicate_mechs(minor_status, &mechs);
374 0 : if (ret != GSS_S_COMPLETE)
375 0 : return ret;
376 :
377 0 : ret = gss_create_empty_oid_set(minor_status, &names);
378 0 : if (ret != GSS_S_COMPLETE)
379 0 : goto out;
380 :
381 0 : for (i = 0; i < mechs->count; i++) {
382 0 : ret = gss_inquire_names_for_mech(minor_status,
383 0 : &mechs->elements[i],
384 : &n);
385 0 : if (ret)
386 0 : continue;
387 :
388 0 : for (j = 0; j < n->count; j++)
389 0 : gss_add_oid_set_member(minor_status,
390 0 : &n->elements[j],
391 : &names);
392 0 : gss_release_oid_set(&junk, &n);
393 : }
394 :
395 0 : ret = GSS_S_COMPLETE;
396 0 : *name_types = names;
397 0 : out:
398 :
399 0 : gss_release_oid_set(&junk, &mechs);
400 :
401 0 : return ret;
402 : }
403 :
404 : OM_uint32 GSSAPI_CALLCONV
405 0 : _gss_spnego_wrap_iov(OM_uint32 * minor_status,
406 : gss_ctx_id_t context_handle,
407 : int conf_req_flag,
408 : gss_qop_t qop_req,
409 : int * conf_state,
410 : gss_iov_buffer_desc *iov,
411 : int iov_count)
412 : {
413 0 : gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
414 :
415 0 : *minor_status = 0;
416 :
417 0 : if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
418 0 : return GSS_S_NO_CONTEXT;
419 :
420 0 : return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id,
421 : conf_req_flag, qop_req, conf_state,
422 : iov, iov_count);
423 : }
424 :
425 : OM_uint32 GSSAPI_CALLCONV
426 0 : _gss_spnego_unwrap_iov(OM_uint32 *minor_status,
427 : gss_ctx_id_t context_handle,
428 : int *conf_state,
429 : gss_qop_t *qop_state,
430 : gss_iov_buffer_desc *iov,
431 : int iov_count)
432 : {
433 0 : gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
434 :
435 0 : *minor_status = 0;
436 :
437 0 : if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
438 0 : return GSS_S_NO_CONTEXT;
439 :
440 0 : return gss_unwrap_iov(minor_status,
441 : ctx->negotiated_ctx_id,
442 : conf_state, qop_state,
443 : iov, iov_count);
444 : }
445 :
446 : OM_uint32 GSSAPI_CALLCONV
447 0 : _gss_spnego_wrap_iov_length(OM_uint32 * minor_status,
448 : gss_ctx_id_t context_handle,
449 : int conf_req_flag,
450 : gss_qop_t qop_req,
451 : int *conf_state,
452 : gss_iov_buffer_desc *iov,
453 : int iov_count)
454 : {
455 0 : gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
456 :
457 0 : *minor_status = 0;
458 :
459 0 : if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
460 0 : return GSS_S_NO_CONTEXT;
461 :
462 0 : return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id,
463 : conf_req_flag, qop_req, conf_state,
464 : iov, iov_count);
465 : }
466 :
467 : #if 0
468 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token
469 : (OM_uint32 * minor_status,
470 : gss_const_ctx_id_t context_handle,
471 : gss_buffer_t input_message_buffer)
472 : {
473 : gssspnego_ctx ctx;
474 :
475 : *minor_status = 0;
476 :
477 : if (context_handle == GSS_C_NO_CONTEXT) {
478 : return GSS_S_NO_CONTEXT;
479 : }
480 :
481 : ctx = (gssspnego_ctx)context_handle;
482 :
483 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
484 : return GSS_S_NO_CONTEXT;
485 : }
486 :
487 : return gss_complete_auth_token(minor_status,
488 : ctx->negotiated_ctx_id,
489 : input_message_buffer);
490 : }
491 : #endif
492 :
493 0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid
494 : (OM_uint32 * minor_status,
495 : gss_const_ctx_id_t context_handle,
496 : const gss_OID desired_object,
497 : gss_buffer_set_t *data_set)
498 : {
499 0 : gssspnego_ctx ctx;
500 :
501 0 : *minor_status = 0;
502 :
503 0 : if (context_handle == GSS_C_NO_CONTEXT) {
504 0 : return GSS_S_NO_CONTEXT;
505 : }
506 :
507 0 : ctx = (gssspnego_ctx)context_handle;
508 :
509 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
510 0 : return GSS_S_NO_CONTEXT;
511 : }
512 :
513 0 : return gss_inquire_sec_context_by_oid(minor_status,
514 0 : ctx->negotiated_ctx_id,
515 : desired_object,
516 : data_set);
517 : }
518 :
519 292289 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_set_sec_context_option
520 : (OM_uint32 * minor_status,
521 : gss_ctx_id_t * context_handle,
522 : const gss_OID desired_object,
523 : const gss_buffer_t value)
524 : {
525 10214 : gssspnego_ctx ctx;
526 :
527 292289 : *minor_status = 0;
528 :
529 : /*
530 : * Return GSS_S_UNAVAILABLE with a NULL context handle as at
531 : * present no context options can be set globally on SPNEGO
532 : * itself. Global mechanism context options are set directly
533 : * on the mechanism; per-context context options are set below
534 : * if ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT.
535 : */
536 292289 : if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
537 282075 : return GSS_S_UNAVAILABLE;
538 :
539 0 : ctx = (gssspnego_ctx)*context_handle;
540 :
541 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
542 0 : return GSS_S_NO_CONTEXT;
543 : }
544 :
545 0 : return gss_set_sec_context_option(minor_status,
546 : &ctx->negotiated_ctx_id,
547 : desired_object,
548 : value);
549 : }
550 :
551 :
552 : OM_uint32 GSSAPI_CALLCONV
553 0 : _gss_spnego_pseudo_random(OM_uint32 *minor_status,
554 : gss_ctx_id_t context_handle,
555 : int prf_key,
556 : const gss_buffer_t prf_in,
557 : ssize_t desired_output_len,
558 : gss_buffer_t prf_out)
559 : {
560 0 : gssspnego_ctx ctx;
561 :
562 0 : *minor_status = 0;
563 :
564 0 : if (context_handle == GSS_C_NO_CONTEXT)
565 0 : return GSS_S_NO_CONTEXT;
566 :
567 0 : ctx = (gssspnego_ctx)context_handle;
568 :
569 0 : if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
570 0 : return GSS_S_NO_CONTEXT;
571 :
572 0 : return gss_pseudo_random(minor_status,
573 : ctx->negotiated_ctx_id,
574 : prf_key,
575 : prf_in,
576 : desired_output_len,
577 : prf_out);
578 : }
|