1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * glue routine for gss_accept_sec_context
29 */
30
31 #include <mechglueP.h>
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #include <string.h>
36 #include <errno.h>
37
38 OM_uint32
39 gss_accept_sec_context(minor_status,
40 context_handle,
41 verifier_cred_handle,
42 input_token_buffer,
43 input_chan_bindings,
44 src_name,
45 mech_type,
46 output_token,
47 ret_flags,
48 time_rec,
49 d_cred)
50
51 OM_uint32 *minor_status;
52 gss_ctx_id_t *context_handle;
53 const gss_cred_id_t verifier_cred_handle;
54 const gss_buffer_t input_token_buffer;
55 const gss_channel_bindings_t input_chan_bindings;
56 gss_name_t *src_name;
57 gss_OID *mech_type;
58 gss_buffer_t output_token;
59 OM_uint32 *ret_flags;
60 OM_uint32 *time_rec;
61 gss_cred_id_t *d_cred; /* delegated cred handle */
62
63 {
64 OM_uint32 status, temp_status, t_minstat;
65 gss_union_ctx_id_t union_ctx_id;
66 gss_union_cred_t union_cred;
67 gss_cred_id_t input_cred_handle = GSS_C_NO_CREDENTIAL;
68 gss_cred_id_t tmp_d_cred = GSS_C_NO_CREDENTIAL;
69 gss_name_t internal_name = GSS_C_NO_NAME;
70 gss_name_t tmp_src_name = GSS_C_NO_NAME;
71 gss_OID_desc token_mech_type_desc;
72 gss_OID token_mech_type = &token_mech_type_desc;
73 gss_OID actual_mech = GSS_C_NO_OID;
74 OM_uint32 flags;
75 gss_mechanism mech;
76
77 /* check parameters first */
78 if (minor_status == NULL)
79 return (GSS_S_CALL_INACCESSIBLE_WRITE);
80 *minor_status = 0;
81
82 if (context_handle == NULL || output_token == NULL)
83 return (GSS_S_CALL_INACCESSIBLE_WRITE);
84
85 /* clear optional fields */
86 output_token->value = NULL;
87 output_token->length = 0;
88 if (src_name)
89 *src_name = NULL;
90
91 if (mech_type)
92 *mech_type = NULL;
93
94 if (d_cred)
95 *d_cred = NULL;
96 /*
97 * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
98 * descriptor to hold the mech type information as well as the
99 * underlying mechanism context handle. Otherwise, cast the
100 * value of *context_handle to the union context variable.
101 */
102
103 if (*context_handle == GSS_C_NO_CONTEXT) {
104
105 if (GSS_EMPTY_BUFFER(input_token_buffer))
106 return (GSS_S_CALL_INACCESSIBLE_READ);
107
108 /* Get the token mech type */
109 status = __gss_get_mech_type(token_mech_type,
110 input_token_buffer);
111
112 if (status)
113 return (status);
114
115 status = GSS_S_FAILURE;
116 union_ctx_id = (gss_union_ctx_id_t)
117 malloc(sizeof (gss_union_ctx_id_desc));
118 if (!union_ctx_id)
119 return (GSS_S_FAILURE);
120
121 union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
122 status = generic_gss_copy_oid(&t_minstat,
123 token_mech_type,
124 &union_ctx_id->mech_type);
125 if (status != GSS_S_COMPLETE) {
126 free(union_ctx_id);
127 return (status);
128 }
129
130 /* set the new context handle to caller's data */
131 *context_handle = (gss_ctx_id_t)union_ctx_id;
132 } else {
133 union_ctx_id = (gss_union_ctx_id_t)*context_handle;
134 token_mech_type = union_ctx_id->mech_type;
135 }
136
137 /*
138 * get the appropriate cred handle from the union cred struct.
139 * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
140 * use the default credential.
141 */
142 union_cred = (gss_union_cred_t)verifier_cred_handle;
143 input_cred_handle = __gss_get_mechanism_cred(union_cred,
144 token_mech_type);
145
146 /*
147 * now select the approprate underlying mechanism routine and
148 * call it.
149 */
150
151 mech = __gss_get_mechanism(token_mech_type);
152 if (mech && mech->gss_accept_sec_context) {
153 status = mech->gss_accept_sec_context(
154 mech->context,
155 minor_status,
156 &union_ctx_id->internal_ctx_id,
157 input_cred_handle,
158 input_token_buffer,
159 input_chan_bindings,
160 &internal_name,
161 &actual_mech,
162 output_token,
163 &flags,
164 time_rec,
165 d_cred ? &tmp_d_cred : NULL);
166
167 /* If there's more work to do, keep going... */
168 if (status == GSS_S_CONTINUE_NEEDED)
169 return (GSS_S_CONTINUE_NEEDED);
170
171 /* if the call failed, return with failure */
172 if (status != GSS_S_COMPLETE)
173 goto error_out;
174
175 if (mech_type != NULL)
176 *mech_type = actual_mech;
177
178 /*
179 * if src_name is non-NULL,
180 * convert internal_name into a union name equivalent
181 * First call the mechanism specific display_name()
182 * then call gss_import_name() to create
183 * the union name struct cast to src_name
184 */
185 if (internal_name != NULL) {
186 temp_status = __gss_convert_name_to_union_name(
187 &t_minstat, mech,
188 internal_name, &tmp_src_name);
189 if (temp_status != GSS_S_COMPLETE) {
190 *minor_status = t_minstat;
191 if (output_token->length)
192 (void) gss_release_buffer(
193 &t_minstat,
194 output_token);
195 if (internal_name != GSS_C_NO_NAME)
196 mech->gss_release_name(
197 mech->context,
198 &t_minstat,
199 &internal_name);
200 return (temp_status);
201 }
202 if (src_name != NULL) {
203 *src_name = tmp_src_name;
204 }
205 } else if (src_name != NULL) {
206 *src_name = GSS_C_NO_NAME;
207 }
208
209 /* Ensure we're returning correct creds format */
210 if ((flags & GSS_C_DELEG_FLAG) &&
211 tmp_d_cred != GSS_C_NO_CREDENTIAL) {
212 /*
213 * If we got back an OID different from the original
214 * token OID, assume the delegated_cred is already
215 * a proper union_cred and just return it. Don't
216 * try to re-wrap it. This is for SPNEGO or other
217 * pseudo-mechanisms.
218 */
219 if (actual_mech != GSS_C_NO_OID &&
220 token_mech_type != GSS_C_NO_OID &&
221 !g_OID_equal(actual_mech, token_mech_type)) {
222 *d_cred = tmp_d_cred;
223 } else {
224 gss_union_cred_t d_u_cred = NULL;
225
226 d_u_cred = malloc(sizeof (gss_union_cred_desc));
227 if (d_u_cred == NULL) {
228 status = GSS_S_FAILURE;
229 goto error_out;
230 }
231 (void) memset(d_u_cred, 0,
232 sizeof (gss_union_cred_desc));
233
234 d_u_cred->count = 1;
235
236 status = generic_gss_copy_oid(
237 &t_minstat,
238 actual_mech,
239 &d_u_cred->mechs_array);
240
241 if (status != GSS_S_COMPLETE) {
242 free(d_u_cred);
243 goto error_out;
244 }
245
246 d_u_cred->cred_array = malloc(
247 sizeof (gss_cred_id_t));
248 if (d_u_cred->cred_array != NULL) {
249 d_u_cred->cred_array[0] = tmp_d_cred;
250 } else {
251 free(d_u_cred);
252 status = GSS_S_FAILURE;
253 goto error_out;
254 }
255
256 if (status != GSS_S_COMPLETE) {
257 free(d_u_cred->cred_array);
258 free(d_u_cred);
259 goto error_out;
260 }
261
262 internal_name = GSS_C_NO_NAME;
263
264 d_u_cred->auxinfo.creation_time = time(0);
265 d_u_cred->auxinfo.time_rec = 0;
266
267 if (mech->gss_inquire_cred) {
268 status = mech->gss_inquire_cred(
269 mech->context,
270 minor_status,
271 tmp_d_cred,
272 &internal_name,
273 &d_u_cred->auxinfo.time_rec,
274 &d_u_cred->auxinfo.cred_usage,
275 NULL);
276 }
277
278 if (internal_name != NULL) {
279 temp_status =
280 __gss_convert_name_to_union_name(
281 &t_minstat, mech,
282 internal_name, &tmp_src_name);
283 if (temp_status != GSS_S_COMPLETE) {
284 *minor_status = t_minstat;
285 if (output_token->length)
286 (void) gss_release_buffer(
287 &t_minstat,
288 output_token);
289 free(d_u_cred->cred_array);
290 free(d_u_cred);
291 return (temp_status);
292 }
293 }
294
295 if (tmp_src_name != NULL) {
296 status = gss_display_name(
297 &t_minstat,
298 tmp_src_name,
299 &d_u_cred->auxinfo.name,
300 &d_u_cred->auxinfo.name_type);
301 }
302
303 *d_cred = (gss_cred_id_t)d_u_cred;
304 }
305 }
306 if (ret_flags != NULL) {
307 *ret_flags = flags;
308 }
309
310 if (src_name == NULL && tmp_src_name != NULL)
311 (void) gss_release_name(&t_minstat,
312 &tmp_src_name);
313 return (status);
314 } else {
315
316 status = GSS_S_BAD_MECH;
317 }
318
319 error_out:
320 if (union_ctx_id) {
321 if (union_ctx_id->mech_type) {
322 if (union_ctx_id->mech_type->elements)
323 free(union_ctx_id->mech_type->elements);
324 free(union_ctx_id->mech_type);
325 }
326 free(union_ctx_id);
327 *context_handle = GSS_C_NO_CONTEXT;
328 }
329
330 if (src_name)
331 *src_name = GSS_C_NO_NAME;
332
333 if (tmp_src_name != GSS_C_NO_NAME)
334 (void) gss_release_buffer(&t_minstat,
335 (gss_buffer_t)tmp_src_name);
336
337 return (status);
338 }