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