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_acquire_cred
27 */
28 #include <mechglueP.h>
29 #include "gssapiP_generic.h"
30 #include <stdio.h>
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #include <string.h>
35 #include <errno.h>
36 #include <time.h>
37
38 /* local functions */
39 static gss_OID_set create_actual_mechs(const gss_OID, int);
40
41 static gss_OID_set
create_actual_mechs(mechs_array,count)42 create_actual_mechs(mechs_array, count)
43 const gss_OID mechs_array;
44 int count;
45 {
46 gss_OID_set actual_mechs;
47 int i;
48 OM_uint32 minor;
49
50 actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
51 if (!actual_mechs)
52 return (NULL);
53
54 actual_mechs->elements = (gss_OID)
55 malloc(sizeof (gss_OID_desc) * count);
56 if (!actual_mechs->elements) {
57 free(actual_mechs);
58 return (NULL);
59 }
60
61 actual_mechs->count = 0;
62
63 for (i = 0; i < count; i++) {
64 actual_mechs->elements[i].elements = (void *)
65 malloc(mechs_array[i].length);
66 if (actual_mechs->elements[i].elements == NULL) {
67 (void) gss_release_oid_set(&minor, &actual_mechs);
68 return (NULL);
69 }
70 g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
71 actual_mechs->count++;
72 }
73
74 return (actual_mechs);
75 }
76
77 static OM_uint32
val_acq_cred_args(OM_uint32 * minor_status,gss_name_t desired_name,OM_uint32 time_req,gss_OID_set desired_mechs,int cred_usage,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * time_rec)78 val_acq_cred_args(
79 OM_uint32 *minor_status,
80 /*LINTED*/
81 gss_name_t desired_name,
82 /*LINTED*/
83 OM_uint32 time_req,
84 /*LINTED*/
85 gss_OID_set desired_mechs,
86 int cred_usage,
87 gss_cred_id_t *output_cred_handle,
88 gss_OID_set *actual_mechs,
89 OM_uint32 *time_rec)
90 {
91
92 /* Initialize outputs. */
93
94 if (minor_status != NULL)
95 *minor_status = 0;
96
97 if (output_cred_handle != NULL)
98 *output_cred_handle = GSS_C_NO_CREDENTIAL;
99
100 if (actual_mechs != NULL)
101 *actual_mechs = GSS_C_NULL_OID_SET;
102
103 if (time_rec != NULL)
104 *time_rec = 0;
105
106 /* Validate arguments. */
107
108 if (minor_status == NULL)
109 return (GSS_S_CALL_INACCESSIBLE_WRITE);
110
111 if (output_cred_handle == NULL)
112 return (GSS_S_CALL_INACCESSIBLE_WRITE);
113
114 if (cred_usage != GSS_C_ACCEPT
115 && cred_usage != GSS_C_INITIATE
116 && cred_usage != GSS_C_BOTH) {
117 if (minor_status) {
118 *minor_status = EINVAL;
119 map_errcode(minor_status);
120 }
121 return GSS_S_FAILURE;
122 }
123
124 return (GSS_S_COMPLETE);
125 }
126
127 OM_uint32
gss_acquire_cred(minor_status,desired_name,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)128 gss_acquire_cred(minor_status,
129 desired_name,
130 time_req,
131 desired_mechs,
132 cred_usage,
133 output_cred_handle,
134 actual_mechs,
135 time_rec)
136
137 OM_uint32 * minor_status;
138 const gss_name_t desired_name;
139 OM_uint32 time_req;
140 const gss_OID_set desired_mechs;
141 int cred_usage;
142 gss_cred_id_t *output_cred_handle;
143 gss_OID_set * actual_mechs;
144 OM_uint32 * time_rec;
145
146 {
147 OM_uint32 major = GSS_S_FAILURE;
148 OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
149 gss_OID_set_desc default_OID_set;
150 gss_OID_set mechs;
151 gss_OID_desc default_OID;
152 gss_mechanism mech;
153 unsigned int i;
154 gss_union_cred_t creds;
155
156 major = val_acq_cred_args(minor_status,
157 desired_name,
158 time_req,
159 desired_mechs,
160 cred_usage,
161 output_cred_handle,
162 actual_mechs,
163 time_rec);
164 if (major != GSS_S_COMPLETE)
165 return (major);
166
167 /* Initial value needed below. */
168 major = GSS_S_FAILURE;
169
170 /*
171 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
172 * appropriate default. We use the first mechanism in the
173 * mechansim list as the default. This set is created with
174 * statics thus needs not be freed
175 */
176 if (desired_mechs == GSS_C_NULL_OID_SET) {
177 mech = __gss_get_mechanism(NULL);
178 if (mech == NULL)
179 return (GSS_S_BAD_MECH);
180
181 mechs = &default_OID_set;
182 default_OID_set.count = 1;
183 default_OID_set.elements = &default_OID;
184 default_OID.length = mech->mech_type.length;
185 default_OID.elements = mech->mech_type.elements;
186 } else
187 mechs = desired_mechs;
188
189 if (mechs->count == NULL)
190 return (GSS_S_BAD_MECH);
191
192 /* allocate the output credential structure */
193 creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
194 if (creds == NULL)
195 return (GSS_S_FAILURE);
196
197 /* initialize to 0s */
198 (void) memset(creds, 0, sizeof (gss_union_cred_desc));
199
200 /* for each requested mech attempt to obtain a credential */
201 for (i = 0; i < mechs->count; i++) {
202 major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
203 desired_name,
204 &mechs->elements[i],
205 cred_usage, time_req, time_req, NULL,
206 NULL, &initTimeOut, &acceptTimeOut);
207 if (major == GSS_S_COMPLETE) {
208 /* update the credential's time */
209 if (cred_usage == GSS_C_ACCEPT) {
210 if (outTime > acceptTimeOut)
211 outTime = acceptTimeOut;
212 } else if (cred_usage == GSS_C_INITIATE) {
213 if (outTime > initTimeOut)
214 outTime = initTimeOut;
215 } else {
216 /*
217 * time_rec is the lesser of the
218 * init/accept times
219 */
220 if (initTimeOut > acceptTimeOut)
221 outTime = (outTime > acceptTimeOut) ?
222 acceptTimeOut : outTime;
223 else
224 outTime = (outTime > initTimeOut) ?
225 initTimeOut : outTime;
226 }
227 }
228 } /* for */
229
230 /* ensure that we have at least one credential element */
231 if (creds->count < 1) {
232 free(creds);
233 return (major);
234 }
235
236 /*
237 * fill in output parameters
238 * setup the actual mechs output parameter
239 */
240 if (actual_mechs != NULL) {
241 if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
242 creds->count)) == NULL) {
243 (void) gss_release_cred(minor_status,
244 (gss_cred_id_t *)&creds);
245 *minor_status = 0;
246 return (GSS_S_FAILURE);
247 }
248 }
249
250 if (time_rec)
251 *time_rec = outTime;
252
253
254 *output_cred_handle = (gss_cred_id_t)creds;
255 return (GSS_S_COMPLETE);
256 }
257
258 static OM_uint32
val_add_cred_args(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_name_t desired_name,gss_OID desired_mech,gss_cred_usage_t cred_usage,OM_uint32 initiator_time_req,OM_uint32 acceptor_time_req,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * initiator_time_rec,OM_uint32 * acceptor_time_rec)259 val_add_cred_args(
260 OM_uint32 *minor_status,
261 gss_cred_id_t input_cred_handle,
262 /*LINTED*/
263 gss_name_t desired_name,
264 /*LINTED*/
265 gss_OID desired_mech,
266 gss_cred_usage_t cred_usage,
267 /*LINTED*/
268 OM_uint32 initiator_time_req,
269 /*LINTED*/
270 OM_uint32 acceptor_time_req,
271 gss_cred_id_t *output_cred_handle,
272 gss_OID_set *actual_mechs,
273 OM_uint32 *initiator_time_rec,
274 OM_uint32 *acceptor_time_rec)
275 {
276
277 /* Initialize outputs. */
278
279 if (minor_status != NULL)
280 *minor_status = 0;
281
282 if (output_cred_handle != NULL)
283 *output_cred_handle = GSS_C_NO_CREDENTIAL;
284
285 if (actual_mechs != NULL)
286 *actual_mechs = GSS_C_NO_OID_SET;
287
288 if (acceptor_time_rec != NULL)
289 *acceptor_time_rec = 0;
290
291 if (initiator_time_rec != NULL)
292 *initiator_time_rec = 0;
293 /* Validate arguments. */
294
295 if (minor_status == NULL)
296 return (GSS_S_CALL_INACCESSIBLE_WRITE);
297
298 if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
299 output_cred_handle == NULL)
300 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
301
302 if (cred_usage != GSS_C_ACCEPT
303 && cred_usage != GSS_C_INITIATE
304 && cred_usage != GSS_C_BOTH) {
305 if (minor_status) {
306 *minor_status = EINVAL;
307 map_errcode(minor_status);
308 }
309 return GSS_S_FAILURE;
310 }
311
312 return (GSS_S_COMPLETE);
313 }
314
315 /* V2 INTERFACE */
316 OM_uint32
gss_add_cred(minor_status,input_cred_handle,desired_name,desired_mech,cred_usage,initiator_time_req,acceptor_time_req,output_cred_handle,actual_mechs,initiator_time_rec,acceptor_time_rec)317 gss_add_cred(minor_status, input_cred_handle,
318 desired_name, desired_mech, cred_usage,
319 initiator_time_req, acceptor_time_req,
320 output_cred_handle, actual_mechs,
321 initiator_time_rec, acceptor_time_rec)
322 OM_uint32 *minor_status;
323 const gss_cred_id_t input_cred_handle;
324 const gss_name_t desired_name;
325 const gss_OID desired_mech;
326 gss_cred_usage_t cred_usage;
327 OM_uint32 initiator_time_req;
328 OM_uint32 acceptor_time_req;
329 gss_cred_id_t *output_cred_handle;
330 gss_OID_set *actual_mechs;
331 OM_uint32 *initiator_time_rec;
332 OM_uint32 *acceptor_time_rec;
333 {
334 OM_uint32 status, time_req, time_rec, temp_minor_status;
335 gss_mechanism mech;
336 gss_union_name_t union_name = NULL;
337 gss_union_cred_t union_cred, new_union_cred;
338 gss_name_t internal_name = GSS_C_NO_NAME;
339 gss_name_t allocated_name = GSS_C_NO_NAME;
340 gss_cred_id_t cred = NULL;
341 gss_OID new_mechs_array = NULL;
342 gss_cred_id_t *new_cred_array = NULL;
343
344 status = val_add_cred_args(minor_status,
345 input_cred_handle,
346 desired_name,
347 desired_mech,
348 cred_usage,
349 initiator_time_req,
350 acceptor_time_req,
351 output_cred_handle,
352 actual_mechs,
353 initiator_time_rec,
354 acceptor_time_rec);
355 if (status != GSS_S_COMPLETE)
356 return (status);
357
358 mech = __gss_get_mechanism(desired_mech);
359 if (!mech)
360 return (GSS_S_BAD_MECH);
361 else if (!mech->gss_acquire_cred)
362 return (GSS_S_UNAVAILABLE);
363
364 if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
365 union_cred = malloc(sizeof (gss_union_cred_desc));
366 if (union_cred == NULL)
367 return (GSS_S_FAILURE);
368
369 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
370 } else {
371 /* Input Cred is non-NULL */
372 union_cred = (gss_union_cred_t)input_cred_handle;
373
374 if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
375 GSS_C_NO_CREDENTIAL) {
376 status = GSS_S_DUPLICATE_ELEMENT;
377 goto errout;
378 }
379
380 /*
381 * If no name was given, determine the name from the
382 * existing credential.
383 */
384 if (desired_name == GSS_C_NO_NAME) {
385 if (gss_import_name(minor_status,
386 &union_cred->auxinfo.name,
387 union_cred->auxinfo.name_type,
388 &allocated_name) == GSS_S_COMPLETE &&
389 (gss_canonicalize_name(minor_status,
390 allocated_name,
391 &mech->mech_type,
392 NULL) == GSS_S_COMPLETE)) {
393 internal_name = allocated_name;
394 }
395 } /* else, get the name from the desired_name below */
396 }
397 if (desired_name != GSS_C_NO_NAME) {
398 /* may need to create a mechanism specific name */
399 union_name = (gss_union_name_t)desired_name;
400
401 if (union_name->mech_type &&
402 g_OID_equal(union_name->mech_type,
403 &mech->mech_type))
404 internal_name = union_name->mech_name;
405 else {
406 if (__gss_import_internal_name(minor_status,
407 &mech->mech_type, union_name,
408 &allocated_name) != GSS_S_COMPLETE) {
409 status = GSS_S_BAD_NAME;
410 goto errout;
411 }
412 internal_name = allocated_name;
413 }
414 }
415
416 if (cred_usage == GSS_C_ACCEPT)
417 time_req = acceptor_time_req;
418 else if (cred_usage == GSS_C_INITIATE)
419 time_req = initiator_time_req;
420 else if (cred_usage == GSS_C_BOTH)
421 time_req = (acceptor_time_req > initiator_time_req) ?
422 acceptor_time_req : initiator_time_req;
423 else
424 time_req = 0;
425
426 status = mech->gss_acquire_cred(mech->context, minor_status,
427 internal_name, time_req,
428 GSS_C_NULL_OID_SET, cred_usage,
429 &cred, NULL, &time_rec);
430
431 if (status != GSS_S_COMPLETE) {
432 map_error(minor_status, mech);
433 goto errout;
434 }
435
436 /* may need to set credential auxinfo structure */
437 if (union_cred->auxinfo.creation_time == 0) {
438 union_cred->auxinfo.creation_time = time(NULL);
439 union_cred->auxinfo.time_rec = time_rec;
440 union_cred->auxinfo.cred_usage = cred_usage;
441
442 /*
443 * If internal_name is GSS_C_NO_NAME a cred with no associated
444 * name was requested: don't set auxinfo.name or auxinfo.name_type.
445 */
446 if (internal_name != GSS_C_NO_NAME) {
447 if ((status = mech->gss_display_name(mech->context,
448 &temp_minor_status, internal_name,
449 &union_cred->auxinfo.name,
450 &union_cred->auxinfo.name_type)) !=
451 GSS_S_COMPLETE)
452 goto errout;
453 }
454 }
455
456 /* now add the new credential elements */
457 new_mechs_array = (gss_OID)
458 malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
459
460 new_cred_array = (gss_cred_id_t *)
461 malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
462
463 if (!new_mechs_array || !new_cred_array) {
464 status = GSS_S_FAILURE;
465 goto errout;
466 }
467
468 if (acceptor_time_rec)
469 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
470 *acceptor_time_rec = time_rec;
471 if (initiator_time_rec)
472 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
473 *initiator_time_rec = time_rec;
474
475 /*
476 * OK, expand the mechanism array and the credential array
477 */
478 (void) memcpy(new_mechs_array, union_cred->mechs_array,
479 sizeof (gss_OID_desc) * union_cred->count);
480 (void) memcpy(new_cred_array, union_cred->cred_array,
481 sizeof (gss_cred_id_t) * union_cred->count);
482
483 new_cred_array[union_cred->count] = cred;
484 if ((new_mechs_array[union_cred->count].elements =
485 malloc(mech->mech_type.length)) == NULL)
486 goto errout;
487
488 g_OID_copy(&new_mechs_array[union_cred->count],
489 &mech->mech_type);
490
491 if (actual_mechs) {
492 *actual_mechs = create_actual_mechs(new_mechs_array,
493 union_cred->count + 1);
494 if (*actual_mechs == NULL) {
495 free(new_mechs_array[union_cred->count].elements);
496 goto errout;
497 }
498 }
499
500 if (output_cred_handle == NULL) {
501 free(union_cred->mechs_array);
502 free(union_cred->cred_array);
503 new_union_cred = union_cred;
504 } else {
505 new_union_cred = malloc(sizeof (gss_union_cred_desc));
506 if (new_union_cred == NULL) {
507 free(new_mechs_array[union_cred->count].elements);
508 goto errout;
509 }
510 *new_union_cred = *union_cred;
511 *output_cred_handle = (gss_cred_id_t)new_union_cred;
512 }
513
514 new_union_cred->mechs_array = new_mechs_array;
515 new_union_cred->cred_array = new_cred_array;
516 new_union_cred->count++;
517
518 /* We're done with the internal name. Free it if we allocated it. */
519
520 if (allocated_name)
521 (void) __gss_release_internal_name(&temp_minor_status,
522 &mech->mech_type,
523 &allocated_name);
524
525 return (GSS_S_COMPLETE);
526
527 errout:
528 if (new_mechs_array)
529 free(new_mechs_array);
530 if (new_cred_array)
531 free(new_cred_array);
532
533 if (cred != NULL && mech->gss_release_cred)
534 mech->gss_release_cred(mech->context,
535 &temp_minor_status, &cred);
536
537 if (allocated_name)
538 (void) __gss_release_internal_name(&temp_minor_status,
539 &mech->mech_type,
540 &allocated_name);
541
542 if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
543 if (union_cred->auxinfo.name.value)
544 free(union_cred->auxinfo.name.value);
545 free(union_cred);
546 }
547
548 return (status);
549 }
550