1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *  glue routine for gss_acquire_cred
29  */
30 
31 #include <mechglueP.h>
32 #include <gssapi/gssapi_ext.h>
33 #include <stdio.h>
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #include <string.h>
38 #include <errno.h>
39 #include <time.h>
40 /* local functions */
41 static gss_OID_set create_actual_mechs(const gss_OID, int);
42 
43 static gss_OID_set
create_actual_mechs(mechs_array,count)44 create_actual_mechs(mechs_array, count)
45 	const gss_OID	mechs_array;
46 	int count;
47 {
48 	gss_OID_set 	actual_mechs;
49 	int		i;
50 	OM_uint32	minor;
51 
52 	actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
53 	if (!actual_mechs)
54 		return (NULL);
55 
56 	actual_mechs->elements = (gss_OID)
57 		malloc(sizeof (gss_OID_desc) * count);
58 	if (!actual_mechs->elements) {
59 		free(actual_mechs);
60 		return (NULL);
61 	}
62 
63 	actual_mechs->count = 0;
64 
65 	for (i = 0; i < count; i++) {
66 		actual_mechs->elements[i].elements = (void *)
67 			malloc(mechs_array[i].length);
68 		if (actual_mechs->elements[i].elements == NULL) {
69 			(void) gss_release_oid_set(&minor, &actual_mechs);
70 			return (NULL);
71 		}
72 		g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
73 		actual_mechs->count++;
74 	}
75 
76 	return (actual_mechs);
77 }
78 
79 
80 OM_uint32
gss_acquire_cred_with_password(minor_status,desired_name,password,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)81 gss_acquire_cred_with_password(minor_status,
82 			desired_name,
83 			password,
84 			time_req,
85 			desired_mechs,
86 			cred_usage,
87 			output_cred_handle,
88 			actual_mechs,
89 			time_rec)
90 
91 OM_uint32 *		minor_status;
92 const gss_name_t	desired_name;
93 const gss_buffer_t	password;
94 OM_uint32		time_req;
95 const gss_OID_set	desired_mechs;
96 int			cred_usage;
97 gss_cred_id_t 		*output_cred_handle;
98 gss_OID_set *		actual_mechs;
99 OM_uint32 *		time_rec;
100 
101 {
102 	OM_uint32 major = GSS_S_FAILURE;
103 	OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
104 	gss_OID_set_desc default_OID_set;
105 	gss_OID_set mechs;
106 	gss_OID_desc default_OID;
107 	gss_mechanism mech;
108 	int i;
109 	gss_union_cred_t creds;
110 
111 	/* start by checking parameters */
112 	if (minor_status == NULL)
113 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
114 	*minor_status = 0;
115 
116 	if (desired_name == GSS_C_NO_NAME)
117 		return (GSS_S_BAD_NAME);
118 
119 	if (output_cred_handle == NULL)
120 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
121 
122 	*output_cred_handle = GSS_C_NO_CREDENTIAL;
123 
124 	/* Set output parameters to NULL for now */
125 	if (actual_mechs != NULL)
126 		*actual_mechs = GSS_C_NULL_OID_SET;
127 
128 	if (time_rec)
129 		*time_rec = 0;
130 
131 	/*
132 	 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
133 	 * appropriate default.  We use the first mechanism in the
134 	 * mechansim list as the default. This set is created with
135 	 * statics thus needs not be freed
136 	 */
137 	if (desired_mechs == GSS_C_NULL_OID_SET) {
138 		mech = __gss_get_mechanism(GSS_C_NULL_OID);
139 		if (mech == NULL)
140 			return (GSS_S_BAD_MECH);
141 
142 		mechs = &default_OID_set;
143 		default_OID_set.count = 1;
144 		default_OID_set.elements = &default_OID;
145 		default_OID.length = mech->mech_type.length;
146 		default_OID.elements = mech->mech_type.elements;
147 	} else
148 		mechs = desired_mechs;
149 
150 	if (mechs->count == 0)
151 		return (GSS_S_BAD_MECH);
152 
153 	/* allocate the output credential structure */
154 	creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
155 	if (creds == NULL)
156 		return (GSS_S_FAILURE);
157 
158 	/* initialize to 0s */
159 	(void) memset(creds, 0, sizeof (gss_union_cred_desc));
160 
161 	/* for each requested mech attempt to obtain a credential */
162 	for (i = 0; i < mechs->count; i++) {
163 		major = gss_add_cred_with_password(minor_status,
164 				(gss_cred_id_t)creds,
165 				desired_name,
166 				&mechs->elements[i],
167 				password,
168 				cred_usage, time_req, time_req, NULL,
169 				NULL, &initTimeOut, &acceptTimeOut);
170 		if (major == GSS_S_COMPLETE) {
171 			/* update the credential's time */
172 			if (cred_usage == GSS_C_ACCEPT) {
173 				if (outTime > acceptTimeOut)
174 					outTime = acceptTimeOut;
175 			} else if (cred_usage == GSS_C_INITIATE) {
176 				if (outTime > initTimeOut)
177 					outTime = initTimeOut;
178 			} else {
179 				/*
180 				 * time_rec is the lesser of the
181 				 * init/accept times
182 				 */
183 				if (initTimeOut > acceptTimeOut)
184 					outTime = (outTime > acceptTimeOut) ?
185 						acceptTimeOut : outTime;
186 				else
187 					outTime = (outTime > initTimeOut) ?
188 						initTimeOut : outTime;
189 			}
190 		}
191 	} /* for */
192 
193 	/* ensure that we have at least one credential element */
194 	if (creds->count < 1) {
195 		free(creds);
196 		return (major);
197 	}
198 
199 	/*
200 	 * fill in output parameters
201 	 * setup the actual mechs output parameter
202 	 */
203 	if (actual_mechs != NULL) {
204 		if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
205 					creds->count)) == NULL) {
206 			(void) gss_release_cred(minor_status,
207 				(gss_cred_id_t *)&creds);
208 			*minor_status = 0;
209 			return (GSS_S_FAILURE);
210 		}
211 	}
212 
213 	if (time_rec)
214 		*time_rec = outTime;
215 
216 
217 	*output_cred_handle = (gss_cred_id_t)creds;
218 	return (GSS_S_COMPLETE);
219 }
220 
221 /* V2 INTERFACE */
222 OM_uint32
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)223 gss_add_cred_with_password(minor_status, input_cred_handle,
224 			desired_name, desired_mech, password,
225 			cred_usage, initiator_time_req,
226 			acceptor_time_req, output_cred_handle,
227 			actual_mechs, initiator_time_rec,
228 			acceptor_time_rec)
229 	OM_uint32		*minor_status;
230 	const gss_cred_id_t	input_cred_handle;
231 	const gss_name_t	desired_name;
232 	const gss_OID		desired_mech;
233 	const gss_buffer_t	password;
234 	gss_cred_usage_t	cred_usage;
235 	OM_uint32		initiator_time_req;
236 	OM_uint32		acceptor_time_req;
237 	gss_cred_id_t		*output_cred_handle;
238 	gss_OID_set		*actual_mechs;
239 	OM_uint32		*initiator_time_rec;
240 	OM_uint32		*acceptor_time_rec;
241 {
242 	OM_uint32		status, time_req, time_rec, temp_minor_status;
243 	gss_mechanism 		mech;
244 	gss_mechanism_ext 	mech_ext;
245 	gss_union_name_t	union_name = NULL;
246 	gss_union_cred_t	union_cred, new_union_cred;
247 	gss_name_t		internal_name = GSS_C_NO_NAME;
248 	gss_name_t		allocated_name = GSS_C_NO_NAME;
249 	gss_cred_id_t		cred = NULL;
250 	gss_OID			new_mechs_array = NULL;
251 	gss_cred_id_t		*new_cred_array = NULL;
252 
253 	/* check input parameters */
254 	if (minor_status == NULL)
255 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
256 	*minor_status = 0;
257 
258 	if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
259 		output_cred_handle == NULL)
260 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
261 
262 	if (desired_name == GSS_C_NO_NAME)
263 		return (GSS_S_BAD_NAME);
264 	union_name = (gss_union_name_t)desired_name;
265 
266 	if (output_cred_handle != NULL)
267 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
268 
269 	if (actual_mechs != NULL)
270 		*actual_mechs = NULL;
271 
272 	if (acceptor_time_rec != NULL)
273 		*acceptor_time_rec = 0;
274 
275 	if (initiator_time_rec != NULL)
276 		*initiator_time_rec = 0;
277 
278 	if ((mech = __gss_get_mechanism(desired_mech)) == NULL)
279 		return (GSS_S_BAD_MECH);
280 
281 	if ((mech_ext = __gss_get_mechanism_ext(desired_mech)) == NULL ||
282 	    mech_ext->gss_acquire_cred_with_password == NULL)
283 		return (GSS_S_UNAVAILABLE);
284 
285 	if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
286 		union_cred = malloc(sizeof (gss_union_cred_desc));
287 		if (union_cred == NULL)
288 			return (GSS_S_FAILURE);
289 
290 		(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
291 
292 	} else {
293 		union_cred = (gss_union_cred_t)input_cred_handle;
294 		if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
295 			GSS_C_NO_CREDENTIAL)
296 			return (GSS_S_DUPLICATE_ELEMENT);
297 	}
298 
299 	/* May need to create an MN */
300 	if (union_name->mech_type &&
301 		g_OID_equal(union_name->mech_type,
302 				&mech->mech_type))
303 		internal_name = union_name->mech_name;
304 	else {
305 		if (__gss_import_internal_name(minor_status,
306 			&mech->mech_type, union_name,
307 			&allocated_name) != GSS_S_COMPLETE)
308 			return (GSS_S_BAD_NAME);
309 		internal_name = allocated_name;
310 	}
311 
312 	if (cred_usage == GSS_C_ACCEPT)
313 		time_req = acceptor_time_req;
314 	else if (cred_usage == GSS_C_INITIATE)
315 		time_req = initiator_time_req;
316 	else if (cred_usage == GSS_C_BOTH)
317 		time_req = (acceptor_time_req > initiator_time_req) ?
318 			acceptor_time_req : initiator_time_req;
319 
320 	status = mech_ext->gss_acquire_cred_with_password(mech->context,
321 			minor_status, internal_name, password, time_req,
322 			GSS_C_NULL_OID_SET, cred_usage, &cred, NULL,
323 			&time_rec);
324 
325 	if (status != GSS_S_COMPLETE)
326 		goto errout;
327 
328 	/* May need to set credential auxinfo strucutre */
329 	if (union_cred->auxinfo.creation_time == 0) {
330 		union_cred->auxinfo.creation_time = time(NULL);
331 		union_cred->auxinfo.time_rec = time_rec;
332 		union_cred->auxinfo.cred_usage = cred_usage;
333 
334 		if ((status = mech->gss_display_name(mech->context,
335 				&temp_minor_status, internal_name,
336 				&union_cred->auxinfo.name,
337 				&union_cred->auxinfo.name_type)) !=
338 			GSS_S_COMPLETE)
339 			goto errout;
340 	}
341 
342 	/* Now add the new credential elements */
343 	new_mechs_array = (gss_OID)
344 		malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
345 
346 	new_cred_array = (gss_cred_id_t *)
347 		malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
348 
349 	if (!new_mechs_array || !new_cred_array) {
350 		status = GSS_S_FAILURE;
351 		goto errout;
352 	}
353 
354 	if (acceptor_time_rec)
355 		if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
356 			*acceptor_time_rec = time_rec;
357 	if (initiator_time_rec)
358 		if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
359 			*initiator_time_rec = time_rec;
360 
361 	/*
362 	 * OK, expand the mechanism array and the credential array
363 	 */
364 	(void) memcpy(new_mechs_array, union_cred->mechs_array,
365 		sizeof (gss_OID_desc) * union_cred->count);
366 	(void) memcpy(new_cred_array, union_cred->cred_array,
367 		sizeof (gss_cred_id_t) * union_cred->count);
368 
369 	new_cred_array[union_cred->count] = cred;
370 	if ((new_mechs_array[union_cred->count].elements =
371 			malloc(mech->mech_type.length)) == NULL)
372 		goto errout;
373 
374 	g_OID_copy(&new_mechs_array[union_cred->count],
375 			&mech->mech_type);
376 
377 	if (actual_mechs) {
378 		*actual_mechs = create_actual_mechs(new_mechs_array,
379 					union_cred->count + 1);
380 		if (*actual_mechs == NULL) {
381 			free(new_mechs_array[union_cred->count].elements);
382 			goto errout;
383 		}
384 	}
385 
386 	if (output_cred_handle == NULL) {
387 		free(union_cred->mechs_array);
388 		free(union_cred->cred_array);
389 		new_union_cred = union_cred;
390 	} else {
391 		new_union_cred = malloc(sizeof (gss_union_cred_desc));
392 		if (new_union_cred == NULL) {
393 			free(new_mechs_array[union_cred->count].elements);
394 			goto errout;
395 		}
396 		*new_union_cred = *union_cred;
397 		*output_cred_handle = (gss_cred_id_t)new_union_cred;
398 	}
399 
400 	new_union_cred->mechs_array = new_mechs_array;
401 	new_union_cred->cred_array = new_cred_array;
402 	new_union_cred->count++;
403 
404 	/* We're done with the internal name. Free it if we allocated it. */
405 
406 	if (allocated_name)
407 		(void) __gss_release_internal_name(&temp_minor_status,
408 					&mech->mech_type,
409 					&allocated_name);
410 
411 	return (GSS_S_COMPLETE);
412 
413 errout:
414 	if (new_mechs_array)
415 		free(new_mechs_array);
416 	if (new_cred_array)
417 		free(new_cred_array);
418 
419 	if (cred != NULL && mech->gss_release_cred)
420 		mech->gss_release_cred(mech->context,
421 				&temp_minor_status, &cred);
422 
423 	if (allocated_name)
424 		(void) __gss_release_internal_name(&temp_minor_status,
425 					&mech->mech_type,
426 					&allocated_name);
427 
428 	if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
429 		if (union_cred->auxinfo.name.value)
430 			free(union_cred->auxinfo.name.value);
431 		free(union_cred);
432 	}
433 
434 	return (status);
435 }
436