10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53376Smp153739  * Common Development and Distribution License (the "License").
63376Smp153739  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223376Smp153739  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  *  glue routine for gss_acquire_cred
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate #include <mechglueP.h>
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #ifdef HAVE_STDLIB_H
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #endif
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <time.h>
39*5053Sgtb 
400Sstevel@tonic-gate /* local functions */
410Sstevel@tonic-gate static gss_OID_set create_actual_mechs(const gss_OID, int);
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static gss_OID_set
440Sstevel@tonic-gate create_actual_mechs(mechs_array, count)
450Sstevel@tonic-gate 	const gss_OID	mechs_array;
460Sstevel@tonic-gate 	int count;
470Sstevel@tonic-gate {
480Sstevel@tonic-gate 	gss_OID_set 	actual_mechs;
490Sstevel@tonic-gate 	int		i;
500Sstevel@tonic-gate 	OM_uint32	minor;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
530Sstevel@tonic-gate 	if (!actual_mechs)
540Sstevel@tonic-gate 		return (NULL);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 	actual_mechs->elements = (gss_OID)
570Sstevel@tonic-gate 		malloc(sizeof (gss_OID_desc) * count);
580Sstevel@tonic-gate 	if (!actual_mechs->elements) {
590Sstevel@tonic-gate 		free(actual_mechs);
600Sstevel@tonic-gate 		return (NULL);
610Sstevel@tonic-gate 	}
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	actual_mechs->count = 0;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
660Sstevel@tonic-gate 		actual_mechs->elements[i].elements = (void *)
670Sstevel@tonic-gate 			malloc(mechs_array[i].length);
680Sstevel@tonic-gate 		if (actual_mechs->elements[i].elements == NULL) {
690Sstevel@tonic-gate 			(void) gss_release_oid_set(&minor, &actual_mechs);
700Sstevel@tonic-gate 			return (NULL);
710Sstevel@tonic-gate 		}
720Sstevel@tonic-gate 		g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
730Sstevel@tonic-gate 		actual_mechs->count++;
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	return (actual_mechs);
770Sstevel@tonic-gate }
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 
800Sstevel@tonic-gate OM_uint32
810Sstevel@tonic-gate gss_acquire_cred(minor_status,
820Sstevel@tonic-gate 			desired_name,
830Sstevel@tonic-gate 			time_req,
840Sstevel@tonic-gate 			desired_mechs,
850Sstevel@tonic-gate 			cred_usage,
860Sstevel@tonic-gate 			output_cred_handle,
870Sstevel@tonic-gate 			actual_mechs,
880Sstevel@tonic-gate 			time_rec)
890Sstevel@tonic-gate 
900Sstevel@tonic-gate OM_uint32 *		minor_status;
910Sstevel@tonic-gate const gss_name_t	desired_name;
920Sstevel@tonic-gate OM_uint32		time_req;
930Sstevel@tonic-gate const gss_OID_set	desired_mechs;
940Sstevel@tonic-gate int			cred_usage;
950Sstevel@tonic-gate gss_cred_id_t 		*output_cred_handle;
960Sstevel@tonic-gate gss_OID_set *		actual_mechs;
970Sstevel@tonic-gate OM_uint32 *		time_rec;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	OM_uint32 major = GSS_S_FAILURE;
1010Sstevel@tonic-gate 	OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
1020Sstevel@tonic-gate 	gss_OID_set_desc default_OID_set;
1030Sstevel@tonic-gate 	gss_OID_set mechs;
1040Sstevel@tonic-gate 	gss_OID_desc default_OID;
1050Sstevel@tonic-gate 	gss_mechanism mech;
1060Sstevel@tonic-gate 	int i;
1070Sstevel@tonic-gate 	gss_union_cred_t creds;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	/* start by checking parameters */
1100Sstevel@tonic-gate 	if (!minor_status)
1110Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
1120Sstevel@tonic-gate 	*minor_status = 0;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	if (!output_cred_handle)
1150Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	*output_cred_handle = GSS_C_NO_CREDENTIAL;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/* Set output parameters to NULL for now */
1200Sstevel@tonic-gate 	if (actual_mechs)
1210Sstevel@tonic-gate 		*actual_mechs = GSS_C_NULL_OID_SET;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (time_rec)
1240Sstevel@tonic-gate 		*time_rec = 0;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	/*
1270Sstevel@tonic-gate 	 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
1280Sstevel@tonic-gate 	 * appropriate default.  We use the first mechanism in the
1290Sstevel@tonic-gate 	 * mechansim list as the default. This set is created with
1300Sstevel@tonic-gate 	 * statics thus needs not be freed
1310Sstevel@tonic-gate 	 */
1320Sstevel@tonic-gate 	if (desired_mechs == GSS_C_NULL_OID_SET) {
1330Sstevel@tonic-gate 		mech = __gss_get_mechanism(NULL);
1340Sstevel@tonic-gate 		if (mech == NULL)
1350Sstevel@tonic-gate 			return (GSS_S_BAD_MECH);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 		mechs = &default_OID_set;
1380Sstevel@tonic-gate 		default_OID_set.count = 1;
1390Sstevel@tonic-gate 		default_OID_set.elements = &default_OID;
1400Sstevel@tonic-gate 		default_OID.length = mech->mech_type.length;
1410Sstevel@tonic-gate 		default_OID.elements = mech->mech_type.elements;
1420Sstevel@tonic-gate 	} else
1430Sstevel@tonic-gate 		mechs = desired_mechs;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	if (mechs->count == NULL)
1460Sstevel@tonic-gate 		return (GSS_S_BAD_MECH);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/* allocate the output credential structure */
1490Sstevel@tonic-gate 	creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
1500Sstevel@tonic-gate 	if (creds == NULL)
1510Sstevel@tonic-gate 		return (GSS_S_FAILURE);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/* initialize to 0s */
1540Sstevel@tonic-gate 	(void) memset(creds, 0, sizeof (gss_union_cred_desc));
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	/* for each requested mech attempt to obtain a credential */
1570Sstevel@tonic-gate 	for (i = 0; i < mechs->count; i++) {
1580Sstevel@tonic-gate 		major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
1590Sstevel@tonic-gate 				desired_name,
1600Sstevel@tonic-gate 				&mechs->elements[i],
1610Sstevel@tonic-gate 				cred_usage, time_req, time_req, NULL,
1620Sstevel@tonic-gate 				NULL, &initTimeOut, &acceptTimeOut);
1630Sstevel@tonic-gate 		if (major == GSS_S_COMPLETE) {
1640Sstevel@tonic-gate 			/* update the credential's time */
1650Sstevel@tonic-gate 			if (cred_usage == GSS_C_ACCEPT) {
1660Sstevel@tonic-gate 				if (outTime > acceptTimeOut)
1670Sstevel@tonic-gate 					outTime = acceptTimeOut;
1680Sstevel@tonic-gate 			} else if (cred_usage == GSS_C_INITIATE) {
1690Sstevel@tonic-gate 				if (outTime > initTimeOut)
1700Sstevel@tonic-gate 					outTime = initTimeOut;
1710Sstevel@tonic-gate 			} else {
1720Sstevel@tonic-gate 				/*
1730Sstevel@tonic-gate 				 * time_rec is the lesser of the
1740Sstevel@tonic-gate 				 * init/accept times
1750Sstevel@tonic-gate 				 */
1760Sstevel@tonic-gate 				if (initTimeOut > acceptTimeOut)
1770Sstevel@tonic-gate 					outTime = (outTime > acceptTimeOut) ?
1780Sstevel@tonic-gate 						acceptTimeOut : outTime;
1790Sstevel@tonic-gate 				else
1800Sstevel@tonic-gate 					outTime = (outTime > initTimeOut) ?
1810Sstevel@tonic-gate 						initTimeOut : outTime;
1820Sstevel@tonic-gate 			}
1830Sstevel@tonic-gate 		}
1840Sstevel@tonic-gate 	} /* for */
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	/* ensure that we have at least one credential element */
1870Sstevel@tonic-gate 	if (creds->count < 1) {
1880Sstevel@tonic-gate 		free(creds);
1890Sstevel@tonic-gate 		return (major);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/*
1930Sstevel@tonic-gate 	 * fill in output parameters
1940Sstevel@tonic-gate 	 * setup the actual mechs output parameter
1950Sstevel@tonic-gate 	 */
1960Sstevel@tonic-gate 	if (actual_mechs != NULL) {
1970Sstevel@tonic-gate 		if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
1980Sstevel@tonic-gate 					creds->count)) == NULL) {
1990Sstevel@tonic-gate 			(void) gss_release_cred(minor_status,
2000Sstevel@tonic-gate 				(gss_cred_id_t *)&creds);
2010Sstevel@tonic-gate 			*minor_status = 0;
2020Sstevel@tonic-gate 			return (GSS_S_FAILURE);
2030Sstevel@tonic-gate 		}
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	if (time_rec)
2070Sstevel@tonic-gate 		*time_rec = outTime;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	*output_cred_handle = (gss_cred_id_t)creds;
2110Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /* V2 INTERFACE */
2150Sstevel@tonic-gate OM_uint32
2160Sstevel@tonic-gate gss_add_cred(minor_status, input_cred_handle,
2170Sstevel@tonic-gate 			desired_name, desired_mech, cred_usage,
2180Sstevel@tonic-gate 			initiator_time_req, acceptor_time_req,
2190Sstevel@tonic-gate 			output_cred_handle, actual_mechs,
2200Sstevel@tonic-gate 			initiator_time_rec, acceptor_time_rec)
2210Sstevel@tonic-gate 	OM_uint32		*minor_status;
2220Sstevel@tonic-gate 	const gss_cred_id_t	input_cred_handle;
2230Sstevel@tonic-gate 	const gss_name_t	desired_name;
2240Sstevel@tonic-gate 	const gss_OID		desired_mech;
2250Sstevel@tonic-gate 	gss_cred_usage_t	cred_usage;
2260Sstevel@tonic-gate 	OM_uint32		initiator_time_req;
2270Sstevel@tonic-gate 	OM_uint32		acceptor_time_req;
2280Sstevel@tonic-gate 	gss_cred_id_t		*output_cred_handle;
2290Sstevel@tonic-gate 	gss_OID_set		*actual_mechs;
2300Sstevel@tonic-gate 	OM_uint32		*initiator_time_rec;
2310Sstevel@tonic-gate 	OM_uint32		*acceptor_time_rec;
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	OM_uint32		status, time_req, time_rec, temp_minor_status;
2340Sstevel@tonic-gate 	gss_mechanism 		mech;
2350Sstevel@tonic-gate 	gss_union_name_t	union_name = NULL;
2360Sstevel@tonic-gate 	gss_union_cred_t	union_cred, new_union_cred;
2370Sstevel@tonic-gate 	gss_name_t		internal_name = GSS_C_NO_NAME;
2380Sstevel@tonic-gate 	gss_name_t		allocated_name = GSS_C_NO_NAME;
2390Sstevel@tonic-gate 	gss_cred_id_t		cred = NULL;
2400Sstevel@tonic-gate 	gss_OID			new_mechs_array = NULL;
2410Sstevel@tonic-gate 	gss_cred_id_t		*new_cred_array = NULL;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/* check input parameters */
2440Sstevel@tonic-gate 	if (minor_status == NULL)
2450Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
2460Sstevel@tonic-gate 	*minor_status = 0;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
2490Sstevel@tonic-gate 		output_cred_handle == NULL)
2500Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (output_cred_handle)
2530Sstevel@tonic-gate 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	if (actual_mechs)
2560Sstevel@tonic-gate 		*actual_mechs = NULL;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if (acceptor_time_rec)
2590Sstevel@tonic-gate 		*acceptor_time_rec = 0;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if (initiator_time_rec)
2620Sstevel@tonic-gate 		*initiator_time_rec = 0;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	mech = __gss_get_mechanism(desired_mech);
2650Sstevel@tonic-gate 	if (!mech)
2660Sstevel@tonic-gate 		return (GSS_S_BAD_MECH);
2670Sstevel@tonic-gate 	else if (!mech->gss_acquire_cred)
2680Sstevel@tonic-gate 		return (GSS_S_UNAVAILABLE);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
2710Sstevel@tonic-gate 		union_cred = malloc(sizeof (gss_union_cred_desc));
2720Sstevel@tonic-gate 		if (union_cred == NULL)
2730Sstevel@tonic-gate 			return (GSS_S_FAILURE);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
276160Swyllys 	} else {
277160Swyllys 		/* Input Cred is non-NULL */
278160Swyllys 		union_cred = (gss_union_cred_t)input_cred_handle;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
281160Swyllys 			GSS_C_NO_CREDENTIAL) {
282160Swyllys 			status = GSS_S_DUPLICATE_ELEMENT;
283160Swyllys 			goto errout;
284160Swyllys 		}
2850Sstevel@tonic-gate 
286160Swyllys 		/*
287160Swyllys 		 * If no name was given, determine the name from the
288160Swyllys 		 * existing credential.
289160Swyllys 		 */
290160Swyllys 		if (desired_name == GSS_C_NO_NAME) {
291160Swyllys 			if (gss_import_name(minor_status,
292160Swyllys 				&union_cred->auxinfo.name,
293160Swyllys 				union_cred->auxinfo.name_type,
294160Swyllys 				&allocated_name) == GSS_S_COMPLETE &&
295160Swyllys 			    (gss_canonicalize_name(minor_status,
296160Swyllys 					allocated_name,
297160Swyllys 					&mech->mech_type,
298160Swyllys 					NULL) == GSS_S_COMPLETE)) {
2990Sstevel@tonic-gate 				internal_name = allocated_name;
3000Sstevel@tonic-gate 			}
301160Swyllys 		} /* else, get the name from the desired_name below */
302160Swyllys 	}
303160Swyllys 	if (desired_name != GSS_C_NO_NAME) {
304160Swyllys 		/* may need to create a mechanism specific name */
305160Swyllys 		union_name = (gss_union_name_t)desired_name;
306160Swyllys 
307160Swyllys 		if (union_name->mech_type &&
308160Swyllys 			g_OID_equal(union_name->mech_type,
309160Swyllys 					&mech->mech_type))
310160Swyllys 			internal_name = union_name->mech_name;
311160Swyllys 		else {
312160Swyllys 			if (__gss_import_internal_name(minor_status,
313160Swyllys 				&mech->mech_type, union_name,
314160Swyllys 				&allocated_name) != GSS_S_COMPLETE) {
315160Swyllys 				status = GSS_S_BAD_NAME;
316160Swyllys 				goto errout;
317160Swyllys 			}
318160Swyllys 			internal_name = allocated_name;
3190Sstevel@tonic-gate 		}
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (cred_usage == GSS_C_ACCEPT)
3230Sstevel@tonic-gate 		time_req = acceptor_time_req;
3240Sstevel@tonic-gate 	else if (cred_usage == GSS_C_INITIATE)
3250Sstevel@tonic-gate 		time_req = initiator_time_req;
3260Sstevel@tonic-gate 	else if (cred_usage == GSS_C_BOTH)
3270Sstevel@tonic-gate 		time_req = (acceptor_time_req > initiator_time_req) ?
3280Sstevel@tonic-gate 			acceptor_time_req : initiator_time_req;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	status = mech->gss_acquire_cred(mech->context, minor_status,
3310Sstevel@tonic-gate 				internal_name, time_req,
3320Sstevel@tonic-gate 				GSS_C_NULL_OID_SET, cred_usage,
3330Sstevel@tonic-gate 				&cred, NULL, &time_rec);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	if (status != GSS_S_COMPLETE)
3360Sstevel@tonic-gate 		goto errout;
3370Sstevel@tonic-gate 
338160Swyllys 	/* may need to set credential auxinfo structure */
3390Sstevel@tonic-gate 	if (union_cred->auxinfo.creation_time == 0) {
3400Sstevel@tonic-gate 		union_cred->auxinfo.creation_time = time(NULL);
3410Sstevel@tonic-gate 		union_cred->auxinfo.time_rec = time_rec;
3420Sstevel@tonic-gate 		union_cred->auxinfo.cred_usage = cred_usage;
3430Sstevel@tonic-gate 
3443376Smp153739 	/*
3453376Smp153739 	 * If internal_name is GSS_C_NO_NAME a cred with no associated
3463376Smp153739 	 * name was requested: don't set auxinfo.name or auxinfo.name_type.
3473376Smp153739 	 */
3483376Smp153739 		if (internal_name != GSS_C_NO_NAME) {
3493376Smp153739 			if ((status = mech->gss_display_name(mech->context,
3503376Smp153739 					&temp_minor_status, internal_name,
3513376Smp153739 					&union_cred->auxinfo.name,
3523376Smp153739 					&union_cred->auxinfo.name_type)) !=
3533376Smp153739 				GSS_S_COMPLETE)
3540Sstevel@tonic-gate 				goto errout;
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/* now add the new credential elements */
3590Sstevel@tonic-gate 	new_mechs_array = (gss_OID)
3600Sstevel@tonic-gate 		malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	new_cred_array = (gss_cred_id_t *)
3630Sstevel@tonic-gate 		malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (!new_mechs_array || !new_cred_array) {
3660Sstevel@tonic-gate 		status = GSS_S_FAILURE;
3670Sstevel@tonic-gate 		goto errout;
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (acceptor_time_rec)
3710Sstevel@tonic-gate 		if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
3720Sstevel@tonic-gate 			*acceptor_time_rec = time_rec;
3730Sstevel@tonic-gate 	if (initiator_time_rec)
3740Sstevel@tonic-gate 		if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
3750Sstevel@tonic-gate 			*initiator_time_rec = time_rec;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/*
3780Sstevel@tonic-gate 	 * OK, expand the mechanism array and the credential array
3790Sstevel@tonic-gate 	 */
3800Sstevel@tonic-gate 	(void) memcpy(new_mechs_array, union_cred->mechs_array,
3810Sstevel@tonic-gate 		sizeof (gss_OID_desc) * union_cred->count);
3820Sstevel@tonic-gate 	(void) memcpy(new_cred_array, union_cred->cred_array,
3830Sstevel@tonic-gate 		sizeof (gss_cred_id_t) * union_cred->count);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	new_cred_array[union_cred->count] = cred;
3860Sstevel@tonic-gate 	if ((new_mechs_array[union_cred->count].elements =
3870Sstevel@tonic-gate 			malloc(mech->mech_type.length)) == NULL)
3880Sstevel@tonic-gate 		goto errout;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	g_OID_copy(&new_mechs_array[union_cred->count],
3910Sstevel@tonic-gate 			&mech->mech_type);
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if (actual_mechs) {
3940Sstevel@tonic-gate 		*actual_mechs = create_actual_mechs(new_mechs_array,
3950Sstevel@tonic-gate 					union_cred->count + 1);
3960Sstevel@tonic-gate 		if (*actual_mechs == NULL) {
3970Sstevel@tonic-gate 			free(new_mechs_array[union_cred->count].elements);
3980Sstevel@tonic-gate 			goto errout;
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	if (output_cred_handle == NULL) {
4030Sstevel@tonic-gate 		free(union_cred->mechs_array);
4040Sstevel@tonic-gate 		free(union_cred->cred_array);
4050Sstevel@tonic-gate 		new_union_cred = union_cred;
4060Sstevel@tonic-gate 	} else {
4070Sstevel@tonic-gate 		new_union_cred = malloc(sizeof (gss_union_cred_desc));
4080Sstevel@tonic-gate 		if (new_union_cred == NULL) {
4090Sstevel@tonic-gate 			free(new_mechs_array[union_cred->count].elements);
4100Sstevel@tonic-gate 			goto errout;
4110Sstevel@tonic-gate 		}
4120Sstevel@tonic-gate 		*new_union_cred = *union_cred;
4130Sstevel@tonic-gate 		*output_cred_handle = (gss_cred_id_t)new_union_cred;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	new_union_cred->mechs_array = new_mechs_array;
4170Sstevel@tonic-gate 	new_union_cred->cred_array = new_cred_array;
4180Sstevel@tonic-gate 	new_union_cred->count++;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/* We're done with the internal name. Free it if we allocated it. */
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if (allocated_name)
4230Sstevel@tonic-gate 		(void) __gss_release_internal_name(&temp_minor_status,
4240Sstevel@tonic-gate 					&mech->mech_type,
4250Sstevel@tonic-gate 					&allocated_name);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate errout:
4300Sstevel@tonic-gate 	if (new_mechs_array)
4310Sstevel@tonic-gate 		free(new_mechs_array);
4320Sstevel@tonic-gate 	if (new_cred_array)
4330Sstevel@tonic-gate 		free(new_cred_array);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (cred != NULL && mech->gss_release_cred)
4360Sstevel@tonic-gate 		mech->gss_release_cred(mech->context,
4370Sstevel@tonic-gate 				&temp_minor_status, &cred);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (allocated_name)
4400Sstevel@tonic-gate 		(void) __gss_release_internal_name(&temp_minor_status,
4410Sstevel@tonic-gate 					&mech->mech_type,
4420Sstevel@tonic-gate 					&allocated_name);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
4450Sstevel@tonic-gate 		if (union_cred->auxinfo.name.value)
4460Sstevel@tonic-gate 			free(union_cred->auxinfo.name.value);
4470Sstevel@tonic-gate 		free(union_cred);
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	return (status);
4510Sstevel@tonic-gate }
452