s4:torture: Adapt KDC canon test to Heimdal upstream changes
[metze/samba/wip.git] / source4 / heimdal / lib / gssapi / spnego / context_stubs.c
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 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     gss_ctx_id_t context;
42     gssspnego_ctx ctx;
43     OM_uint32 ret;
44
45     if (context_handle == GSS_C_NO_CONTEXT)
46         return GSS_S_NO_CONTEXT;
47
48     context = (gss_ctx_id_t)context_handle;
49     ctx = (gssspnego_ctx)context_handle;
50
51     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
52
53     ret = gss_process_context_token(minor_status,
54                                     ctx->negotiated_ctx_id,
55                                     token_buffer);
56     if (ret != GSS_S_COMPLETE) {
57         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
58         return ret;
59     }
60
61     ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
62
63     return _gss_spnego_internal_delete_sec_context(minor_status,
64                                            &context,
65                                            GSS_C_NO_BUFFER);
66 }
67
68 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     gssspnego_ctx ctx;
75
76     if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
77         return GSS_S_NO_CONTEXT;
78
79     ctx = (gssspnego_ctx)*context_handle;
80
81     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
82
83     return _gss_spnego_internal_delete_sec_context(minor_status,
84                                                    context_handle,
85                                                    output_token);
86 }
87
88 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     gssspnego_ctx ctx;
95     *minor_status = 0;
96
97     if (context_handle == GSS_C_NO_CONTEXT) {
98         return GSS_S_NO_CONTEXT;
99     }
100
101     ctx = (gssspnego_ctx)context_handle;
102
103     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
104         return GSS_S_NO_CONTEXT;
105     }
106
107     return gss_context_time(minor_status,
108                             ctx->negotiated_ctx_id,
109                             time_rec);
110 }
111
112 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     gssspnego_ctx ctx;
121
122     *minor_status = 0;
123
124     if (context_handle == GSS_C_NO_CONTEXT) {
125         return GSS_S_NO_CONTEXT;
126     }
127
128     ctx = (gssspnego_ctx)context_handle;
129
130     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
131         return GSS_S_NO_CONTEXT;
132     }
133
134     return gss_get_mic(minor_status, ctx->negotiated_ctx_id,
135                        qop_req, message_buffer, message_token);
136 }
137
138 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     gssspnego_ctx ctx;
147
148     *minor_status = 0;
149
150     if (context_handle == GSS_C_NO_CONTEXT) {
151         return GSS_S_NO_CONTEXT;
152     }
153
154     ctx = (gssspnego_ctx)context_handle;
155
156     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
157         return GSS_S_NO_CONTEXT;
158     }
159
160     return gss_verify_mic(minor_status,
161                           ctx->negotiated_ctx_id,
162                           message_buffer,
163                           token_buffer,
164                           qop_state);
165 }
166
167 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     gssspnego_ctx ctx;
178
179     *minor_status = 0;
180
181     if (context_handle == GSS_C_NO_CONTEXT) {
182         return GSS_S_NO_CONTEXT;
183     }
184
185     ctx = (gssspnego_ctx)context_handle;
186
187     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
188         return GSS_S_NO_CONTEXT;
189     }
190
191     return gss_wrap(minor_status,
192                     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 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     gssspnego_ctx ctx;
210
211     *minor_status = 0;
212
213     if (context_handle == GSS_C_NO_CONTEXT) {
214         return GSS_S_NO_CONTEXT;
215     }
216
217     ctx = (gssspnego_ctx)context_handle;
218
219     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
220         return GSS_S_NO_CONTEXT;
221     }
222
223     return gss_unwrap(minor_status,
224                       ctx->negotiated_ctx_id,
225                       input_message_buffer,
226                       output_message_buffer,
227                       conf_state,
228                       qop_state);
229 }
230
231 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     gssspnego_ctx ctx;
244     OM_uint32 maj_stat;
245
246     *minor_status = 0;
247
248     if (context_handle == GSS_C_NO_CONTEXT)
249         return GSS_S_NO_CONTEXT;
250
251     ctx = (gssspnego_ctx)context_handle;
252
253     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
254         return GSS_S_NO_CONTEXT;
255
256     maj_stat = gss_inquire_context(minor_status,
257                                    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     if (open_context)
267         *open_context = gssspnego_ctx_complete_p(ctx);
268
269     return maj_stat;
270 }
271
272 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     gssspnego_ctx ctx;
282
283     *minor_status = 0;
284
285     if (context_handle == GSS_C_NO_CONTEXT) {
286         return GSS_S_NO_CONTEXT;
287     }
288
289     ctx = (gssspnego_ctx)context_handle;
290
291     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
292         return GSS_S_NO_CONTEXT;
293     }
294
295     return gss_wrap_size_limit(minor_status,
296                                ctx->negotiated_ctx_id,
297                                conf_req_flag,
298                                qop_req,
299                                req_output_size,
300                                max_input_size);
301 }
302
303 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     gssspnego_ctx ctx;
310     OM_uint32 major_status;
311
312     *minor_status = 0;
313
314     if (context_handle == NULL)
315         return GSS_S_NO_CONTEXT;
316
317     ctx = (gssspnego_ctx)*context_handle;
318
319     if (ctx == NULL)
320         return GSS_S_NO_CONTEXT;
321
322     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     if (ctx->flags.local && !gssspnego_ctx_complete_p(ctx)) {
331         major_status = GSS_S_NO_CONTEXT;
332         goto out;
333     }
334
335     major_status = _gss_spnego_export_sec_context_internal(minor_status,
336                                                            ctx,
337                                                            interprocess_token);
338
339 out:
340     if (major_status == GSS_S_COMPLETE)
341         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     return major_status;
348 }
349
350 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     return _gss_spnego_import_sec_context_internal(minor_status,
357                                                    interprocess_token,
358                                                    (gssspnego_ctx *)context_handle);
359 }
360
361 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     gss_OID_set mechs, names, n;
368     OM_uint32 ret, junk;
369     size_t i, j;
370
371     *name_types = NULL;
372
373     ret = _gss_spnego_indicate_mechs(minor_status, &mechs);
374     if (ret != GSS_S_COMPLETE)
375         return ret;
376
377     ret = gss_create_empty_oid_set(minor_status, &names);
378     if (ret != GSS_S_COMPLETE)
379         goto out;
380
381     for (i = 0; i < mechs->count; i++) {
382         ret = gss_inquire_names_for_mech(minor_status,
383                                          &mechs->elements[i],
384                                          &n);
385         if (ret)
386             continue;
387
388         for (j = 0; j < n->count; j++)
389             gss_add_oid_set_member(minor_status,
390                                    &n->elements[j],
391                                    &names);
392         gss_release_oid_set(&junk, &n);
393     }
394
395     ret = GSS_S_COMPLETE;
396     *name_types = names;
397 out:
398
399     gss_release_oid_set(&junk, &mechs);
400
401     return ret;
402 }
403
404 OM_uint32 GSSAPI_CALLCONV
405 _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     gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
414
415     *minor_status = 0;
416
417     if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
418         return GSS_S_NO_CONTEXT;
419
420     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 _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     gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
434
435     *minor_status = 0;
436
437     if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
438         return GSS_S_NO_CONTEXT;
439
440     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 _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     gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
456
457     *minor_status = 0;
458
459     if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
460         return GSS_S_NO_CONTEXT;
461
462     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 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     gssspnego_ctx ctx;
500
501     *minor_status = 0;
502
503     if (context_handle == GSS_C_NO_CONTEXT) {
504         return GSS_S_NO_CONTEXT;
505     }
506
507     ctx = (gssspnego_ctx)context_handle;
508
509     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
510         return GSS_S_NO_CONTEXT;
511     }
512
513     return gss_inquire_sec_context_by_oid(minor_status,
514                                           ctx->negotiated_ctx_id,
515                                           desired_object,
516                                           data_set);
517 }
518
519 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     gssspnego_ctx ctx;
526
527     *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     if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
537         return GSS_S_UNAVAILABLE;
538
539     ctx = (gssspnego_ctx)*context_handle;
540
541     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
542         return GSS_S_NO_CONTEXT;
543     }
544
545     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 _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     gssspnego_ctx ctx;
561
562     *minor_status = 0;
563
564     if (context_handle == GSS_C_NO_CONTEXT)
565         return GSS_S_NO_CONTEXT;
566
567     ctx = (gssspnego_ctx)context_handle;
568
569     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
570         return GSS_S_NO_CONTEXT;
571
572     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 }