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
val_init_sec_ctx_args(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID * actual_mech_type,gss_buffer_t output_token)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
gss_init_sec_context(minor_status,claimant_cred_handle,context_handle,target_name,req_mech_type,req_flags,time_req,input_chan_bindings,input_token,actual_mech_type,output_token,ret_flags,time_rec)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