xref: /illumos-gate/usr/src/lib/libgss/g_init_sec_context.c (revision 598f4ceed9327d2d6c2325dd67cae3aa06f7fea6)
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  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  *  glue routine for gss_init_sec_context
27  */
28 #include <mechglueP.h>
29 #include "gssapiP_generic.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 static OM_uint32
35 val_init_sec_ctx_args(
36 	OM_uint32 *minor_status,
37 	gss_ctx_id_t *context_handle,
38 	gss_name_t target_name,
39 	gss_OID *actual_mech_type,
40 	gss_buffer_t output_token)
41 {
42 
43 	/* Initialize outputs. */
44 
45 	if (minor_status != NULL)
46 		*minor_status = 0;
47 
48 	if (actual_mech_type != NULL)
49 		*actual_mech_type = GSS_C_NO_OID;
50 
51 	if (output_token != GSS_C_NO_BUFFER) {
52 		output_token->length = 0;
53 		output_token->value = NULL;
54 	}
55 
56 	/* Validate arguments. */
57 
58 	if (minor_status == NULL)
59 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
60 
61 	if (context_handle == NULL)
62 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
63 
64 	if (target_name == NULL)
65 		return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
66 
67 	if (output_token == NULL)
68 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
69 
70 	return (GSS_S_COMPLETE);
71 }
72 
73 OM_uint32
74 gss_init_sec_context(minor_status,
75 			claimant_cred_handle,
76 			context_handle,
77 			target_name,
78 			req_mech_type,
79 			req_flags,
80 			time_req,
81 			input_chan_bindings,
82 			input_token,
83 			actual_mech_type,
84 			output_token,
85 			ret_flags,
86 			time_rec)
87 
88 OM_uint32 *			minor_status;
89 const gss_cred_id_t		claimant_cred_handle;
90 gss_ctx_id_t 			*context_handle;
91 const gss_name_t		target_name;
92 const gss_OID			req_mech_type;
93 OM_uint32			req_flags;
94 OM_uint32			time_req;
95 const gss_channel_bindings_t	input_chan_bindings;
96 const gss_buffer_t		input_token;
97 gss_OID *			actual_mech_type;
98 gss_buffer_t			output_token;
99 OM_uint32 *			ret_flags;
100 OM_uint32 *			time_rec;
101 
102 {
103 	OM_uint32		status, temp_minor_status;
104 	gss_union_name_t	union_name;
105 	gss_union_cred_t	union_cred;
106 	gss_name_t		internal_name;
107 	gss_union_ctx_id_t	union_ctx_id;
108 	gss_OID			mech_type = GSS_C_NULL_OID;
109 	gss_mechanism		mech;
110 	gss_cred_id_t		input_cred_handle;
111 
112 	status = val_init_sec_ctx_args(minor_status,
113 				context_handle,
114 				target_name,
115 				actual_mech_type,
116 				output_token);
117 	if (status != GSS_S_COMPLETE)
118 		return (status);
119 
120 	if (req_mech_type)
121 		mech_type = (gss_OID)req_mech_type;
122 
123 	union_name = (gss_union_name_t)target_name;
124 
125 	/*
126 	 * obtain the gss mechanism information for the requested
127 	 * mechanism.  If mech_type is NULL, set it to the resultant
128 	 * mechanism
129 	 */
130 	mech = __gss_get_mechanism(mech_type);
131 	if (mech == NULL)
132 		return (GSS_S_BAD_MECH);
133 
134 	if (mech->gss_init_sec_context == NULL)
135 		return (GSS_S_UNAVAILABLE);
136 
137 	if (mech_type == GSS_C_NULL_OID)
138 		mech_type = &mech->mech_type;
139 
140 	/*
141 	 * If target_name is mechanism_specific, then it must match the
142 	 * mech_type that we're about to use.  Otherwise, do an import on
143 	 * the external_name form of the target name.
144 	 */
145 	if (union_name->mech_type &&
146 			g_OID_equal(union_name->mech_type, mech_type)) {
147 		internal_name = union_name->mech_name;
148 	} else {
149 		if ((status = __gss_import_internal_name(minor_status,
150 					mech_type, union_name,
151 					&internal_name)) != GSS_S_COMPLETE)
152 			return (status);
153 	}
154 
155 	/*
156 	 * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
157 	 * descriptor to hold the mech type information as well as the
158 	 * underlying mechanism context handle. Otherwise, cast the
159 	 * value of *context_handle to the union context variable.
160 	 */
161 	if (*context_handle == GSS_C_NO_CONTEXT) {
162 		status = GSS_S_FAILURE;
163 		union_ctx_id = (gss_union_ctx_id_t)
164 			malloc(sizeof (gss_union_ctx_id_desc));
165 		if (union_ctx_id == NULL)
166 			goto end;
167 
168 		if (generic_gss_copy_oid(&temp_minor_status, mech_type,
169 				&union_ctx_id->mech_type) != GSS_S_COMPLETE) {
170 			free(union_ctx_id);
171 			goto end;
172 		}
173 
174 		/* copy the supplied context handle */
175 		union_ctx_id->internal_ctx_id = *context_handle;
176 	} else
177 		union_ctx_id = (gss_union_ctx_id_t)*context_handle;
178 
179 	/*
180 	 * get the appropriate cred handle from the union cred struct.
181 	 * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
182 	 * use the default credential.
183 	 */
184 	union_cred = (gss_union_cred_t)claimant_cred_handle;
185 	input_cred_handle = __gss_get_mechanism_cred(union_cred, mech_type);
186 
187 	/*
188 	 * now call the approprate underlying mechanism routine
189 	 */
190 
191 	status = mech->gss_init_sec_context(
192 				mech->context,
193 				minor_status,
194 				input_cred_handle,
195 				&union_ctx_id->internal_ctx_id,
196 				internal_name,
197 				mech_type,
198 				req_flags,
199 				time_req,
200 				input_chan_bindings,
201 				input_token,
202 				actual_mech_type,
203 				output_token,
204 				ret_flags,
205 				time_rec);
206 
207 	if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
208 		/*
209 		 * the spec says (the preferred) method is to delete all
210 		 * context info on the first call to init, and on all
211 		 * subsequent calls make the caller responsible for
212 		 * calling gss_delete_sec_context
213 		 */
214 		map_error(minor_status, mech);
215 		if (*context_handle == GSS_C_NO_CONTEXT) {
216 			free(union_ctx_id->mech_type->elements);
217 			free(union_ctx_id->mech_type);
218 			free(union_ctx_id);
219 		}
220 	} else if (*context_handle == GSS_C_NO_CONTEXT)
221 		*context_handle = (gss_ctx_id_t)union_ctx_id;
222 
223 end:
224 	if (union_name->mech_name == NULL ||
225 		union_name->mech_name != internal_name) {
226 		(void) __gss_release_internal_name(&temp_minor_status,
227 					mech_type, &internal_name);
228 	}
229 
230 	return (status);
231 }
232