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