xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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(minor_status,desired_name,password,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)101 gss_acquire_cred_with_password(
102     minor_status,
103     desired_name,
104     password,
105     time_req,
106     desired_mechs,
107     cred_usage,
108     output_cred_handle,
109     actual_mechs,
110     time_rec)
111 
112 OM_uint32 *		minor_status;
113 const gss_name_t	desired_name;
114 const gss_buffer_t	password;
115 OM_uint32		time_req;
116 const gss_OID_set	desired_mechs;
117 int			cred_usage;
118 gss_cred_id_t *		output_cred_handle;
119 gss_OID_set *		actual_mechs;
120 OM_uint32 *		time_rec;
121 {
122     OM_uint32 major = GSS_S_FAILURE;
123     OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
124     gss_OID_set_desc default_OID_set;
125     gss_OID_set mechs;
126     gss_OID_desc default_OID;
127     gss_mechanism mech;
128     unsigned int i;
129     gss_union_cred_t creds;
130 
131     major = val_acq_cred_pw_args(minor_status,
132 			         desired_name,
133 			         password,
134 			         time_req,
135 			         desired_mechs,
136 			         cred_usage,
137 			         output_cred_handle,
138 			         actual_mechs,
139 			         time_rec);
140     if (major != GSS_S_COMPLETE)
141 	return (major);
142 
143     /* Initial value needed below. */
144     major = GSS_S_FAILURE;
145 
146     /*
147      * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
148      * appropriate default.  We use the first mechanism in the
149      * mechanism list as the default. This set is created with
150      * statics thus needs not be freed
151      */
152     if(desired_mechs == GSS_C_NULL_OID_SET) {
153 	mech = gssint_get_mechanism(NULL);
154 	if (mech == NULL)
155 	    return (GSS_S_BAD_MECH);
156 
157 	mechs = &default_OID_set;
158 	default_OID_set.count = 1;
159 	default_OID_set.elements = &default_OID;
160 	default_OID.length = mech->mech_type.length;
161 	default_OID.elements = mech->mech_type.elements;
162     } else
163 	mechs = desired_mechs;
164 
165     if (mechs->count == 0)
166 	return (GSS_S_BAD_MECH);
167 
168     /* allocate the output credential structure */
169     creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
170     if (creds == NULL)
171 	return (GSS_S_FAILURE);
172 
173     /* initialize to 0s */
174     (void) memset(creds, 0, sizeof (gss_union_cred_desc));
175     creds->loopback = creds;
176 
177     /* for each requested mech attempt to obtain a credential */
178     for (i = 0; i < mechs->count; i++) {
179 	major = gss_add_cred_with_password(minor_status, (gss_cred_id_t)creds,
180 			     desired_name,
181 			     &mechs->elements[i],
182 			     password,
183 			     cred_usage, time_req, time_req, NULL,
184 			     NULL, &initTimeOut, &acceptTimeOut);
185 	if (major == GSS_S_COMPLETE) {
186 	    /* update the credential's time */
187 	    if (cred_usage == GSS_C_ACCEPT) {
188 		if (outTime > acceptTimeOut)
189 		    outTime = acceptTimeOut;
190 	    } else if (cred_usage == GSS_C_INITIATE) {
191 		if (outTime > initTimeOut)
192 		    outTime = initTimeOut;
193 	    } else {
194 		/*
195 		 * time_rec is the lesser of the
196 		 * init/accept times
197 		 */
198 		if (initTimeOut > acceptTimeOut)
199 		    outTime = (outTime > acceptTimeOut) ?
200 			acceptTimeOut : outTime;
201 		else
202 		    outTime = (outTime > initTimeOut) ?
203 			initTimeOut : outTime;
204 	    }
205 	}
206     } /* for */
207 
208     /* ensure that we have at least one credential element */
209     if (creds->count < 1) {
210 	free(creds);
211 	return (major);
212     }
213 
214     /*
215      * fill in output parameters
216      * setup the actual mechs output parameter
217      */
218     if (actual_mechs != NULL) {
219 	major = gssint_make_public_oid_set(minor_status, creds->mechs_array,
220 					   creds->count, actual_mechs);
221 	if (GSS_ERROR(major)) {
222 	    (void) gss_release_cred(minor_status,
223 				    (gss_cred_id_t *)&creds);
224 	    return (major);
225 	}
226     }
227 
228     if (time_rec)
229 	*time_rec = outTime;
230 
231 
232     creds->loopback = creds;
233     *output_cred_handle = (gss_cred_id_t)creds;
234     return (GSS_S_COMPLETE);
235 }
236 
237 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)238 val_add_cred_pw_args(
239     OM_uint32 *minor_status,
240     gss_cred_id_t input_cred_handle,
241     const gss_name_t desired_name,
242     const gss_OID desired_mech,
243     const gss_buffer_t password,
244     gss_cred_usage_t cred_usage,
245     OM_uint32 initiator_time_req,
246     OM_uint32 acceptor_time_req,
247     gss_cred_id_t *output_cred_handle,
248     gss_OID_set *actual_mechs,
249     OM_uint32 *initiator_time_rec,
250     OM_uint32 *acceptor_time_rec)
251 {
252 
253     /* Initialize outputs. */
254 
255     if (minor_status != NULL)
256 	*minor_status = 0;
257 
258     if (output_cred_handle != NULL)
259 	*output_cred_handle = GSS_C_NO_CREDENTIAL;
260 
261     if (actual_mechs != NULL)
262 	*actual_mechs = GSS_C_NO_OID_SET;
263 
264     if (acceptor_time_rec != NULL)
265 	*acceptor_time_rec = 0;
266 
267     if (initiator_time_rec != NULL)
268 	*initiator_time_rec = 0;
269 
270     /* Validate arguments. */
271 
272     if (desired_name == GSS_C_NO_NAME)
273 	return (GSS_S_BAD_NAME);
274 
275     if (minor_status == NULL)
276 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
277 
278     if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
279 	output_cred_handle == NULL)
280 	return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
281 
282     if (cred_usage != GSS_C_ACCEPT
283 	&& cred_usage != GSS_C_INITIATE
284 	&& cred_usage != GSS_C_BOTH) {
285 	if (minor_status) {
286 	    *minor_status = EINVAL;
287 	    map_errcode(minor_status);
288 	}
289 	return GSS_S_FAILURE;
290     }
291 
292     if (password == GSS_C_NO_BUFFER ||
293         password->length == 0 ||
294         password->value == NULL) {
295 	if (minor_status) {
296 	    *minor_status = EINVAL;
297 	    map_errcode(minor_status);
298 	}
299 	return GSS_S_FAILURE;
300     }
301 
302 
303     return (GSS_S_COMPLETE);
304 }
305 
306 
307 /* V2 KRB5_CALLCONV */
308 OM_uint32 KRB5_CALLCONV
gss_add_cred_with_password(minor_status,input_cred_handle,desired_name,desired_mech,password,cred_usage,initiator_time_req,acceptor_time_req,output_cred_handle,actual_mechs,initiator_time_rec,acceptor_time_rec)309 gss_add_cred_with_password(minor_status, input_cred_handle,
310 		  desired_name, desired_mech, password, cred_usage,
311 		  initiator_time_req, acceptor_time_req,
312 		  output_cred_handle, actual_mechs,
313 		  initiator_time_rec, acceptor_time_rec)
314     OM_uint32		*minor_status;
315     const gss_cred_id_t	input_cred_handle;
316     const gss_name_t	desired_name;
317     const gss_OID	desired_mech;
318     const gss_buffer_t	password;
319     gss_cred_usage_t	cred_usage;
320     OM_uint32		initiator_time_req;
321     OM_uint32		acceptor_time_req;
322     gss_cred_id_t	*output_cred_handle;
323     gss_OID_set		*actual_mechs;
324     OM_uint32		*initiator_time_rec;
325     OM_uint32		*acceptor_time_rec;
326 {
327     OM_uint32		status, temp_minor_status;
328     OM_uint32		time_req, time_rec;
329     gss_union_name_t	union_name;
330     gss_union_cred_t	new_union_cred, union_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_pw_args(minor_status,
341 			          input_cred_handle,
342 			          desired_name,
343 			          desired_mech,
344 			          password,
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     if (!mech->gssspi_acquire_cred_with_password)
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     /* may need to create a mechanism specific name */
383     union_name = (gss_union_name_t)desired_name;
384     if (union_name->mech_type &&
385 	g_OID_equal(union_name->mech_type, selected_mech))
386 	internal_name = union_name->mech_name;
387     else {
388 	if (gssint_import_internal_name(minor_status,
389 					selected_mech, union_name,
390 					&allocated_name) != GSS_S_COMPLETE)
391 	    return (GSS_S_BAD_NAME);
392 	internal_name = allocated_name;
393     }
394 
395     if (cred_usage == GSS_C_ACCEPT)
396 	time_req = acceptor_time_req;
397     else if (cred_usage == GSS_C_INITIATE)
398 	time_req = initiator_time_req;
399     else if (cred_usage == GSS_C_BOTH)
400 	time_req = (acceptor_time_req > initiator_time_req) ?
401 	    acceptor_time_req : initiator_time_req;
402     else
403 	time_req = 0;
404 
405     status = gss_create_empty_oid_set(minor_status, &target_mechs);
406     if (status != GSS_S_COMPLETE)
407 	goto errout;
408 
409     status = gss_add_oid_set_member(minor_status,
410 				    gssint_get_public_oid(selected_mech),
411 				    &target_mechs);
412     if (status != GSS_S_COMPLETE)
413 	goto errout;
414 
415     status = mech->gssspi_acquire_cred_with_password(minor_status,
416 						     internal_name,
417 						     password,
418 						     time_req,
419 						     target_mechs,
420 						     cred_usage,
421 						     &cred,
422 						     NULL,
423 						     &time_rec);
424     if (status != GSS_S_COMPLETE) {
425 	map_error(minor_status, mech);
426 	goto errout;
427     }
428 
429     /* now add the new credential elements */
430     new_mechs_array = (gss_OID)
431 	malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
432 
433     new_cred_array = (gss_cred_id_t *)
434 	malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
435 
436     if (!new_mechs_array || !new_cred_array) {
437 	status = GSS_S_FAILURE;
438 	goto errout;
439     }
440 
441     if (acceptor_time_rec)
442 	if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
443 	    *acceptor_time_rec = time_rec;
444     if (initiator_time_rec)
445 	if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
446 	    *initiator_time_rec = time_rec;
447 
448     /*
449      * OK, expand the mechanism array and the credential array
450      */
451     (void) memcpy(new_mechs_array, union_cred->mechs_array,
452 		  sizeof (gss_OID_desc) * union_cred->count);
453     (void) memcpy(new_cred_array, union_cred->cred_array,
454 		  sizeof (gss_cred_id_t) * union_cred->count);
455 
456     new_cred_array[union_cred->count] = cred;
457     if ((new_mechs_array[union_cred->count].elements =
458 	 malloc(selected_mech->length)) == NULL)
459 	goto errout;
460 
461     g_OID_copy(&new_mechs_array[union_cred->count], selected_mech);
462 
463     if (actual_mechs != NULL) {
464 	status = gssint_make_public_oid_set(minor_status, new_mechs_array,
465 					    union_cred->count + 1,
466 					    actual_mechs);
467 	if (GSS_ERROR(status)) {
468 	    free(new_mechs_array[union_cred->count].elements);
469 	    goto errout;
470 	}
471     }
472 
473     if (output_cred_handle == NULL) {
474 	free(union_cred->mechs_array);
475 	free(union_cred->cred_array);
476 	new_union_cred = union_cred;
477     } else {
478 	new_union_cred = malloc(sizeof (gss_union_cred_desc));
479 	if (new_union_cred == NULL) {
480 	    free(new_mechs_array[union_cred->count].elements);
481 	    goto errout;
482 	}
483 	*new_union_cred = *union_cred;
484 	*output_cred_handle = (gss_cred_id_t)new_union_cred;
485     }
486 
487     new_union_cred->mechs_array = new_mechs_array;
488     new_union_cred->cred_array = new_cred_array;
489     new_union_cred->count++;
490     new_union_cred->loopback = new_union_cred;
491 
492     /* We're done with the internal name. Free it if we allocated it. */
493 
494     if (allocated_name)
495 	(void) gssint_release_internal_name(&temp_minor_status,
496 					    selected_mech,
497 					   &allocated_name);
498 
499     if (target_mechs)
500 	(void)gss_release_oid_set(&temp_minor_status, &target_mechs);
501 
502     return (GSS_S_COMPLETE);
503 
504 errout:
505     if (new_mechs_array)
506 	free(new_mechs_array);
507     if (new_cred_array)
508 	free(new_cred_array);
509 
510     if (cred != NULL && mech->gss_release_cred)
511 	mech->gss_release_cred(&temp_minor_status, &cred);
512 
513     if (allocated_name)
514 	(void) gssint_release_internal_name(&temp_minor_status,
515 					    selected_mech, &allocated_name);
516 
517     if (target_mechs)
518 	(void)gss_release_oid_set(&temp_minor_status, &target_mechs);
519 
520     if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred)
521 	free(union_cred);
522 
523     return (status);
524 }
525