s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / third_party / heimdal / lib / gssapi / mech / gss_init_sec_context.c
1 /*-
2  * Copyright (c) 2005 Doug Rabson
3  * All rights reserved.
4  *
5  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
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  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *      $FreeBSD: src/lib/libgssapi/gss_init_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
29  */
30
31 #include "mech_locl.h"
32
33 gss_cred_id_t
34 _gss_mg_find_mech_cred(
35     gss_const_cred_id_t cred_handle,
36     gss_const_OID mech_type)
37 {
38         struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
39         struct _gss_mechanism_cred *mc;
40
41         if (cred == NULL)
42                 return GSS_C_NO_CREDENTIAL;
43
44         HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
45                 if (gss_oid_equal(mech_type, mc->gmc_mech_oid))
46                         return mc->gmc_cred;
47         }
48         return GSS_C_NO_CREDENTIAL;
49 }
50
51 static void
52 log_init_sec_context(struct _gss_context *ctx,
53                      struct _gss_name *target,
54                      OM_uint32 req_flags,
55                      struct _gss_cred *cred,
56                      gss_OID mech_type,
57                      gss_buffer_t input_token)
58 {
59     gssapi_mech_interface m;
60
61     if (ctx)
62         m = ctx->gc_mech;
63     else
64         m = __gss_get_mechanism(mech_type);
65     if (m == NULL)
66         return;
67
68     mech_type = &m->gm_mech_oid;
69
70     _gss_mg_log(1, "gss_isc: %s %sfirst flags %08x, %s cred, %stoken",
71                 m->gm_name,
72                 (ctx == NULL) ? "" : "not ",
73                 req_flags,
74                 (cred != NULL) ? "specific" : "default",
75                 (input_token != NULL && input_token->length) ? "" : "no ");
76
77     _gss_mg_log_cred(1, cred, "gss_isc cred");
78
79     /* print target name */
80     _gss_mg_log_name(1, target, mech_type, "gss_isc: target");
81 }
82
83 /**
84  * As the initiator build a context with an acceptor.
85  *
86  * Returns in the major
87  * - GSS_S_COMPLETE - if the context if build
88  * - GSS_S_CONTINUE_NEEDED -  if the caller needs  to continue another
89  *      round of gss_i nit_sec_context
90  * - error code - any other error code
91  *
92  * @param minor_status minor status code.
93  *
94  * @param initiator_cred_handle the credential to use when building
95  *        the context, if GSS_C_NO_CREDENTIAL is passed, the default
96  *        credential for the mechanism will be used.
97  *
98  * @param context_handle a pointer to a context handle, will be
99  *        returned as long as there is not an error.
100  *
101  * @param target_name the target name of acceptor, created using
102  *        gss_import_name(). The name is can be of any name types the
103  *        mechanism supports, check supported name types with
104  *        gss_inquire_names_for_mech().
105  *
106  * @param input_mech_type mechanism type to use, if GSS_C_NO_OID is
107  *        used, Kerberos (GSS_KRB5_MECHANISM) will be tried. Other
108  *        available mechanism are listed in the @ref gssapi_mechs_intro
109  *        section.
110  *
111  * @param req_flags flags using when building the context, see @ref
112  *        gssapi_context_flags
113  *
114  * @param time_req time requested this context should be valid in
115  *        seconds, common used value is GSS_C_INDEFINITE
116  *
117  * @param input_chan_bindings Channel bindings used, if not exepected
118  *        otherwise, used GSS_C_NO_CHANNEL_BINDINGS
119  *
120  * @param input_token input token sent from the acceptor, for the
121  *        initial packet the buffer of { NULL, 0 } should be used.
122  *
123  * @param actual_mech_type the actual mech used, MUST NOT be freed
124  *        since it pointing to static memory.
125  *
126  * @param output_token if there is an output token, regardless of
127  *        complete, continue_needed, or error it should be sent to the
128  *        acceptor
129  *
130  * @param ret_flags return what flags was negotitated, caller should
131  *        check if they are accetable. For example, if
132  *        GSS_C_MUTUAL_FLAG was negotiated with the acceptor or not.
133  *
134  * @param time_rec amount of time this context is valid for
135  *
136  * @returns a gss_error code, see gss_display_status() about printing
137  *          the error code.
138  *
139  * @ingroup gssapi
140  */
141
142
143
144 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
145 gss_init_sec_context(OM_uint32 * minor_status,
146     gss_const_cred_id_t initiator_cred_handle,
147     gss_ctx_id_t * context_handle,
148     gss_const_name_t target_name,
149     const gss_OID input_mech_type,
150     OM_uint32 req_flags,
151     OM_uint32 time_req,
152     const gss_channel_bindings_t input_chan_bindings,
153     const gss_buffer_t input_token,
154     gss_OID * actual_mech_type,
155     gss_buffer_t output_token,
156     OM_uint32 * ret_flags,
157     OM_uint32 * time_rec)
158 {
159         OM_uint32 major_status;
160         gssapi_mech_interface m;
161         gss_const_name_t mn_inner = GSS_C_NO_NAME;
162         struct _gss_name *name = (struct _gss_name *) target_name;
163         struct _gss_mechanism_name *mn;
164         struct _gss_context *ctx = (struct _gss_context *) *context_handle;
165         gss_const_cred_id_t cred_handle;
166         int allocated_ctx;
167         gss_OID mech_type = input_mech_type;
168
169         *minor_status = 0;
170
171         _mg_buffer_zero(output_token);
172         if (actual_mech_type)
173             *actual_mech_type = GSS_C_NO_OID;
174         if (ret_flags)
175             *ret_flags = 0;
176         if (time_rec)
177             *time_rec = 0;
178
179         if (mech_type == GSS_C_NO_OID)
180             mech_type = GSS_KRB5_MECHANISM;
181
182         _gss_mg_check_name(target_name);
183
184         if (_gss_mg_log_level(1))
185             log_init_sec_context(ctx, name, req_flags,
186                                  (struct _gss_cred *)initiator_cred_handle,
187                                  input_mech_type, input_token);
188
189         /*
190          * If we haven't allocated a context yet, do so now and lookup
191          * the mechanism switch table. If we have one already, make
192          * sure we use the same mechanism switch as before.
193          */
194         if (!ctx) {
195                 ctx = malloc(sizeof(struct _gss_context));
196                 if (!ctx) {
197                         *minor_status = ENOMEM;
198                         return (GSS_S_FAILURE);
199                 }
200                 memset(ctx, 0, sizeof(struct _gss_context));
201                 m = ctx->gc_mech = __gss_get_mechanism(mech_type);
202                 if (!m) {
203                         free(ctx);
204                         *minor_status = 0;
205                         gss_mg_set_error_string(mech_type, GSS_S_BAD_MECH,
206                                                 *minor_status,
207                                                 "Unsupported mechanism requested");
208                         return (GSS_S_BAD_MECH);
209                 }
210                 allocated_ctx = 1;
211         } else {
212                 m = ctx->gc_mech;
213                 mech_type = &ctx->gc_mech->gm_mech_oid;
214                 allocated_ctx = 0;
215         }
216
217         /*
218          * Find the MN for this mechanism.
219          */
220         if ((m->gm_flags & GM_USE_MG_NAME)) {
221             mn_inner = target_name;
222         } else {
223             major_status = _gss_find_mn(minor_status, name, mech_type, &mn);
224             if (major_status != GSS_S_COMPLETE) {
225                     if (allocated_ctx)
226                         free(ctx);
227                     return major_status;
228             }
229             if (mn)
230                 mn_inner = mn->gmn_name;
231         }
232
233         /*
234          * If we have a cred, find the cred for this mechanism.
235          */
236         if (m->gm_flags & GM_USE_MG_CRED)
237                 cred_handle = initiator_cred_handle;
238         else
239                 cred_handle = _gss_mg_find_mech_cred(initiator_cred_handle, mech_type);
240
241         if (initiator_cred_handle != GSS_C_NO_CREDENTIAL &&
242             cred_handle == NULL) {
243             *minor_status = 0;
244             if (allocated_ctx)
245                 free(ctx);
246             gss_mg_set_error_string(mech_type, GSS_S_UNAVAILABLE,
247                                     *minor_status,
248                                     "Credential for the requested mechanism "
249                                     "not found in credential handle");
250             return GSS_S_UNAVAILABLE;
251         }
252
253         major_status = m->gm_init_sec_context(minor_status,
254             cred_handle,
255             &ctx->gc_ctx,
256             mn_inner,
257             mech_type,
258             req_flags,
259             time_req,
260             input_chan_bindings,
261             input_token,
262             actual_mech_type,
263             output_token,
264             ret_flags,
265             time_rec);
266
267         if (major_status != GSS_S_COMPLETE
268             && major_status != GSS_S_CONTINUE_NEEDED) {
269                 if (allocated_ctx)
270                         free(ctx);
271                 _mg_buffer_zero(output_token);
272                 _gss_mg_error(m, *minor_status);
273         } else {
274                 *context_handle = (gss_ctx_id_t) ctx;
275         }
276
277         _gss_mg_log(1, "gss_isc: %s maj_stat: %d/%d",
278                     m->gm_name, (int)major_status, (int)*minor_status);
279
280         return (major_status);
281 }