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