1 /* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
2
3 /*
4 * Copyright 2009 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26 /*
27 * Copyright 1996 by Sun Microsystems, Inc.
28 *
29 * Permission to use, copy, modify, distribute, and sell this software
30 * and its documentation for any purpose is hereby granted without fee,
31 * provided that the above copyright notice appears in all copies and
32 * that both that copyright notice and this permission notice appear in
33 * supporting documentation, and that the name of Sun Microsystems not be used
34 * in advertising or publicity pertaining to distribution of the software
35 * without specific, written prior permission. Sun Microsystems makes no
36 * representations about the suitability of this software for any
37 * purpose. It is provided "as is" without express or implied warranty.
38 *
39 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
40 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
41 * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
42 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
43 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
44 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
45 * PERFORMANCE OF THIS SOFTWARE.
46 */
47
48 /* Glue routine for gss_acquire_cred_impersonate_name */
49
50 #include "mglueP.h"
51 #include <stdio.h>
52 #ifdef HAVE_STDLIB_H
53 #include <stdlib.h>
54 #endif
55 #include <string.h>
56 #include <errno.h>
57 #include <time.h>
58
59 static OM_uint32
val_acq_cred_impersonate_name_args(OM_uint32 * minor_status,const gss_cred_id_t impersonator_cred_handle,const gss_name_t desired_name,OM_uint32 time_req,gss_OID_set desired_mechs,gss_cred_usage_t cred_usage,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * time_rec)60 val_acq_cred_impersonate_name_args(
61 OM_uint32 *minor_status,
62 const gss_cred_id_t impersonator_cred_handle,
63 const gss_name_t desired_name,
64 OM_uint32 time_req,
65 gss_OID_set desired_mechs,
66 gss_cred_usage_t cred_usage,
67 gss_cred_id_t *output_cred_handle,
68 gss_OID_set *actual_mechs,
69 OM_uint32 *time_rec)
70 {
71
72 /* Initialize outputs. */
73
74 if (minor_status != NULL)
75 *minor_status = 0;
76
77 if (output_cred_handle != NULL)
78 *output_cred_handle = GSS_C_NO_CREDENTIAL;
79
80 if (actual_mechs != NULL)
81 *actual_mechs = GSS_C_NULL_OID_SET;
82
83 if (time_rec != NULL)
84 *time_rec = 0;
85
86 /* Validate arguments. */
87
88 if (minor_status == NULL)
89 return (GSS_S_CALL_INACCESSIBLE_WRITE);
90
91 if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
92 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
93
94 if (desired_name == GSS_C_NO_NAME)
95 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
96
97 if (output_cred_handle == NULL)
98 return (GSS_S_CALL_INACCESSIBLE_WRITE);
99
100 if (cred_usage != GSS_C_ACCEPT
101 && cred_usage != GSS_C_INITIATE
102 && cred_usage != GSS_C_BOTH) {
103 if (minor_status) {
104 *minor_status = EINVAL;
105 map_errcode(minor_status);
106 }
107 return GSS_S_FAILURE;
108 }
109
110 return (GSS_S_COMPLETE);
111 }
112
113
114 OM_uint32 KRB5_CALLCONV
gss_acquire_cred_impersonate_name(OM_uint32 * minor_status,const gss_cred_id_t impersonator_cred_handle,const gss_name_t desired_name,OM_uint32 time_req,const gss_OID_set desired_mechs,gss_cred_usage_t cred_usage,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * time_rec)115 gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
116 const gss_cred_id_t impersonator_cred_handle,
117 const gss_name_t desired_name,
118 OM_uint32 time_req,
119 const gss_OID_set desired_mechs,
120 gss_cred_usage_t cred_usage,
121 gss_cred_id_t *output_cred_handle,
122 gss_OID_set *actual_mechs,
123 OM_uint32 *time_rec)
124 {
125 OM_uint32 major = GSS_S_FAILURE;
126 OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
127 gss_OID_set_desc default_OID_set;
128 gss_OID_set mechs;
129 gss_OID_desc default_OID;
130 gss_mechanism mech;
131 unsigned int i;
132 gss_union_cred_t creds;
133
134 major = val_acq_cred_impersonate_name_args(minor_status,
135 impersonator_cred_handle,
136 desired_name,
137 time_req,
138 desired_mechs,
139 cred_usage,
140 output_cred_handle,
141 actual_mechs,
142 time_rec);
143 if (major != GSS_S_COMPLETE)
144 return (major);
145
146 /* Initial value needed below. */
147 major = GSS_S_FAILURE;
148
149 /*
150 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
151 * appropriate default. We use the first mechanism in the
152 * mechanism list as the default. This set is created with
153 * statics thus needs not be freed
154 */
155 if(desired_mechs == GSS_C_NULL_OID_SET) {
156 mech = gssint_get_mechanism(NULL);
157 if (mech == NULL)
158 return (GSS_S_BAD_MECH);
159
160 mechs = &default_OID_set;
161 default_OID_set.count = 1;
162 default_OID_set.elements = &default_OID;
163 default_OID.length = mech->mech_type.length;
164 default_OID.elements = mech->mech_type.elements;
165 } else
166 mechs = desired_mechs;
167
168 if (mechs->count == 0)
169 return (GSS_S_BAD_MECH);
170
171 /* allocate the output credential structure */
172 creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
173 if (creds == NULL)
174 return (GSS_S_FAILURE);
175
176 /* initialize to 0s */
177 (void) memset(creds, 0, sizeof (gss_union_cred_desc));
178 creds->loopback = creds;
179
180 /* for each requested mech attempt to obtain a credential */
181 for (i = 0; i < mechs->count; i++) {
182 major = gss_add_cred_impersonate_name(minor_status,
183 (gss_cred_id_t)creds,
184 impersonator_cred_handle,
185 desired_name,
186 &mechs->elements[i],
187 cred_usage,
188 time_req,
189 time_req, NULL,
190 NULL,
191 &initTimeOut,
192 &acceptTimeOut);
193 if (major == GSS_S_COMPLETE) {
194 /* update the credential's time */
195 if (cred_usage == GSS_C_ACCEPT) {
196 if (outTime > acceptTimeOut)
197 outTime = acceptTimeOut;
198 } else if (cred_usage == GSS_C_INITIATE) {
199 if (outTime > initTimeOut)
200 outTime = initTimeOut;
201 } else {
202 /*
203 * time_rec is the lesser of the
204 * init/accept times
205 */
206 if (initTimeOut > acceptTimeOut)
207 outTime = (outTime > acceptTimeOut) ?
208 acceptTimeOut : outTime;
209 else
210 outTime = (outTime > initTimeOut) ?
211 initTimeOut : outTime;
212 }
213 }
214 } /* for */
215
216 /* ensure that we have at least one credential element */
217 if (creds->count < 1) {
218 free(creds);
219 return (major);
220 }
221
222 /*
223 * fill in output parameters
224 * setup the actual mechs output parameter
225 */
226 if (actual_mechs != NULL) {
227 gss_OID_set_desc oids;
228
229 oids.count = creds->count;
230 oids.elements = creds->mechs_array;
231
232 major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
233 if (GSS_ERROR(major)) {
234 (void) gss_release_cred(minor_status,
235 (gss_cred_id_t *)&creds);
236 return (major);
237 }
238 }
239
240 if (time_rec)
241 *time_rec = outTime;
242
243
244 creds->loopback = creds;
245 *output_cred_handle = (gss_cred_id_t)creds;
246 return (GSS_S_COMPLETE);
247 }
248
249 static OM_uint32
val_add_cred_impersonate_name_args(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,const gss_cred_id_t impersonator_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)250 val_add_cred_impersonate_name_args(
251 OM_uint32 *minor_status,
252 gss_cred_id_t input_cred_handle,
253 const gss_cred_id_t impersonator_cred_handle,
254 gss_name_t desired_name,
255 gss_OID desired_mech,
256 gss_cred_usage_t cred_usage,
257 OM_uint32 initiator_time_req,
258 OM_uint32 acceptor_time_req,
259 gss_cred_id_t *output_cred_handle,
260 gss_OID_set *actual_mechs,
261 OM_uint32 *initiator_time_rec,
262 OM_uint32 *acceptor_time_rec)
263 {
264
265 /* Initialize outputs. */
266
267 if (minor_status != NULL)
268 *minor_status = 0;
269
270 if (output_cred_handle != NULL)
271 *output_cred_handle = GSS_C_NO_CREDENTIAL;
272
273 if (actual_mechs != NULL)
274 *actual_mechs = GSS_C_NO_OID_SET;
275
276 if (acceptor_time_rec != NULL)
277 *acceptor_time_rec = 0;
278
279 if (initiator_time_rec != NULL)
280 *initiator_time_rec = 0;
281
282 /* Validate arguments. */
283
284 if (minor_status == NULL)
285 return (GSS_S_CALL_INACCESSIBLE_WRITE);
286
287 if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
288 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
289
290 if (desired_name == GSS_C_NO_NAME)
291 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
292
293 if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
294 output_cred_handle == NULL)
295 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
296
297 if (cred_usage != GSS_C_ACCEPT
298 && cred_usage != GSS_C_INITIATE
299 && cred_usage != GSS_C_BOTH) {
300 if (minor_status) {
301 *minor_status = EINVAL;
302 map_errcode(minor_status);
303 }
304 return GSS_S_FAILURE;
305 }
306
307 return (GSS_S_COMPLETE);
308 }
309
310
311 /* V2 KRB5_CALLCONV */
312 OM_uint32 KRB5_CALLCONV
gss_add_cred_impersonate_name(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,const gss_cred_id_t impersonator_cred_handle,const gss_name_t desired_name,const 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)313 gss_add_cred_impersonate_name(OM_uint32 *minor_status,
314 gss_cred_id_t input_cred_handle,
315 const gss_cred_id_t impersonator_cred_handle,
316 const gss_name_t desired_name,
317 const gss_OID desired_mech,
318 gss_cred_usage_t cred_usage,
319 OM_uint32 initiator_time_req,
320 OM_uint32 acceptor_time_req,
321 gss_cred_id_t *output_cred_handle,
322 gss_OID_set *actual_mechs,
323 OM_uint32 *initiator_time_rec,
324 OM_uint32 *acceptor_time_rec)
325 {
326 OM_uint32 status, temp_minor_status;
327 OM_uint32 time_req, time_rec;
328 gss_union_name_t union_name;
329 gss_union_cred_t new_union_cred, union_cred;
330 gss_cred_id_t mech_impersonator_cred;
331 gss_name_t internal_name = GSS_C_NO_NAME;
332 gss_name_t allocated_name = GSS_C_NO_NAME;
333 gss_mechanism mech;
334 gss_cred_id_t cred = NULL;
335 gss_OID new_mechs_array = NULL;
336 gss_cred_id_t * new_cred_array = NULL;
337 gss_OID_set target_mechs = GSS_C_NO_OID_SET;
338 gss_OID selected_mech = GSS_C_NO_OID;
339
340 status = val_add_cred_impersonate_name_args(minor_status,
341 input_cred_handle,
342 impersonator_cred_handle,
343 desired_name,
344 desired_mech,
345 cred_usage,
346 initiator_time_req,
347 acceptor_time_req,
348 output_cred_handle,
349 actual_mechs,
350 initiator_time_rec,
351 acceptor_time_rec);
352 if (status != GSS_S_COMPLETE)
353 return (status);
354
355 status = gssint_select_mech_type(minor_status, desired_mech,
356 &selected_mech);
357 if (status != GSS_S_COMPLETE)
358 return status;
359
360 mech = gssint_get_mechanism(selected_mech);
361 if (!mech)
362 return GSS_S_BAD_MECH;
363 else if (!mech->gss_acquire_cred_impersonate_name)
364 return (GSS_S_UNAVAILABLE);
365
366 if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
367 union_cred = malloc(sizeof (gss_union_cred_desc));
368 if (union_cred == NULL)
369 return (GSS_S_FAILURE);
370
371 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
372
373 /* for default credentials we will use GSS_C_NO_NAME */
374 internal_name = GSS_C_NO_NAME;
375 } else {
376 union_cred = (gss_union_cred_t)input_cred_handle;
377 if (gssint_get_mechanism_cred(union_cred, selected_mech) !=
378 GSS_C_NO_CREDENTIAL)
379 return (GSS_S_DUPLICATE_ELEMENT);
380 }
381
382 mech_impersonator_cred =
383 gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
384 selected_mech);
385 if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
386 return (GSS_S_NO_CRED);
387
388 /* may need to create a mechanism specific name */
389 union_name = (gss_union_name_t)desired_name;
390 if (union_name->mech_type &&
391 g_OID_equal(union_name->mech_type, selected_mech))
392 internal_name = union_name->mech_name;
393 else {
394 if (gssint_import_internal_name(minor_status,
395 selected_mech, union_name,
396 &allocated_name) != GSS_S_COMPLETE)
397 return (GSS_S_BAD_NAME);
398 internal_name = allocated_name;
399 }
400
401 if (cred_usage == GSS_C_ACCEPT)
402 time_req = acceptor_time_req;
403 else if (cred_usage == GSS_C_INITIATE)
404 time_req = initiator_time_req;
405 else if (cred_usage == GSS_C_BOTH)
406 time_req = (acceptor_time_req > initiator_time_req) ?
407 acceptor_time_req : initiator_time_req;
408 else
409 time_req = 0;
410
411 status = gss_create_empty_oid_set(minor_status, &target_mechs);
412 if (status != GSS_S_COMPLETE)
413 goto errout;
414
415 status = gss_add_oid_set_member(minor_status,
416 gssint_get_public_oid(selected_mech),
417 &target_mechs);
418 if (status != GSS_S_COMPLETE)
419 goto errout;
420
421 status = mech->gss_acquire_cred_impersonate_name(minor_status,
422 mech_impersonator_cred,
423 internal_name,
424 time_req,
425 target_mechs,
426 cred_usage,
427 &cred,
428 NULL,
429 &time_rec);
430 if (status != GSS_S_COMPLETE) {
431 map_error(minor_status, mech);
432 goto errout;
433 }
434
435 /* now add the new credential elements */
436 new_mechs_array = (gss_OID)
437 malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
438
439 new_cred_array = (gss_cred_id_t *)
440 malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
441
442 if (!new_mechs_array || !new_cred_array) {
443 status = GSS_S_FAILURE;
444 goto errout;
445 }
446
447 if (acceptor_time_rec)
448 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
449 *acceptor_time_rec = time_rec;
450 if (initiator_time_rec)
451 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
452 *initiator_time_rec = time_rec;
453
454 /*
455 * OK, expand the mechanism array and the credential array
456 */
457 (void) memcpy(new_mechs_array, union_cred->mechs_array,
458 sizeof (gss_OID_desc) * union_cred->count);
459 (void) memcpy(new_cred_array, union_cred->cred_array,
460 sizeof (gss_cred_id_t) * union_cred->count);
461
462 new_cred_array[union_cred->count] = cred;
463 if ((new_mechs_array[union_cred->count].elements =
464 malloc(selected_mech->length)) == NULL)
465 goto errout;
466
467 g_OID_copy(&new_mechs_array[union_cred->count], selected_mech);
468
469 if (actual_mechs != NULL) {
470 status = gssint_make_public_oid_set(minor_status, new_mechs_array,
471 union_cred->count + 1,
472 actual_mechs);
473 if (GSS_ERROR(status)) {
474 free(new_mechs_array[union_cred->count].elements);
475 goto errout;
476 }
477 }
478
479 if (output_cred_handle == NULL) {
480 free(union_cred->mechs_array);
481 free(union_cred->cred_array);
482 new_union_cred = union_cred;
483 } else {
484 new_union_cred = malloc(sizeof (gss_union_cred_desc));
485 if (new_union_cred == NULL) {
486 free(new_mechs_array[union_cred->count].elements);
487 goto errout;
488 }
489 *new_union_cred = *union_cred;
490 *output_cred_handle = (gss_cred_id_t)new_union_cred;
491 }
492
493 new_union_cred->mechs_array = new_mechs_array;
494 new_union_cred->cred_array = new_cred_array;
495 new_union_cred->count++;
496 new_union_cred->loopback = new_union_cred;
497
498 /* We're done with the internal name. Free it if we allocated it. */
499
500 if (allocated_name)
501 (void) gssint_release_internal_name(&temp_minor_status, selected_mech,
502 &allocated_name);
503
504 if (target_mechs)
505 (void) gss_release_oid_set(&temp_minor_status, &target_mechs);
506
507 return (GSS_S_COMPLETE);
508
509 errout:
510 if (new_mechs_array)
511 free(new_mechs_array);
512 if (new_cred_array)
513 free(new_cred_array);
514
515 if (cred != NULL && mech->gss_release_cred)
516 mech->gss_release_cred(&temp_minor_status, &cred);
517
518 if (allocated_name)
519 (void) gssint_release_internal_name(&temp_minor_status,
520 selected_mech, &allocated_name);
521
522 if (target_mechs)
523 (void) gss_release_oid_set(&temp_minor_status, &target_mechs);
524
525 if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred)
526 free(union_cred);
527
528 return (status);
529 }
530