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