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.
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.
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]
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
26 * glue routine for gss_acquire_cred
28 #include <mechglueP.h>
29 #include "gssapiP_generic.h"
39 static gss_OID_set
create_actual_mechs(const gss_OID
, int);
42 create_actual_mechs(mechs_array
, count
)
43 const gss_OID mechs_array
;
46 gss_OID_set actual_mechs
;
50 actual_mechs
= (gss_OID_set
) malloc(sizeof (gss_OID_set_desc
));
54 actual_mechs
->elements
= (gss_OID
)
55 malloc(sizeof (gss_OID_desc
) * count
);
56 if (!actual_mechs
->elements
) {
61 actual_mechs
->count
= 0;
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
);
70 g_OID_copy(&actual_mechs
->elements
[i
], &mechs_array
[i
]);
71 actual_mechs
->count
++;
74 return (actual_mechs
);
79 OM_uint32
*minor_status
,
81 gss_name_t desired_name
,
85 gss_OID_set desired_mechs
,
87 gss_cred_id_t
*output_cred_handle
,
88 gss_OID_set
*actual_mechs
,
92 /* Initialize outputs. */
94 if (minor_status
!= NULL
)
97 if (output_cred_handle
!= NULL
)
98 *output_cred_handle
= GSS_C_NO_CREDENTIAL
;
100 if (actual_mechs
!= NULL
)
101 *actual_mechs
= GSS_C_NULL_OID_SET
;
103 if (time_rec
!= NULL
)
106 /* Validate arguments. */
108 if (minor_status
== NULL
)
109 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
111 if (output_cred_handle
== NULL
)
112 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
114 if (cred_usage
!= GSS_C_ACCEPT
115 && cred_usage
!= GSS_C_INITIATE
116 && cred_usage
!= GSS_C_BOTH
) {
118 *minor_status
= EINVAL
;
119 map_errcode(minor_status
);
121 return GSS_S_FAILURE
;
124 return (GSS_S_COMPLETE
);
128 gss_acquire_cred(minor_status
,
137 OM_uint32
* minor_status
;
138 const gss_name_t desired_name
;
140 const gss_OID_set desired_mechs
;
142 gss_cred_id_t
*output_cred_handle
;
143 gss_OID_set
* actual_mechs
;
144 OM_uint32
* time_rec
;
147 OM_uint32 major
= GSS_S_FAILURE
;
148 OM_uint32 initTimeOut
, acceptTimeOut
, outTime
= GSS_C_INDEFINITE
;
149 gss_OID_set_desc default_OID_set
;
151 gss_OID_desc default_OID
;
154 gss_union_cred_t creds
;
156 major
= val_acq_cred_args(minor_status
,
164 if (major
!= GSS_S_COMPLETE
)
167 /* Initial value needed below. */
168 major
= GSS_S_FAILURE
;
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
176 if (desired_mechs
== GSS_C_NULL_OID_SET
) {
177 mech
= __gss_get_mechanism(NULL
);
179 return (GSS_S_BAD_MECH
);
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
;
187 mechs
= desired_mechs
;
189 if (mechs
->count
== NULL
)
190 return (GSS_S_BAD_MECH
);
192 /* allocate the output credential structure */
193 creds
= (gss_union_cred_t
)malloc(sizeof (gss_union_cred_desc
));
195 return (GSS_S_FAILURE
);
197 /* initialize to 0s */
198 (void) memset(creds
, 0, sizeof (gss_union_cred_desc
));
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
,
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
;
217 * time_rec is the lesser of the
220 if (initTimeOut
> acceptTimeOut
)
221 outTime
= (outTime
> acceptTimeOut
) ?
222 acceptTimeOut
: outTime
;
224 outTime
= (outTime
> initTimeOut
) ?
225 initTimeOut
: outTime
;
230 /* ensure that we have at least one credential element */
231 if (creds
->count
< 1) {
237 * fill in output parameters
238 * setup the actual mechs output parameter
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
);
246 return (GSS_S_FAILURE
);
254 *output_cred_handle
= (gss_cred_id_t
)creds
;
255 return (GSS_S_COMPLETE
);
260 OM_uint32
*minor_status
,
261 gss_cred_id_t input_cred_handle
,
263 gss_name_t desired_name
,
265 gss_OID desired_mech
,
266 gss_cred_usage_t cred_usage
,
268 OM_uint32 initiator_time_req
,
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
)
277 /* Initialize outputs. */
279 if (minor_status
!= NULL
)
282 if (output_cred_handle
!= NULL
)
283 *output_cred_handle
= GSS_C_NO_CREDENTIAL
;
285 if (actual_mechs
!= NULL
)
286 *actual_mechs
= GSS_C_NO_OID_SET
;
288 if (acceptor_time_rec
!= NULL
)
289 *acceptor_time_rec
= 0;
291 if (initiator_time_rec
!= NULL
)
292 *initiator_time_rec
= 0;
293 /* Validate arguments. */
295 if (minor_status
== NULL
)
296 return (GSS_S_CALL_INACCESSIBLE_WRITE
);
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
);
302 if (cred_usage
!= GSS_C_ACCEPT
303 && cred_usage
!= GSS_C_INITIATE
304 && cred_usage
!= GSS_C_BOTH
) {
306 *minor_status
= EINVAL
;
307 map_errcode(minor_status
);
309 return GSS_S_FAILURE
;
312 return (GSS_S_COMPLETE
);
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
;
334 OM_uint32 status
, time_req
, time_rec
, temp_minor_status
;
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
;
344 status
= val_add_cred_args(minor_status
,
355 if (status
!= GSS_S_COMPLETE
)
358 mech
= __gss_get_mechanism(desired_mech
);
360 return (GSS_S_BAD_MECH
);
361 else if (!mech
->gss_acquire_cred
)
362 return (GSS_S_UNAVAILABLE
);
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
);
369 (void) memset(union_cred
, 0, sizeof (gss_union_cred_desc
));
371 /* Input Cred is non-NULL */
372 union_cred
= (gss_union_cred_t
)input_cred_handle
;
374 if (__gss_get_mechanism_cred(union_cred
, desired_mech
) !=
375 GSS_C_NO_CREDENTIAL
) {
376 status
= GSS_S_DUPLICATE_ELEMENT
;
381 * If no name was given, determine the name from the
382 * existing credential.
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
,
392 NULL
) == GSS_S_COMPLETE
)) {
393 internal_name
= allocated_name
;
395 } /* else, get the name from the desired_name below */
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
;
401 if (union_name
->mech_type
&&
402 g_OID_equal(union_name
->mech_type
,
404 internal_name
= union_name
->mech_name
;
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
;
412 internal_name
= allocated_name
;
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
;
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
);
431 if (status
!= GSS_S_COMPLETE
) {
432 map_error(minor_status
, mech
);
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
;
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.
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
)) !=
456 /* now add the new credential elements */
457 new_mechs_array
= (gss_OID
)
458 malloc(sizeof (gss_OID_desc
) * (union_cred
->count
+1));
460 new_cred_array
= (gss_cred_id_t
*)
461 malloc(sizeof (gss_cred_id_t
) * (union_cred
->count
+1));
463 if (!new_mechs_array
|| !new_cred_array
) {
464 status
= GSS_S_FAILURE
;
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
;
476 * OK, expand the mechanism array and the credential array
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
);
483 new_cred_array
[union_cred
->count
] = cred
;
484 if ((new_mechs_array
[union_cred
->count
].elements
=
485 malloc(mech
->mech_type
.length
)) == NULL
)
488 g_OID_copy(&new_mechs_array
[union_cred
->count
],
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
);
500 if (output_cred_handle
== NULL
) {
501 free(union_cred
->mechs_array
);
502 free(union_cred
->cred_array
);
503 new_union_cred
= union_cred
;
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
);
510 *new_union_cred
= *union_cred
;
511 *output_cred_handle
= (gss_cred_id_t
)new_union_cred
;
514 new_union_cred
->mechs_array
= new_mechs_array
;
515 new_union_cred
->cred_array
= new_cred_array
;
516 new_union_cred
->count
++;
518 /* We're done with the internal name. Free it if we allocated it. */
521 (void) __gss_release_internal_name(&temp_minor_status
,
525 return (GSS_S_COMPLETE
);
529 free(new_mechs_array
);
531 free(new_cred_array
);
533 if (cred
!= NULL
&& mech
->gss_release_cred
)
534 mech
->gss_release_cred(mech
->context
,
535 &temp_minor_status
, &cred
);
538 (void) __gss_release_internal_name(&temp_minor_status
,
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
);