1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "@(#)g_acquire_cred.c 1.23 04/09/08 SMI"
7
8 /*
9 * glue routine for gss_acquire_cred
10 */
11
12 #include <mechglueP.h>
13 #include <stdio.h>
14 #ifdef HAVE_STDLIB_H
15 #include <stdlib.h>
16 #endif
17 #include <string.h>
18 #include <errno.h>
19 #include <time.h>
20 /* local functions */
21 static gss_OID_set create_actual_mechs(const gss_OID, int);
22
23 static gss_OID_set
24 create_actual_mechs(creds)
25 gss_union_cred_t creds;
26 {
27 gss_OID_set actual_mechs;
28 int i;
29
30 actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
31 if (!actual_mechs)
32 return (NULL);
33
34 actual_mechs->elements = (gss_OID)
35 malloc(sizeof (gss_OID_desc) * creds->count);
36 if (!actual_mechs->elements) {
37 free(actual_mechs);
38 return (NULL);
39 }
40
41 actual_mechs->count = 0;
42
43 for (i = 0; i < creds->count; i++) {
44 actual_mechs->elements[i].elements =
45 creds->mechs_array[i].length;
46 actual_mechs->elements[i].elements = (void *)
47 malloc(creds->mechs_array[i].length);
48 memcpy(actual_mechs->elements[i].elements,
49 creds->mechs_array[i].elements,
50 creds->mechs_array[i].length);
51 }
52
53 return (actual_mechs);
54 }
55
56
57 OM_uint32
58 gss_acquire_cred(minor_status,
59 desired_name,
60 time_req,
61 desired_mechs,
62 cred_usage,
63 output_cred_handle,
64 actual_mechs,
65 time_rec)
66
67 OM_uint32 * minor_status;
68 const gss_name_t desired_name;
69 OM_uint32 time_req;
70 const gss_OID_set desired_mechs;
71 int cred_usage;
72 gss_cred_id_t *output_cred_handle;
73 gss_OID_set * actual_mechs;
74 OM_uint32 * time_rec;
75
76 {
77 OM_uint32 status, temp_minor_status, temp_time_rec = ~0;
78 unsigned int i, j, creds_acquired = 0;
79 int k;
80 gss_union_name_t union_name;
81 gss_name_t internal_name;
82 gss_union_cred_t creds;
83 gss_OID_set_desc default_OID_set;
84 gss_OID_desc default_OID;
85 gss_OID specific_mech_type = 0;
86 gss_mechanism mech;
87
88 /*
89 * This struct is used to keep track of which mech_types are
90 * actually available and to store the credentials returned
91 * from them by each mechanism specific gss_acquire_cred() call.
92 * The results are used to construct the final union_cred
93 * structure returned by the glue layer gss_acquire_cred() call
94 * and the actual_mechs gss_OID_set returned.
95 */
96
97 struct creds_returned {
98 unsigned char available;
99 gss_cred_id_t cred;
100 } *creds_returned;
101
102 gss_initialize();
103
104 /* Set this to NULL for now */
105
106 if (actual_mechs)
107 *actual_mechs = GSS_C_NULL_OID_SET;
108
109 if (minor_status)
110 *minor_status = 0;
111
112 /* No need to continue if we don't have a place to store the creds */
113 if (output_cred_handle == NULL)
114 return GSS_S_COMPLETE;
115
116 /*
117 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
118 * appropriate default.
119 */
120 if (desired_mechs == GSS_C_NULL_OID_SET) {
121 /*
122 * If union_name->mech_type is NULL then we get the default
123 * mechanism; otherwise, we get the mechanism for the
124 * mechanism-specific name.
125 */
126 mech = __gss_get_mechanism(specific_mech_type);
127 if (mech == NULL)
128 return (GSS_S_BAD_MECH);
129 desired_mechs = &default_OID_set;
130 default_OID_set.count = 1 ;
131 default_OID_set.elements = &default_OID;
132 default_OID.length = mech->mech_type.length;
133 default_OID.elements = mech->mech_type.elements;
134 }
135
136 /*
137 * Now allocate the creds returned array. There is one element
138 * for each member of the desired_mechs argument.
139 */
140
141 creds_returned = (struct creds_returned *)
142 malloc(sizeof(struct creds_returned) * desired_mechs->count);
143
144 /*
145 * For each requested mechanism in desired_mechs, determine if it
146 * is supported. If so, mark the corresponding element in
147 * creds_returned->available as 1 and call the mechanism
148 * specific gss_acquire_cred(), placing the returned cred in
149 * creds_returned->cred. If not, mark creds_returned->available as
150 * 0.
151 */
152 status = GSS_S_BAD_MECH;
153 for (j=0; j < desired_mechs->count; j++) {
154 creds_returned[j].available = 0;
155
156 mech = __gss_get_mechanism (&desired_mechs->elements[j]);
157 if (!mech || !mech->gss_acquire_cred)
158 continue;
159 /*
160 * If this is a mechanism-specific name, then only use the
161 * mechanism of the name.
162 */
163 if (specific_mech_type && !g_OID_equal(specific_mech_type,
164 &mech->mech_type))
165 continue;
166 /*
167 * If this is not a mechanism-specific name, then we need to
168 * do an import the external name in union_name first.
169 */
170 if (union_name == 0)
171 internal_name = (gss_name_t) 0;
172 else if (!union_name->mech_type) {
173 if (__gss_import_internal_name(&temp_minor_status,
174 &mech->mech_type,
175 union_name, &internal_name)) {
176 continue;
177 }
178 } else
179 internal_name = union_name->mech_name;
180
181 status = mech->gss_acquire_cred(mech->context, minor_status,
182 internal_name, time_req,
183 desired_mechs, cred_usage,
184 &creds_returned[j].cred,
185 NULL, &temp_time_rec);
186
187 /* Release the internal name, if allocated above */
188 if (union_name && !union_name->mech_type) {
189 (void) __gss_release_internal_name(&temp_minor_status,
190 &mech->mech_type,
191 &internal_name);
192 }
193
194 if (status != GSS_S_COMPLETE)
195 continue;
196
197 /*
198 * Add this into the creds_returned structure, if we got
199 * a good credential for this mechanism.
200 */
201 if (time_rec) {
202 *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec;
203 temp_time_rec = *time_rec;
204 }
205
206 creds_returned[j].available = 1;
207 creds_acquired++;
208
209 /*
210 * If union_name is set, then we're done. Continue, and
211 * declare success. Otherwise, if do an inquire credentials
212 * from the first mechanism that succeeds and use that as the
213 * union name.
214 */
215 if (union_name)
216 continue;
217
218 status = mech->gss_inquire_cred(mech->context, &temp_minor_status,
219 creds_returned[j].cred,
220 &internal_name, 0, 0, 0);
221 if (status) {
222 /* Should never happen */
223 creds_returned[j].available = 0;
224 creds_acquired--;
225 if (mech->gss_release_cred)
226 mech->gss_release_cred(mech->context, minor_status,
227 &creds_returned[j].cred);
228 continue;
229 }
230
231 status = __gss_convert_name_to_union_name(&temp_minor_status, mech,
232 internal_name,
233 (gss_name_t *) &union_name);
234 }
235
236 /*
237 * Now allocate the creds struct, which will be cast as a gss_cred_id_t
238 * and returned in the output_cred_handle argument. If there were
239 * no credentials found, return an error. Also, allocate the
240 * actual_mechs data.
241 */
242 if (creds_acquired == 0) {
243 free (creds_returned);
244 return (status);
245 }
246
247 creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc));
248
249 creds->count = creds_acquired;
250
251 creds->mechs_array = (gss_OID)
252 malloc(sizeof(gss_OID_desc) * creds_acquired);
253
254 creds->cred_array = (gss_cred_id_t *)
255 malloc(sizeof(gss_cred_id_t) * creds_acquired);
256
257 if(actual_mechs != NULL) {
258 *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
259
260 (*actual_mechs)->count = creds_acquired;
261
262 (*actual_mechs)->elements = (gss_OID)
263 malloc(sizeof(gss_OID_desc) * creds_acquired);
264 }
265
266 /*
267 * copy the mechanisms found and their allocated credentials into the
268 * creds structure. At the same time, build up the actual_mechs
269 * data.
270 */
271
272 j = 0;
273
274 for (i=0; i<desired_mechs->count; i++) {
275 if(creds_returned[i].available) {
276
277 creds->mechs_array[j].length =
278 desired_mechs->elements[i].length;
279 creds->mechs_array[j].elements = (void *)
280 malloc(desired_mechs->elements[i].length);
281 memcpy(creds->mechs_array[j].elements,
282 desired_mechs->elements[i].elements,
283 desired_mechs->elements[i].length);
284 creds->cred_array[j] = creds_returned[i].cred;
285 if (actual_mechs) {
286 (*actual_mechs)->elements[j].length =
287 desired_mechs->elements[i].length;
288 (*actual_mechs)->elements[j].elements = (void *)
289 malloc(desired_mechs->elements[i].length);
290 memcpy((*actual_mechs)->elements[j].elements,
291 desired_mechs->elements[i].elements,
292 desired_mechs->elements[i].length);
293 }
294 j++;
295 }
296 }
297
298 /* free the creds_returned struct, since we are done with it. */
299
300 free(creds_returned);
301
302 /* record the information needed for gss_inquire_cred() */
303
304 creds->auxinfo.creation_time = time(0);
305 creds->auxinfo.time_rec = temp_time_rec;
306 creds->auxinfo.cred_usage = cred_usage;
307
308 /*
309 * we can't just record the internal name, desired_name, since
310 * it may be destroyed between now and the time gss_inquire_cred()
311 * is called. So we must record the printable name in a
312 * gss_buffer_t, calling gss_display_name() to fill it in. When
313 * gss_inquire_name() is called, we must then call gss_import_name()
314 * to get the internal name that is required at that point.
315 */
316 if (desired_name) {
317 status = gss_display_name(&temp_minor_status, desired_name,
318 &creds->auxinfo.name,
319 &creds->auxinfo.name_type);
320 if (status) {
321 status = GSS_S_BAD_NAME;
322 goto error_out;
323 }
324 } else {
325 status = gss_display_name(&temp_minor_status, union_name,
326 &creds->auxinfo.name,
327 &creds->auxinfo.name_type);
328 if (status) {
329 status = GSS_S_BAD_NAME;
330 goto error_out;
331 }
332 }
333
334 *output_cred_handle = (gss_cred_id_t) creds;
335 return(GSS_S_COMPLETE);
336
337 error_out:
338 for (k=0; k < creds->count; k++) {
339 free(creds->mechs_array[k].elements);
340 if (actual_mechs)
341 free((*actual_mechs)->elements[k].elements);
342 }
343
344 if (actual_mechs) {
345 free((*actual_mechs)->elements);
346 free(*actual_mechs);
347 *actual_mechs = GSS_C_NULL_OID_SET;
348 }
349 free(creds->cred_array);
350 free(creds->mechs_array);
351 free(creds);
352
353 return(status);
354 }
355
356 /* V2 INTERFACE */
357 OM_uint32
358 gss_add_cred(minor_status, input_cred_handle,
359 desired_name, desired_mech, cred_usage,
360 initiator_time_req, acceptor_time_req,
361 output_cred_handle, actual_mechs,
362 initiator_time_rec, acceptor_time_rec)
363 OM_uint32 *minor_status;
364 const gss_cred_id_t input_cred_handle;
365 const gss_name_t desired_name;
366 const gss_OID desired_mech;
367 gss_cred_usage_t cred_usage;
368 OM_uint32 initiator_time_req;
369 OM_uint32 acceptor_time_req;
370 gss_cred_id_t *output_cred_handle;
371 gss_OID_set *actual_mechs;
372 OM_uint32 *initiator_time_rec;
373 OM_uint32 *acceptor_time_rec;
374 {
375 OM_uint32 status, time_req, time_rec, temp_minor_status;
376 gss_mechanism mech;
377 gss_union_name_t union_name = NULL;
378 gss_union_cred_t union_cred, new_union_cred;
379 gss_name_t internal_name = GSS_C_NO_NAME;
380 gss_name_t allocated_name = GSS_C_NO_NAME;
381 gss_cred_id_t cred = NULL;
382 gss_OID new_mechs_array = NULL;
383 gss_cred_id_t *new_cred_array = NULL;
384
385 if (input_cred_handle == GSS_C_NO_CREDENTIAL)
386 return (GSS_S_NO_CRED);
387
388 union_cred = (gss_union_cred_t) input_cred_handle;
389
390 mech = __gss_get_mechanism(desired_mech);
391 if (!mech)
392 return (GSS_S_BAD_MECH);
393
394 if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
395 GSS_C_NO_CREDENTIAL)
396 return GSS_S_DUPLICATE_ELEMENT;
397
398 union_name = (gss_union_name_t) desired_name;
399 if (union_name->mech_type) {
400 if (!g_OID_equal(desired_mech, union_name->mech_type))
401 return GSS_S_BAD_NAMETYPE;
402 internal_name = union_name->mech_name;
403 } else {
404 if (__gss_import_internal_name(minor_status, desired_mech,
405 union_name, &internal_name))
406 return (GSS_S_BAD_NAME);
407 }
408
409 if (cred_usage == GSS_C_ACCEPT)
410 time_req = acceptor_time_req;
411 else if (cred_usage == GSS_C_INITIATE)
412 time_req = initiator_time_req;
413 else if (cred_usage == GSS_C_BOTH)
414 time_req = (acceptor_time_req > initiator_time_req) ?
415 acceptor_time_req : initiator_time_req;
416
417 status = mech->gss_acquire_cred(mech->context, minor_status,
418 internal_name, time_req,
419 GSS_C_NULL_OID_SET, cred_usage,
420 &cred, NULL, &time_rec);
421 if (status != GSS_S_COMPLETE)
422 goto errout;
423
424 new_mechs_array = (gss_OID)
425 malloc(sizeof(gss_OID_desc) * (union_cred->count+1));
426
427 new_cred_array = (gss_cred_id_t *)
428 malloc(sizeof(gss_cred_id_t) * (union_cred->count+1));
429
430 if (!new_mechs_array || !new_cred_array) {
431 *minor_status = ENOMEM;
432 status = GSS_S_FAILURE;
433 goto errout;
434 }
435
436
437 if (acceptor_time_rec)
438 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
439 *acceptor_time_rec = time_rec;
440 if (initiator_time_rec)
441 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
442 *initiator_time_rec = time_rec;
443
444 /*
445 * OK, expand the mechanism array in the union credentials
446 * (Look for the union label...)
447 */
448 memcpy(new_mechs_array, union_cred->mechs_array,
449 sizeof(gss_OID_desc) * union_cred->count);
450 memcpy(new_cred_array, union_cred->cred_array,
451 sizeof(gss_cred_id_t) * union_cred->count);
452
453 new_cred_array[union_cred->count] = cred;
454 new_mechs_array[union_cred->count].length = desired_mech->length;
455 new_mechs_array[union_cred->count].elements = malloc(desired_mech->length);
456 if (!new_mechs_array[union_cred->count].elements) {
457 *minor_status = ENOMEM;
458 goto errout;
459 }
460 memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements,
461 desired_mech->length);
462
463 if (output_cred_handle == NULL) {
464 free(union_cred->mechs_array);
465 free(union_cred->cred_array);
466 new_union_cred = union_cred;
467 } else {
468 new_union_cred = malloc(sizeof(gss_union_cred_desc));
469 if (new_union_cred == NULL) {
470 *minor_status = ENOMEM;
471 goto errout;
472 }
473 *new_union_cred = *union_cred;
474 *output_cred_handle = new_union_cred;
475 }
476 new_union_cred->mechs_array = new_mechs_array;
477 new_union_cred->cred_array = new_cred_array;
478 new_union_cred->count++;
479 new_mechs_array = 0;
480 new_cred_array = 0;
481
482 if (actual_mechs)
483 *actual_mechs = create_actual_mechs(new_union_cred);
484
485 status = GSS_S_COMPLETE;
486
487 errout:
488 if (new_mechs_array)
489 free(new_mechs_array);
490 if (new_cred_array)
491 free(new_cred_array);
492 if (!union_name->mech_type) {
493 (void) __gss_release_internal_name(&temp_minor_status,
494 desired_mech, &internal_name);
495 }
496
497 return(status);
498 }
|
1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI"
7
8 /*
9 * glue routine for gss_acquire_cred
10 */
11
12 #include <mechglueP.h>
13 #include <stdio.h>
14 #ifdef HAVE_STDLIB_H
15 #include <stdlib.h>
16 #endif
17 #include <string.h>
18 #include <errno.h>
19 #include <time.h>
20 /* local functions */
21 static gss_OID_set create_actual_mechs(const gss_OID, int);
22
23 static gss_OID_set
24 create_actual_mechs(mechs_array, count)
25 const gss_OID mechs_array;
26 int count;
27 {
28 gss_OID_set actual_mechs;
29 int i;
30 OM_uint32 minor;
31
32 actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
33 if (!actual_mechs)
34 return (NULL);
35
36 actual_mechs->elements = (gss_OID)
37 malloc(sizeof (gss_OID_desc) * count);
38 if (!actual_mechs->elements) {
39 free(actual_mechs);
40 return (NULL);
41 }
42
43 actual_mechs->count = 0;
44
45 for (i = 0; i < count; i++) {
46 actual_mechs->elements[i].elements = (void *)
47 malloc(mechs_array[i].length);
48 if (actual_mechs->elements[i].elements == NULL) {
49 (void) gss_release_oid_set(&minor, &actual_mechs);
50 return (NULL);
51 }
52 g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
53 actual_mechs->count++;
54 }
55
56 return (actual_mechs);
57 }
58
59
60 OM_uint32
61 gss_acquire_cred(minor_status,
62 desired_name,
63 time_req,
64 desired_mechs,
65 cred_usage,
66 output_cred_handle,
67 actual_mechs,
68 time_rec)
69
70 OM_uint32 * minor_status;
71 const gss_name_t desired_name;
72 OM_uint32 time_req;
73 const gss_OID_set desired_mechs;
74 int cred_usage;
75 gss_cred_id_t *output_cred_handle;
76 gss_OID_set * actual_mechs;
77 OM_uint32 * time_rec;
78
79 {
80 OM_uint32 major = GSS_S_FAILURE;
81 OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
82 gss_OID_set_desc default_OID_set;
83 gss_OID_set mechs;
84 gss_OID_desc default_OID;
85 gss_mechanism mech;
86 int i;
87 gss_union_cred_t creds;
88
89 /* start by checking parameters */
90 if (!minor_status)
91 return (GSS_S_CALL_INACCESSIBLE_WRITE);
92 *minor_status = 0;
93
94 if (!output_cred_handle)
95 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
96
97 *output_cred_handle = GSS_C_NO_CREDENTIAL;
98
99 /* Set output parameters to NULL for now */
100 if (actual_mechs)
101 *actual_mechs = GSS_C_NULL_OID_SET;
102
103 if (time_rec)
104 *time_rec = 0;
105
106 /*
107 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
108 * appropriate default. We use the first mechanism in the
109 * mechansim list as the default. This set is created with
110 * statics thus needs not be freed
111 */
112 if (desired_mechs == GSS_C_NULL_OID_SET) {
113 mech = __gss_get_mechanism(NULL);
114 if (mech == NULL)
115 return (GSS_S_BAD_MECH);
116
117 mechs = &default_OID_set;
118 default_OID_set.count = 1;
119 default_OID_set.elements = &default_OID;
120 default_OID.length = mech->mech_type.length;
121 default_OID.elements = mech->mech_type.elements;
122 } else
123 mechs = desired_mechs;
124
125 if (mechs->count == NULL)
126 return (GSS_S_BAD_MECH);
127
128 /* allocate the output credential structure */
129 creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
130 if (creds == NULL)
131 return (GSS_S_FAILURE);
132
133 /* initialize to 0s */
134 (void) memset(creds, 0, sizeof (gss_union_cred_desc));
135
136 /* for each requested mech attempt to obtain a credential */
137 for (i = 0; i < mechs->count; i++) {
138 major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
139 desired_name,
140 &mechs->elements[i],
141 cred_usage, time_req, time_req, NULL,
142 NULL, &initTimeOut, &acceptTimeOut);
143 if (major == GSS_S_COMPLETE) {
144 /* update the credential's time */
145 if (cred_usage == GSS_C_ACCEPT) {
146 if (outTime > acceptTimeOut)
147 outTime = acceptTimeOut;
148 } else if (cred_usage == GSS_C_INITIATE) {
149 if (outTime > initTimeOut)
150 outTime = initTimeOut;
151 } else {
152 /*
153 * time_rec is the lesser of the
154 * init/accept times
155 */
156 if (initTimeOut > acceptTimeOut)
157 outTime = (outTime > acceptTimeOut) ?
158 acceptTimeOut : outTime;
159 else
160 outTime = (outTime > initTimeOut) ?
161 initTimeOut : outTime;
162 }
163 }
164 } /* for */
165
166 /* ensure that we have at least one credential element */
167 if (creds->count < 1) {
168 free(creds);
169 return (major);
170 }
171
172 /*
173 * fill in output parameters
174 * setup the actual mechs output parameter
175 */
176 if (actual_mechs != NULL) {
177 if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
178 creds->count)) == NULL) {
179 (void) gss_release_cred(minor_status,
180 (gss_cred_id_t *)&creds);
181 *minor_status = 0;
182 return (GSS_S_FAILURE);
183 }
184 }
185
186 if (time_rec)
187 *time_rec = outTime;
188
189
190 *output_cred_handle = (gss_cred_id_t)creds;
191 return (GSS_S_COMPLETE);
192 }
193
194 /* V2 INTERFACE */
195 OM_uint32
196 gss_add_cred(minor_status, input_cred_handle,
197 desired_name, desired_mech, cred_usage,
198 initiator_time_req, acceptor_time_req,
199 output_cred_handle, actual_mechs,
200 initiator_time_rec, acceptor_time_rec)
201 OM_uint32 *minor_status;
202 const gss_cred_id_t input_cred_handle;
203 const gss_name_t desired_name;
204 const gss_OID desired_mech;
205 gss_cred_usage_t cred_usage;
206 OM_uint32 initiator_time_req;
207 OM_uint32 acceptor_time_req;
208 gss_cred_id_t *output_cred_handle;
209 gss_OID_set *actual_mechs;
210 OM_uint32 *initiator_time_rec;
211 OM_uint32 *acceptor_time_rec;
212 {
213 OM_uint32 status, time_req, time_rec, temp_minor_status;
214 gss_mechanism mech;
215 gss_union_name_t union_name = NULL;
216 gss_union_cred_t union_cred, new_union_cred;
217 gss_name_t internal_name = GSS_C_NO_NAME;
218 gss_name_t allocated_name = GSS_C_NO_NAME;
219 gss_cred_id_t cred = NULL;
220 gss_OID new_mechs_array = NULL;
221 gss_cred_id_t *new_cred_array = NULL;
222
223 /* check input parameters */
224 if (minor_status == NULL)
225 return (GSS_S_CALL_INACCESSIBLE_WRITE);
226 *minor_status = 0;
227
228 if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
229 output_cred_handle == NULL)
230 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
231
232 if (output_cred_handle)
233 *output_cred_handle = GSS_C_NO_CREDENTIAL;
234
235 if (actual_mechs)
236 *actual_mechs = NULL;
237
238 if (acceptor_time_rec)
239 *acceptor_time_rec = 0;
240
241 if (initiator_time_rec)
242 *initiator_time_rec = 0;
243
244 mech = __gss_get_mechanism(desired_mech);
245 if (!mech)
246 return (GSS_S_BAD_MECH);
247 else if (!mech->gss_acquire_cred)
248 return (GSS_S_UNAVAILABLE);
249
250 if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
251 union_cred = malloc(sizeof (gss_union_cred_desc));
252 if (union_cred == NULL)
253 return (GSS_S_FAILURE);
254
255 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
256
257 /* for default credentials we will use GSS_C_NO_NAME */
258 internal_name = GSS_C_NO_NAME;
259 } else {
260 union_cred = (gss_union_cred_t)input_cred_handle;
261 if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
262 GSS_C_NO_CREDENTIAL)
263 return (GSS_S_DUPLICATE_ELEMENT);
264
265 /* may need to create a mechanism specific name */
266 if (desired_name) {
267 union_name = (gss_union_name_t)desired_name;
268 if (union_name->mech_type &&
269 g_OID_equal(union_name->mech_type,
270 &mech->mech_type))
271 internal_name = union_name->mech_name;
272 else {
273 if (__gss_import_internal_name(minor_status,
274 &mech->mech_type, union_name,
275 &allocated_name) != GSS_S_COMPLETE)
276 return (GSS_S_BAD_NAME);
277 internal_name = allocated_name;
278 }
279 }
280 }
281
282
283 if (cred_usage == GSS_C_ACCEPT)
284 time_req = acceptor_time_req;
285 else if (cred_usage == GSS_C_INITIATE)
286 time_req = initiator_time_req;
287 else if (cred_usage == GSS_C_BOTH)
288 time_req = (acceptor_time_req > initiator_time_req) ?
289 acceptor_time_req : initiator_time_req;
290
291 status = mech->gss_acquire_cred(mech->context, minor_status,
292 internal_name, time_req,
293 GSS_C_NULL_OID_SET, cred_usage,
294 &cred, NULL, &time_rec);
295
296 if (status != GSS_S_COMPLETE)
297 goto errout;
298
299 /* may need to set credential auxinfo strucutre */
300 if (union_cred->auxinfo.creation_time == 0) {
301 union_cred->auxinfo.creation_time = time(NULL);
302 union_cred->auxinfo.time_rec = time_rec;
303 union_cred->auxinfo.cred_usage = cred_usage;
304
305 /*
306 * we must set the name; if name is not supplied
307 * we must do inquire cred to get it
308 */
309 if (internal_name == NULL) {
310 if (mech->gss_inquire_cred == NULL ||
311 ((status = mech->gss_inquire_cred(
312 mech->context,
313 &temp_minor_status, cred,
314 &allocated_name, NULL, NULL,
315 NULL)) != GSS_S_COMPLETE))
316 goto errout;
317 internal_name = allocated_name;
318 }
319
320 if ((status = mech->gss_display_name(mech->context,
321 &temp_minor_status, internal_name,
322 &union_cred->auxinfo.name,
323 &union_cred->auxinfo.name_type)) !=
324 GSS_S_COMPLETE)
325 goto errout;
326 }
327
328 /* now add the new credential elements */
329 new_mechs_array = (gss_OID)
330 malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
331
332 new_cred_array = (gss_cred_id_t *)
333 malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
334
335 if (!new_mechs_array || !new_cred_array) {
336 status = GSS_S_FAILURE;
337 goto errout;
338 }
339
340 if (acceptor_time_rec)
341 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
342 *acceptor_time_rec = time_rec;
343 if (initiator_time_rec)
344 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
345 *initiator_time_rec = time_rec;
346
347 /*
348 * OK, expand the mechanism array and the credential array
349 */
350 (void) memcpy(new_mechs_array, union_cred->mechs_array,
351 sizeof (gss_OID_desc) * union_cred->count);
352 (void) memcpy(new_cred_array, union_cred->cred_array,
353 sizeof (gss_cred_id_t) * union_cred->count);
354
355 new_cred_array[union_cred->count] = cred;
356 if ((new_mechs_array[union_cred->count].elements =
357 malloc(mech->mech_type.length)) == NULL)
358 goto errout;
359
360 g_OID_copy(&new_mechs_array[union_cred->count],
361 &mech->mech_type);
362
363 if (actual_mechs) {
364 *actual_mechs = create_actual_mechs(new_mechs_array,
365 union_cred->count + 1);
366 if (*actual_mechs == NULL) {
367 free(new_mechs_array[union_cred->count].elements);
368 goto errout;
369 }
370 }
371
372 if (output_cred_handle == NULL) {
373 free(union_cred->mechs_array);
374 free(union_cred->cred_array);
375 new_union_cred = union_cred;
376 } else {
377 new_union_cred = malloc(sizeof (gss_union_cred_desc));
378 if (new_union_cred == NULL) {
379 free(new_mechs_array[union_cred->count].elements);
380 goto errout;
381 }
382 *new_union_cred = *union_cred;
383 *output_cred_handle = (gss_cred_id_t)new_union_cred;
384 }
385
386 new_union_cred->mechs_array = new_mechs_array;
387 new_union_cred->cred_array = new_cred_array;
388 new_union_cred->count++;
389
390 /* We're done with the internal name. Free it if we allocated it. */
391
392 if (allocated_name)
393 (void) __gss_release_internal_name(&temp_minor_status,
394 &mech->mech_type,
395 &allocated_name);
396
397 return (GSS_S_COMPLETE);
398
399 errout:
400 if (new_mechs_array)
401 free(new_mechs_array);
402 if (new_cred_array)
403 free(new_cred_array);
404
405 if (cred != NULL && mech->gss_release_cred)
406 mech->gss_release_cred(mech->context,
407 &temp_minor_status, &cred);
408
409 if (allocated_name)
410 (void) __gss_release_internal_name(&temp_minor_status,
411 &mech->mech_type,
412 &allocated_name);
413
414 if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
415 if (union_cred->auxinfo.name.value)
416 free(union_cred->auxinfo.name.value);
417 free(union_cred);
418 }
419
420 return (status);
421 }
|