Don't use mech default cred when input cred isn't
[heimdal.git] / lib / gssapi / mech / gss_init_sec_context.c
blob21e02aea6972af86ca60eb5200791cb3db6897fe
1 /*-
2 * Copyright (c) 2005 Doug Rabson
3 * All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 * $FreeBSD: src/lib/libgssapi/gss_init_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
29 #include "mech_locl.h"
31 static gss_cred_id_t
32 _gss_mech_cred_find(gss_const_cred_id_t cred_handle, gss_OID mech_type)
34 struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
35 struct _gss_mechanism_cred *mc;
37 if (cred == NULL)
38 return GSS_C_NO_CREDENTIAL;
40 HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
41 if (gss_oid_equal(mech_type, mc->gmc_mech_oid))
42 return mc->gmc_cred;
44 return GSS_C_NO_CREDENTIAL;
47 /**
48 * As the initiator build a context with an acceptor.
50 * Returns in the major
51 * - GSS_S_COMPLETE - if the context if build
52 * - GSS_S_CONTINUE_NEEDED - if the caller needs to continue another
53 * round of gss_i nit_sec_context
54 * - error code - any other error code
56 * @param minor_status minor status code.
58 * @param initiator_cred_handle the credential to use when building
59 * the context, if GSS_C_NO_CREDENTIAL is passed, the default
60 * credential for the mechanism will be used.
62 * @param context_handle a pointer to a context handle, will be
63 * returned as long as there is not an error.
65 * @param target_name the target name of acceptor, created using
66 * gss_import_name(). The name is can be of any name types the
67 * mechanism supports, check supported name types with
68 * gss_inquire_names_for_mech().
70 * @param input_mech_type mechanism type to use, if GSS_C_NO_OID is
71 * used, Kerberos (GSS_KRB5_MECHANISM) will be tried. Other
72 * available mechanism are listed in the @ref gssapi_mechs_intro
73 * section.
75 * @param req_flags flags using when building the context, see @ref
76 * gssapi_context_flags
78 * @param time_req time requested this context should be valid in
79 * seconds, common used value is GSS_C_INDEFINITE
81 * @param input_chan_bindings Channel bindings used, if not exepected
82 * otherwise, used GSS_C_NO_CHANNEL_BINDINGS
84 * @param input_token input token sent from the acceptor, for the
85 * initial packet the buffer of { NULL, 0 } should be used.
87 * @param actual_mech_type the actual mech used, MUST NOT be freed
88 * since it pointing to static memory.
90 * @param output_token if there is an output token, regardless of
91 * complete, continue_needed, or error it should be sent to the
92 * acceptor
94 * @param ret_flags return what flags was negotitated, caller should
95 * check if they are accetable. For example, if
96 * GSS_C_MUTUAL_FLAG was negotiated with the acceptor or not.
98 * @param time_rec amount of time this context is valid for
100 * @returns a gss_error code, see gss_display_status() about printing
101 * the error code.
103 * @ingroup gssapi
108 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
109 gss_init_sec_context(OM_uint32 * minor_status,
110 gss_const_cred_id_t initiator_cred_handle,
111 gss_ctx_id_t * context_handle,
112 gss_const_name_t target_name,
113 const gss_OID input_mech_type,
114 OM_uint32 req_flags,
115 OM_uint32 time_req,
116 const gss_channel_bindings_t input_chan_bindings,
117 const gss_buffer_t input_token,
118 gss_OID * actual_mech_type,
119 gss_buffer_t output_token,
120 OM_uint32 * ret_flags,
121 OM_uint32 * time_rec)
123 OM_uint32 major_status;
124 gssapi_mech_interface m;
125 struct _gss_name *name = (struct _gss_name *) target_name;
126 struct _gss_mechanism_name *mn;
127 struct _gss_context *ctx = (struct _gss_context *) *context_handle;
128 gss_const_cred_id_t cred_handle;
129 int allocated_ctx;
130 gss_OID mech_type = input_mech_type;
132 *minor_status = 0;
134 _mg_buffer_zero(output_token);
135 if (actual_mech_type)
136 *actual_mech_type = GSS_C_NO_OID;
137 if (ret_flags)
138 *ret_flags = 0;
139 if (time_rec)
140 *time_rec = 0;
143 * If we haven't allocated a context yet, do so now and lookup
144 * the mechanism switch table. If we have one already, make
145 * sure we use the same mechanism switch as before.
147 if (!ctx) {
148 if (mech_type == NULL)
149 mech_type = GSS_KRB5_MECHANISM;
151 ctx = malloc(sizeof(struct _gss_context));
152 if (!ctx) {
153 *minor_status = ENOMEM;
154 return (GSS_S_FAILURE);
156 memset(ctx, 0, sizeof(struct _gss_context));
157 m = ctx->gc_mech = __gss_get_mechanism(mech_type);
158 if (!m) {
159 free(ctx);
160 return (GSS_S_BAD_MECH);
162 allocated_ctx = 1;
163 } else {
164 m = ctx->gc_mech;
165 mech_type = &ctx->gc_mech->gm_mech_oid;
166 allocated_ctx = 0;
170 * Find the MN for this mechanism.
172 major_status = _gss_find_mn(minor_status, name, mech_type, &mn);
173 if (major_status != GSS_S_COMPLETE) {
174 if (allocated_ctx)
175 free(ctx);
176 return major_status;
180 * If we have a cred, find the cred for this mechanism.
182 if (m->gm_flags & GM_USE_MG_CRED)
183 cred_handle = initiator_cred_handle;
184 else
185 cred_handle = _gss_mech_cred_find(initiator_cred_handle, mech_type);
187 if (initiator_cred_handle != GSS_C_NO_CREDENTIAL &&
188 cred_handle == NULL) {
189 if (allocated_ctx)
190 free(ctx);
191 return GSS_S_NO_CRED;
194 major_status = m->gm_init_sec_context(minor_status,
195 cred_handle,
196 &ctx->gc_ctx,
197 mn->gmn_name,
198 mech_type,
199 req_flags,
200 time_req,
201 input_chan_bindings,
202 input_token,
203 actual_mech_type,
204 output_token,
205 ret_flags,
206 time_rec);
208 if (major_status != GSS_S_COMPLETE
209 && major_status != GSS_S_CONTINUE_NEEDED) {
210 if (allocated_ctx)
211 free(ctx);
212 _mg_buffer_zero(output_token);
213 _gss_mg_error(m, major_status, *minor_status);
214 } else {
215 *context_handle = (gss_ctx_id_t) ctx;
218 return (major_status);