xref: /titanic_44/usr/src/lib/libgss/g_accept_sec_context.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *  glue routine for gss_accept_sec_context
31  */
32 
33 #include <mechglueP.h>
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #include <string.h>
38 #include <errno.h>
39 
40 OM_uint32
41 gss_accept_sec_context(minor_status,
42 			context_handle,
43 			verifier_cred_handle,
44 			input_token_buffer,
45 			input_chan_bindings,
46 			src_name,
47 			mech_type,
48 			output_token,
49 			ret_flags,
50 			time_rec,
51 			d_cred)
52 
53 OM_uint32 			*minor_status;
54 gss_ctx_id_t			*context_handle;
55 const gss_cred_id_t		verifier_cred_handle;
56 const gss_buffer_t		input_token_buffer;
57 const gss_channel_bindings_t	input_chan_bindings;
58 gss_name_t			*src_name;
59 gss_OID				*mech_type;
60 gss_buffer_t			output_token;
61 OM_uint32			*ret_flags;
62 OM_uint32			*time_rec;
63 gss_cred_id_t			*d_cred; /* delegated cred handle */
64 
65 {
66 	OM_uint32		status, temp_status, temp_minor_status;
67 	gss_union_ctx_id_t	union_ctx_id;
68 	gss_union_cred_t	union_cred;
69 	gss_cred_id_t	input_cred_handle = GSS_C_NO_CREDENTIAL;
70 	gss_cred_id_t	tmp_d_cred = GSS_C_NO_CREDENTIAL;
71 	gss_name_t		internal_name = GSS_C_NO_NAME;
72 	gss_name_t		tmp_src_name = GSS_C_NO_NAME;
73 	gss_OID_desc	token_mech_type_desc;
74 	gss_OID		token_mech_type = &token_mech_type_desc;
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(&temp_minor_status,
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 					mech_type,
162 					output_token,
163 					ret_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 		/*
176 		 * if src_name is non-NULL,
177 		 * convert internal_name into a union name equivalent
178 		 * First call the mechanism specific display_name()
179 		 * then call gss_import_name() to create
180 		 * the union name struct cast to src_name
181 		 */
182 		if (internal_name != NULL) {
183 			temp_status = __gss_convert_name_to_union_name(
184 				&temp_minor_status, mech,
185 				internal_name, &tmp_src_name);
186 			if (temp_status != GSS_S_COMPLETE) {
187 				*minor_status = temp_minor_status;
188 				if (output_token->length)
189 					(void) gss_release_buffer(
190 						&temp_minor_status,
191 						output_token);
192 				if (internal_name != GSS_C_NO_NAME)
193 					mech->gss_release_name(
194 						mech->context,
195 						&temp_minor_status,
196 						&internal_name);
197 				return (temp_status);
198 			}
199 			if (src_name != NULL) {
200 				*src_name = tmp_src_name;
201 			}
202 		} else if (src_name != NULL) {
203 			*src_name = GSS_C_NO_NAME;
204 		}
205 
206 		/* Ensure we're returning correct creds format */
207 		if ((ret_flags && GSS_C_DELEG_FLAG) &&
208 			tmp_d_cred != GSS_C_NO_CREDENTIAL) {
209 			gss_union_cred_t d_u_cred = NULL;
210 
211 			d_u_cred = malloc(sizeof (gss_union_cred_desc));
212 			if (d_u_cred == NULL) {
213 				status = GSS_S_FAILURE;
214 				goto error_out;
215 			}
216 			(void) memset(d_u_cred, 0,
217 				    sizeof (gss_union_cred_desc));
218 
219 			d_u_cred->count = 1;
220 
221 			status = generic_gss_copy_oid(&temp_minor_status,
222 				token_mech_type,
223 				&d_u_cred->mechs_array);
224 
225 			if (status != GSS_S_COMPLETE) {
226 				free(d_u_cred);
227 				goto error_out;
228 			}
229 
230 			d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
231 			if (d_u_cred->cred_array != NULL) {
232 				d_u_cred->cred_array[0] = tmp_d_cred;
233 			} else {
234 				free(d_u_cred);
235 				status = GSS_S_FAILURE;
236 				goto error_out;
237 			}
238 
239 			if (status != GSS_S_COMPLETE) {
240 				free(d_u_cred->cred_array);
241 				free(d_u_cred);
242 				goto error_out;
243 			}
244 
245 			internal_name = GSS_C_NO_NAME;
246 
247 			d_u_cred->auxinfo.creation_time = time(0);
248 			d_u_cred->auxinfo.time_rec = 0;
249 
250 			if (mech->gss_inquire_cred) {
251 				status = mech->gss_inquire_cred(mech->context,
252 					minor_status,
253 					tmp_d_cred,
254 					&internal_name,
255 					&d_u_cred->auxinfo.time_rec,
256 					&d_u_cred->auxinfo.cred_usage,
257 					NULL);
258 			}
259 
260 			if (internal_name != NULL) {
261 				temp_status = __gss_convert_name_to_union_name(
262 					&temp_minor_status, mech,
263 					internal_name, &tmp_src_name);
264 				if (temp_status != GSS_S_COMPLETE) {
265 					*minor_status = temp_minor_status;
266 					if (output_token->length)
267 						(void) gss_release_buffer(
268 							&temp_minor_status,
269 							output_token);
270 					free(d_u_cred->cred_array);
271 					free(d_u_cred);
272 					return (temp_status);
273 				}
274 			}
275 
276 			if (tmp_src_name != NULL) {
277 				status = gss_display_name(
278 					&temp_minor_status,
279 					tmp_src_name,
280 					&d_u_cred->auxinfo.name,
281 					&d_u_cred->auxinfo.name_type);
282 			}
283 
284 			*d_cred = (gss_cred_id_t)d_u_cred;
285 		}
286 
287 		if (src_name == NULL && tmp_src_name != NULL)
288 			(void) gss_release_name(&temp_minor_status,
289 					&tmp_src_name);
290 		return	(status);
291 	} else {
292 
293 		status = GSS_S_BAD_MECH;
294 	}
295 
296 error_out:
297 	if (union_ctx_id) {
298 		if (union_ctx_id->mech_type) {
299 			if (union_ctx_id->mech_type->elements)
300 				free(union_ctx_id->mech_type->elements);
301 			free(union_ctx_id->mech_type);
302 		}
303 		free(union_ctx_id);
304 		*context_handle = GSS_C_NO_CONTEXT;
305 	}
306 
307 	if (output_token->length)
308 		(void) gss_release_buffer(&temp_minor_status, output_token);
309 
310 	if (src_name)
311 		*src_name = GSS_C_NO_NAME;
312 
313 	if (tmp_src_name != GSS_C_NO_NAME)
314 		(void) gss_release_buffer(&temp_minor_status,
315 			(gss_buffer_t)tmp_src_name);
316 
317 	return (status);
318 }
319