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 2005 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_acquire_cred
31 */
32
33 #include <mechglueP.h>
34 #include <gssapi/gssapi_ext.h>
35 #include <stdio.h>
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #include <string.h>
40 #include <errno.h>
41 #include <time.h>
42 /* local functions */
43 static gss_OID_set create_actual_mechs(const gss_OID, int);
44
45 static gss_OID_set
create_actual_mechs(mechs_array,count)46 create_actual_mechs(mechs_array, count)
47 const gss_OID mechs_array;
48 int count;
49 {
50 gss_OID_set actual_mechs;
51 int i;
52 OM_uint32 minor;
53
54 actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
55 if (!actual_mechs)
56 return (NULL);
57
58 actual_mechs->elements = (gss_OID)
59 malloc(sizeof (gss_OID_desc) * count);
60 if (!actual_mechs->elements) {
61 free(actual_mechs);
62 return (NULL);
63 }
64
65 actual_mechs->count = 0;
66
67 for (i = 0; i < count; i++) {
68 actual_mechs->elements[i].elements = (void *)
69 malloc(mechs_array[i].length);
70 if (actual_mechs->elements[i].elements == NULL) {
71 (void) gss_release_oid_set(&minor, &actual_mechs);
72 return (NULL);
73 }
74 g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
75 actual_mechs->count++;
76 }
77
78 return (actual_mechs);
79 }
80
81
82 OM_uint32
gss_acquire_cred_with_password(minor_status,desired_name,password,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)83 gss_acquire_cred_with_password(minor_status,
84 desired_name,
85 password,
86 time_req,
87 desired_mechs,
88 cred_usage,
89 output_cred_handle,
90 actual_mechs,
91 time_rec)
92
93 OM_uint32 * minor_status;
94 const gss_name_t desired_name;
95 const gss_buffer_t password;
96 OM_uint32 time_req;
97 const gss_OID_set desired_mechs;
98 int cred_usage;
99 gss_cred_id_t *output_cred_handle;
100 gss_OID_set * actual_mechs;
101 OM_uint32 * time_rec;
102
103 {
104 OM_uint32 major = GSS_S_FAILURE;
105 OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
106 gss_OID_set_desc default_OID_set;
107 gss_OID_set mechs;
108 gss_OID_desc default_OID;
109 gss_mechanism mech;
110 int i;
111 gss_union_cred_t creds;
112
113 /* start by checking parameters */
114 if (minor_status == NULL)
115 return (GSS_S_CALL_INACCESSIBLE_WRITE);
116 *minor_status = 0;
117
118 if (desired_name == GSS_C_NO_NAME)
119 return (GSS_S_BAD_NAME);
120
121 if (output_cred_handle == NULL)
122 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
123
124 *output_cred_handle = GSS_C_NO_CREDENTIAL;
125
126 /* Set output parameters to NULL for now */
127 if (actual_mechs != NULL)
128 *actual_mechs = GSS_C_NULL_OID_SET;
129
130 if (time_rec)
131 *time_rec = 0;
132
133 /*
134 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
135 * appropriate default. We use the first mechanism in the
136 * mechansim list as the default. This set is created with
137 * statics thus needs not be freed
138 */
139 if (desired_mechs == GSS_C_NULL_OID_SET) {
140 mech = __gss_get_mechanism(GSS_C_NULL_OID);
141 if (mech == NULL)
142 return (GSS_S_BAD_MECH);
143
144 mechs = &default_OID_set;
145 default_OID_set.count = 1;
146 default_OID_set.elements = &default_OID;
147 default_OID.length = mech->mech_type.length;
148 default_OID.elements = mech->mech_type.elements;
149 } else
150 mechs = desired_mechs;
151
152 if (mechs->count == 0)
153 return (GSS_S_BAD_MECH);
154
155 /* allocate the output credential structure */
156 creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
157 if (creds == NULL)
158 return (GSS_S_FAILURE);
159
160 /* initialize to 0s */
161 (void) memset(creds, 0, sizeof (gss_union_cred_desc));
162
163 /* for each requested mech attempt to obtain a credential */
164 for (i = 0; i < mechs->count; i++) {
165 major = gss_add_cred_with_password(minor_status,
166 (gss_cred_id_t)creds,
167 desired_name,
168 &mechs->elements[i],
169 password,
170 cred_usage, time_req, time_req, NULL,
171 NULL, &initTimeOut, &acceptTimeOut);
172 if (major == GSS_S_COMPLETE) {
173 /* update the credential's time */
174 if (cred_usage == GSS_C_ACCEPT) {
175 if (outTime > acceptTimeOut)
176 outTime = acceptTimeOut;
177 } else if (cred_usage == GSS_C_INITIATE) {
178 if (outTime > initTimeOut)
179 outTime = initTimeOut;
180 } else {
181 /*
182 * time_rec is the lesser of the
183 * init/accept times
184 */
185 if (initTimeOut > acceptTimeOut)
186 outTime = (outTime > acceptTimeOut) ?
187 acceptTimeOut : outTime;
188 else
189 outTime = (outTime > initTimeOut) ?
190 initTimeOut : outTime;
191 }
192 }
193 } /* for */
194
195 /* ensure that we have at least one credential element */
196 if (creds->count < 1) {
197 free(creds);
198 return (major);
199 }
200
201 /*
202 * fill in output parameters
203 * setup the actual mechs output parameter
204 */
205 if (actual_mechs != NULL) {
206 if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
207 creds->count)) == NULL) {
208 (void) gss_release_cred(minor_status,
209 (gss_cred_id_t *)&creds);
210 *minor_status = 0;
211 return (GSS_S_FAILURE);
212 }
213 }
214
215 if (time_rec)
216 *time_rec = outTime;
217
218
219 *output_cred_handle = (gss_cred_id_t)creds;
220 return (GSS_S_COMPLETE);
221 }
222
223 /* V2 INTERFACE */
224 OM_uint32
gss_add_cred_with_password(minor_status,input_cred_handle,desired_name,desired_mech,password,cred_usage,initiator_time_req,acceptor_time_req,output_cred_handle,actual_mechs,initiator_time_rec,acceptor_time_rec)225 gss_add_cred_with_password(minor_status, input_cred_handle,
226 desired_name, desired_mech, password,
227 cred_usage, initiator_time_req,
228 acceptor_time_req, output_cred_handle,
229 actual_mechs, initiator_time_rec,
230 acceptor_time_rec)
231 OM_uint32 *minor_status;
232 const gss_cred_id_t input_cred_handle;
233 const gss_name_t desired_name;
234 const gss_OID desired_mech;
235 const gss_buffer_t password;
236 gss_cred_usage_t cred_usage;
237 OM_uint32 initiator_time_req;
238 OM_uint32 acceptor_time_req;
239 gss_cred_id_t *output_cred_handle;
240 gss_OID_set *actual_mechs;
241 OM_uint32 *initiator_time_rec;
242 OM_uint32 *acceptor_time_rec;
243 {
244 OM_uint32 status, time_req, time_rec, temp_minor_status;
245 gss_mechanism mech;
246 gss_mechanism_ext mech_ext;
247 gss_union_name_t union_name = NULL;
248 gss_union_cred_t union_cred, new_union_cred;
249 gss_name_t internal_name = GSS_C_NO_NAME;
250 gss_name_t allocated_name = GSS_C_NO_NAME;
251 gss_cred_id_t cred = NULL;
252 gss_OID new_mechs_array = NULL;
253 gss_cred_id_t *new_cred_array = NULL;
254
255 /* check input parameters */
256 if (minor_status == NULL)
257 return (GSS_S_CALL_INACCESSIBLE_WRITE);
258 *minor_status = 0;
259
260 if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
261 output_cred_handle == NULL)
262 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
263
264 if (desired_name == GSS_C_NO_NAME)
265 return (GSS_S_BAD_NAME);
266 union_name = (gss_union_name_t)desired_name;
267
268 if (output_cred_handle != NULL)
269 *output_cred_handle = GSS_C_NO_CREDENTIAL;
270
271 if (actual_mechs != NULL)
272 *actual_mechs = NULL;
273
274 if (acceptor_time_rec != NULL)
275 *acceptor_time_rec = 0;
276
277 if (initiator_time_rec != NULL)
278 *initiator_time_rec = 0;
279
280 if ((mech = __gss_get_mechanism(desired_mech)) == NULL)
281 return (GSS_S_BAD_MECH);
282
283 if ((mech_ext = __gss_get_mechanism_ext(desired_mech)) == NULL ||
284 mech_ext->gss_acquire_cred_with_password == NULL)
285 return (GSS_S_UNAVAILABLE);
286
287 if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
288 union_cred = malloc(sizeof (gss_union_cred_desc));
289 if (union_cred == NULL)
290 return (GSS_S_FAILURE);
291
292 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
293
294 } else {
295 union_cred = (gss_union_cred_t)input_cred_handle;
296 if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
297 GSS_C_NO_CREDENTIAL)
298 return (GSS_S_DUPLICATE_ELEMENT);
299 }
300
301 /* May need to create an MN */
302 if (union_name->mech_type &&
303 g_OID_equal(union_name->mech_type,
304 &mech->mech_type))
305 internal_name = union_name->mech_name;
306 else {
307 if (__gss_import_internal_name(minor_status,
308 &mech->mech_type, union_name,
309 &allocated_name) != GSS_S_COMPLETE)
310 return (GSS_S_BAD_NAME);
311 internal_name = allocated_name;
312 }
313
314 if (cred_usage == GSS_C_ACCEPT)
315 time_req = acceptor_time_req;
316 else if (cred_usage == GSS_C_INITIATE)
317 time_req = initiator_time_req;
318 else if (cred_usage == GSS_C_BOTH)
319 time_req = (acceptor_time_req > initiator_time_req) ?
320 acceptor_time_req : initiator_time_req;
321
322 status = mech_ext->gss_acquire_cred_with_password(mech->context,
323 minor_status, internal_name, password, time_req,
324 GSS_C_NULL_OID_SET, cred_usage, &cred, NULL,
325 &time_rec);
326
327 if (status != GSS_S_COMPLETE)
328 goto errout;
329
330 /* May need to set credential auxinfo strucutre */
331 if (union_cred->auxinfo.creation_time == 0) {
332 union_cred->auxinfo.creation_time = time(NULL);
333 union_cred->auxinfo.time_rec = time_rec;
334 union_cred->auxinfo.cred_usage = cred_usage;
335
336 if ((status = mech->gss_display_name(mech->context,
337 &temp_minor_status, internal_name,
338 &union_cred->auxinfo.name,
339 &union_cred->auxinfo.name_type)) !=
340 GSS_S_COMPLETE)
341 goto errout;
342 }
343
344 /* Now add the new credential elements */
345 new_mechs_array = (gss_OID)
346 malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
347
348 new_cred_array = (gss_cred_id_t *)
349 malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
350
351 if (!new_mechs_array || !new_cred_array) {
352 status = GSS_S_FAILURE;
353 goto errout;
354 }
355
356 if (acceptor_time_rec)
357 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
358 *acceptor_time_rec = time_rec;
359 if (initiator_time_rec)
360 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
361 *initiator_time_rec = time_rec;
362
363 /*
364 * OK, expand the mechanism array and the credential array
365 */
366 (void) memcpy(new_mechs_array, union_cred->mechs_array,
367 sizeof (gss_OID_desc) * union_cred->count);
368 (void) memcpy(new_cred_array, union_cred->cred_array,
369 sizeof (gss_cred_id_t) * union_cred->count);
370
371 new_cred_array[union_cred->count] = cred;
372 if ((new_mechs_array[union_cred->count].elements =
373 malloc(mech->mech_type.length)) == NULL)
374 goto errout;
375
376 g_OID_copy(&new_mechs_array[union_cred->count],
377 &mech->mech_type);
378
379 if (actual_mechs) {
380 *actual_mechs = create_actual_mechs(new_mechs_array,
381 union_cred->count + 1);
382 if (*actual_mechs == NULL) {
383 free(new_mechs_array[union_cred->count].elements);
384 goto errout;
385 }
386 }
387
388 if (output_cred_handle == NULL) {
389 free(union_cred->mechs_array);
390 free(union_cred->cred_array);
391 new_union_cred = union_cred;
392 } else {
393 new_union_cred = malloc(sizeof (gss_union_cred_desc));
394 if (new_union_cred == NULL) {
395 free(new_mechs_array[union_cred->count].elements);
396 goto errout;
397 }
398 *new_union_cred = *union_cred;
399 *output_cred_handle = (gss_cred_id_t)new_union_cred;
400 }
401
402 new_union_cred->mechs_array = new_mechs_array;
403 new_union_cred->cred_array = new_cred_array;
404 new_union_cred->count++;
405
406 /* We're done with the internal name. Free it if we allocated it. */
407
408 if (allocated_name)
409 (void) __gss_release_internal_name(&temp_minor_status,
410 &mech->mech_type,
411 &allocated_name);
412
413 return (GSS_S_COMPLETE);
414
415 errout:
416 if (new_mechs_array)
417 free(new_mechs_array);
418 if (new_cred_array)
419 free(new_cred_array);
420
421 if (cred != NULL && mech->gss_release_cred)
422 mech->gss_release_cred(mech->context,
423 &temp_minor_status, &cred);
424
425 if (allocated_name)
426 (void) __gss_release_internal_name(&temp_minor_status,
427 &mech->mech_type,
428 &allocated_name);
429
430 if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
431 if (union_cred->auxinfo.name.value)
432 free(union_cred->auxinfo.name.value);
433 free(union_cred);
434 }
435
436 return (status);
437 }
438