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