17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53dba6097Smp  * Common Development and Distribution License (the "License").
63dba6097Smp  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
225e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  *  glue routine for gss_acquire_cred
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate #include <mechglueP.h>
295e01956fSGlenn Barry #include "gssapiP_generic.h"
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #endif
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <time.h>
37ab9b2e15Sgtb 
387c478bd9Sstevel@tonic-gate /* local functions */
397c478bd9Sstevel@tonic-gate static gss_OID_set create_actual_mechs(const gss_OID, int);
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate static gss_OID_set
create_actual_mechs(mechs_array,count)427c478bd9Sstevel@tonic-gate create_actual_mechs(mechs_array, count)
437c478bd9Sstevel@tonic-gate 	const gss_OID	mechs_array;
447c478bd9Sstevel@tonic-gate 	int count;
457c478bd9Sstevel@tonic-gate {
467c478bd9Sstevel@tonic-gate 	gss_OID_set 	actual_mechs;
477c478bd9Sstevel@tonic-gate 	int		i;
487c478bd9Sstevel@tonic-gate 	OM_uint32	minor;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
517c478bd9Sstevel@tonic-gate 	if (!actual_mechs)
527c478bd9Sstevel@tonic-gate 		return (NULL);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 	actual_mechs->elements = (gss_OID)
557c478bd9Sstevel@tonic-gate 		malloc(sizeof (gss_OID_desc) * count);
567c478bd9Sstevel@tonic-gate 	if (!actual_mechs->elements) {
577c478bd9Sstevel@tonic-gate 		free(actual_mechs);
587c478bd9Sstevel@tonic-gate 		return (NULL);
597c478bd9Sstevel@tonic-gate 	}
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	actual_mechs->count = 0;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
647c478bd9Sstevel@tonic-gate 		actual_mechs->elements[i].elements = (void *)
657c478bd9Sstevel@tonic-gate 			malloc(mechs_array[i].length);
667c478bd9Sstevel@tonic-gate 		if (actual_mechs->elements[i].elements == NULL) {
677c478bd9Sstevel@tonic-gate 			(void) gss_release_oid_set(&minor, &actual_mechs);
687c478bd9Sstevel@tonic-gate 			return (NULL);
697c478bd9Sstevel@tonic-gate 		}
707c478bd9Sstevel@tonic-gate 		g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
717c478bd9Sstevel@tonic-gate 		actual_mechs->count++;
727c478bd9Sstevel@tonic-gate 	}
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	return (actual_mechs);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate 
77503a2b89SPeter Shoults static OM_uint32
val_acq_cred_args(OM_uint32 * minor_status,gss_name_t desired_name,OM_uint32 time_req,gss_OID_set desired_mechs,int cred_usage,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * time_rec)78503a2b89SPeter Shoults val_acq_cred_args(
795e01956fSGlenn Barry     OM_uint32 *minor_status,
805e01956fSGlenn Barry     /*LINTED*/
815e01956fSGlenn Barry     gss_name_t desired_name,
825e01956fSGlenn Barry     /*LINTED*/
835e01956fSGlenn Barry     OM_uint32 time_req,
845e01956fSGlenn Barry     /*LINTED*/
855e01956fSGlenn Barry     gss_OID_set desired_mechs,
865e01956fSGlenn Barry     int cred_usage,
875e01956fSGlenn Barry     gss_cred_id_t *output_cred_handle,
885e01956fSGlenn Barry     gss_OID_set *actual_mechs,
895e01956fSGlenn Barry     OM_uint32 *time_rec)
90503a2b89SPeter Shoults {
91503a2b89SPeter Shoults 
925e01956fSGlenn Barry    /* Initialize outputs. */
93503a2b89SPeter Shoults 
945e01956fSGlenn Barry     if (minor_status != NULL)
955e01956fSGlenn Barry         *minor_status = 0;
96503a2b89SPeter Shoults 
975e01956fSGlenn Barry     if (output_cred_handle != NULL)
985e01956fSGlenn Barry         *output_cred_handle = GSS_C_NO_CREDENTIAL;
99503a2b89SPeter Shoults 
1005e01956fSGlenn Barry     if (actual_mechs != NULL)
1015e01956fSGlenn Barry         *actual_mechs = GSS_C_NULL_OID_SET;
102503a2b89SPeter Shoults 
1035e01956fSGlenn Barry     if (time_rec != NULL)
1045e01956fSGlenn Barry         *time_rec = 0;
105503a2b89SPeter Shoults 
1065e01956fSGlenn Barry     /* Validate arguments. */
107503a2b89SPeter Shoults 
1085e01956fSGlenn Barry     if (minor_status == NULL)
1095e01956fSGlenn Barry         return (GSS_S_CALL_INACCESSIBLE_WRITE);
110503a2b89SPeter Shoults 
1115e01956fSGlenn Barry     if (output_cred_handle == NULL)
1125e01956fSGlenn Barry         return (GSS_S_CALL_INACCESSIBLE_WRITE);
113503a2b89SPeter Shoults 
1145e01956fSGlenn Barry     if (cred_usage != GSS_C_ACCEPT
1155e01956fSGlenn Barry         && cred_usage != GSS_C_INITIATE
1165e01956fSGlenn Barry         && cred_usage != GSS_C_BOTH) {
1175e01956fSGlenn Barry         if (minor_status) {
1185e01956fSGlenn Barry             *minor_status = EINVAL;
1195e01956fSGlenn Barry             map_errcode(minor_status);
1205e01956fSGlenn Barry         }
1215e01956fSGlenn Barry         return GSS_S_FAILURE;
1225e01956fSGlenn Barry     }
1235e01956fSGlenn Barry 
1245e01956fSGlenn Barry     return (GSS_S_COMPLETE);
125503a2b89SPeter Shoults }
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate OM_uint32
gss_acquire_cred(minor_status,desired_name,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)1287c478bd9Sstevel@tonic-gate gss_acquire_cred(minor_status,
1297c478bd9Sstevel@tonic-gate 			desired_name,
1307c478bd9Sstevel@tonic-gate 			time_req,
1317c478bd9Sstevel@tonic-gate 			desired_mechs,
1327c478bd9Sstevel@tonic-gate 			cred_usage,
1337c478bd9Sstevel@tonic-gate 			output_cred_handle,
1347c478bd9Sstevel@tonic-gate 			actual_mechs,
1357c478bd9Sstevel@tonic-gate 			time_rec)
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate OM_uint32 *		minor_status;
1387c478bd9Sstevel@tonic-gate const gss_name_t	desired_name;
1397c478bd9Sstevel@tonic-gate OM_uint32		time_req;
1407c478bd9Sstevel@tonic-gate const gss_OID_set	desired_mechs;
1417c478bd9Sstevel@tonic-gate int			cred_usage;
1427c478bd9Sstevel@tonic-gate gss_cred_id_t 		*output_cred_handle;
1437c478bd9Sstevel@tonic-gate gss_OID_set *		actual_mechs;
1447c478bd9Sstevel@tonic-gate OM_uint32 *		time_rec;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	OM_uint32 major = GSS_S_FAILURE;
1487c478bd9Sstevel@tonic-gate 	OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
1497c478bd9Sstevel@tonic-gate 	gss_OID_set_desc default_OID_set;
1507c478bd9Sstevel@tonic-gate 	gss_OID_set mechs;
1517c478bd9Sstevel@tonic-gate 	gss_OID_desc default_OID;
1527c478bd9Sstevel@tonic-gate 	gss_mechanism mech;
1535e01956fSGlenn Barry 	unsigned int i;
1547c478bd9Sstevel@tonic-gate 	gss_union_cred_t creds;
1557c478bd9Sstevel@tonic-gate 
156503a2b89SPeter Shoults 	major = val_acq_cred_args(minor_status,
1575e01956fSGlenn Barry 				desired_name,
1585e01956fSGlenn Barry 				time_req,
1595e01956fSGlenn Barry 				desired_mechs,
1605e01956fSGlenn Barry 				cred_usage,
161503a2b89SPeter Shoults 				output_cred_handle,
162503a2b89SPeter Shoults 				actual_mechs,
163503a2b89SPeter Shoults 				time_rec);
164503a2b89SPeter Shoults 	if (major != GSS_S_COMPLETE)
165503a2b89SPeter Shoults 		return (major);
1667c478bd9Sstevel@tonic-gate 
167503a2b89SPeter Shoults 	/* Initial value needed below. */
168503a2b89SPeter Shoults 	major = GSS_S_FAILURE;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/*
1717c478bd9Sstevel@tonic-gate 	 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
1727c478bd9Sstevel@tonic-gate 	 * appropriate default.  We use the first mechanism in the
1737c478bd9Sstevel@tonic-gate 	 * mechansim list as the default. This set is created with
1747c478bd9Sstevel@tonic-gate 	 * statics thus needs not be freed
1757c478bd9Sstevel@tonic-gate 	 */
1767c478bd9Sstevel@tonic-gate 	if (desired_mechs == GSS_C_NULL_OID_SET) {
1777c478bd9Sstevel@tonic-gate 		mech = __gss_get_mechanism(NULL);
1787c478bd9Sstevel@tonic-gate 		if (mech == NULL)
1797c478bd9Sstevel@tonic-gate 			return (GSS_S_BAD_MECH);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		mechs = &default_OID_set;
1827c478bd9Sstevel@tonic-gate 		default_OID_set.count = 1;
1837c478bd9Sstevel@tonic-gate 		default_OID_set.elements = &default_OID;
1847c478bd9Sstevel@tonic-gate 		default_OID.length = mech->mech_type.length;
1857c478bd9Sstevel@tonic-gate 		default_OID.elements = mech->mech_type.elements;
1867c478bd9Sstevel@tonic-gate 	} else
1877c478bd9Sstevel@tonic-gate 		mechs = desired_mechs;
1887c478bd9Sstevel@tonic-gate 
189*6f6dd2caSToomas Soome 	if (mechs->count == 0)
1907c478bd9Sstevel@tonic-gate 		return (GSS_S_BAD_MECH);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* allocate the output credential structure */
1937c478bd9Sstevel@tonic-gate 	creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
1947c478bd9Sstevel@tonic-gate 	if (creds == NULL)
1957c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/* initialize to 0s */
1987c478bd9Sstevel@tonic-gate 	(void) memset(creds, 0, sizeof (gss_union_cred_desc));
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/* for each requested mech attempt to obtain a credential */
2017c478bd9Sstevel@tonic-gate 	for (i = 0; i < mechs->count; i++) {
2027c478bd9Sstevel@tonic-gate 		major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
2037c478bd9Sstevel@tonic-gate 				desired_name,
2047c478bd9Sstevel@tonic-gate 				&mechs->elements[i],
2057c478bd9Sstevel@tonic-gate 				cred_usage, time_req, time_req, NULL,
2067c478bd9Sstevel@tonic-gate 				NULL, &initTimeOut, &acceptTimeOut);
2077c478bd9Sstevel@tonic-gate 		if (major == GSS_S_COMPLETE) {
2087c478bd9Sstevel@tonic-gate 			/* update the credential's time */
2097c478bd9Sstevel@tonic-gate 			if (cred_usage == GSS_C_ACCEPT) {
2107c478bd9Sstevel@tonic-gate 				if (outTime > acceptTimeOut)
2117c478bd9Sstevel@tonic-gate 					outTime = acceptTimeOut;
2127c478bd9Sstevel@tonic-gate 			} else if (cred_usage == GSS_C_INITIATE) {
2137c478bd9Sstevel@tonic-gate 				if (outTime > initTimeOut)
2147c478bd9Sstevel@tonic-gate 					outTime = initTimeOut;
2157c478bd9Sstevel@tonic-gate 			} else {
2167c478bd9Sstevel@tonic-gate 				/*
2177c478bd9Sstevel@tonic-gate 				 * time_rec is the lesser of the
2187c478bd9Sstevel@tonic-gate 				 * init/accept times
2197c478bd9Sstevel@tonic-gate 				 */
2207c478bd9Sstevel@tonic-gate 				if (initTimeOut > acceptTimeOut)
2217c478bd9Sstevel@tonic-gate 					outTime = (outTime > acceptTimeOut) ?
2227c478bd9Sstevel@tonic-gate 						acceptTimeOut : outTime;
2237c478bd9Sstevel@tonic-gate 				else
2247c478bd9Sstevel@tonic-gate 					outTime = (outTime > initTimeOut) ?
2257c478bd9Sstevel@tonic-gate 						initTimeOut : outTime;
2267c478bd9Sstevel@tonic-gate 			}
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 	} /* for */
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/* ensure that we have at least one credential element */
2317c478bd9Sstevel@tonic-gate 	if (creds->count < 1) {
2327c478bd9Sstevel@tonic-gate 		free(creds);
2337c478bd9Sstevel@tonic-gate 		return (major);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/*
2377c478bd9Sstevel@tonic-gate 	 * fill in output parameters
2387c478bd9Sstevel@tonic-gate 	 * setup the actual mechs output parameter
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate 	if (actual_mechs != NULL) {
2417c478bd9Sstevel@tonic-gate 		if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
2427c478bd9Sstevel@tonic-gate 					creds->count)) == NULL) {
2437c478bd9Sstevel@tonic-gate 			(void) gss_release_cred(minor_status,
2447c478bd9Sstevel@tonic-gate 				(gss_cred_id_t *)&creds);
2457c478bd9Sstevel@tonic-gate 			*minor_status = 0;
2467c478bd9Sstevel@tonic-gate 			return (GSS_S_FAILURE);
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if (time_rec)
2517c478bd9Sstevel@tonic-gate 		*time_rec = outTime;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	*output_cred_handle = (gss_cred_id_t)creds;
2557c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
258503a2b89SPeter Shoults static OM_uint32
val_add_cred_args(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_name_t desired_name,gss_OID desired_mech,gss_cred_usage_t cred_usage,OM_uint32 initiator_time_req,OM_uint32 acceptor_time_req,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * initiator_time_rec,OM_uint32 * acceptor_time_rec)259503a2b89SPeter Shoults val_add_cred_args(
260503a2b89SPeter Shoults 	OM_uint32 *minor_status,
261503a2b89SPeter Shoults 	gss_cred_id_t input_cred_handle,
2625e01956fSGlenn Barry 	/*LINTED*/
2635e01956fSGlenn Barry 	gss_name_t desired_name,
2645e01956fSGlenn Barry 	/*LINTED*/
2655e01956fSGlenn Barry 	gss_OID desired_mech,
2665e01956fSGlenn Barry 	gss_cred_usage_t cred_usage,
2675e01956fSGlenn Barry 	/*LINTED*/
2685e01956fSGlenn Barry 	OM_uint32 initiator_time_req,
2695e01956fSGlenn Barry 	/*LINTED*/
2705e01956fSGlenn Barry 	OM_uint32 acceptor_time_req,
271503a2b89SPeter Shoults 	gss_cred_id_t *output_cred_handle,
272503a2b89SPeter Shoults 	gss_OID_set *actual_mechs,
273503a2b89SPeter Shoults 	OM_uint32 *initiator_time_rec,
274503a2b89SPeter Shoults 	OM_uint32 *acceptor_time_rec)
275503a2b89SPeter Shoults {
276503a2b89SPeter Shoults 
277503a2b89SPeter Shoults 	/* Initialize outputs. */
278503a2b89SPeter Shoults 
279503a2b89SPeter Shoults 	if (minor_status != NULL)
280503a2b89SPeter Shoults 		*minor_status = 0;
281503a2b89SPeter Shoults 
282503a2b89SPeter Shoults 	if (output_cred_handle != NULL)
283503a2b89SPeter Shoults 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
284503a2b89SPeter Shoults 
285503a2b89SPeter Shoults 	if (actual_mechs != NULL)
286503a2b89SPeter Shoults 		*actual_mechs = GSS_C_NO_OID_SET;
287503a2b89SPeter Shoults 
288503a2b89SPeter Shoults 	if (acceptor_time_rec != NULL)
289503a2b89SPeter Shoults 		*acceptor_time_rec = 0;
290503a2b89SPeter Shoults 
291503a2b89SPeter Shoults 	if (initiator_time_rec != NULL)
292503a2b89SPeter Shoults 		*initiator_time_rec = 0;
293503a2b89SPeter Shoults 	/* Validate arguments. */
294503a2b89SPeter Shoults 
295503a2b89SPeter Shoults 	if (minor_status == NULL)
296503a2b89SPeter Shoults 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
297503a2b89SPeter Shoults 
298503a2b89SPeter Shoults 	if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
2995e01956fSGlenn Barry 	    output_cred_handle == NULL)
300503a2b89SPeter Shoults 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
301503a2b89SPeter Shoults 
3025e01956fSGlenn Barry 	if (cred_usage != GSS_C_ACCEPT
3035e01956fSGlenn Barry 	    && cred_usage != GSS_C_INITIATE
3045e01956fSGlenn Barry 	    && cred_usage != GSS_C_BOTH) {
3055e01956fSGlenn Barry 		if (minor_status) {
3065e01956fSGlenn Barry 			*minor_status = EINVAL;
3075e01956fSGlenn Barry 			map_errcode(minor_status);
3085e01956fSGlenn Barry 		}
3095e01956fSGlenn Barry 		return GSS_S_FAILURE;
3105e01956fSGlenn Barry 	}
3115e01956fSGlenn Barry 
312503a2b89SPeter Shoults 	return (GSS_S_COMPLETE);
313503a2b89SPeter Shoults }
314503a2b89SPeter Shoults 
3157c478bd9Sstevel@tonic-gate /* V2 INTERFACE */
3167c478bd9Sstevel@tonic-gate OM_uint32
gss_add_cred(minor_status,input_cred_handle,desired_name,desired_mech,cred_usage,initiator_time_req,acceptor_time_req,output_cred_handle,actual_mechs,initiator_time_rec,acceptor_time_rec)3177c478bd9Sstevel@tonic-gate gss_add_cred(minor_status, input_cred_handle,
3187c478bd9Sstevel@tonic-gate 			desired_name, desired_mech, cred_usage,
3197c478bd9Sstevel@tonic-gate 			initiator_time_req, acceptor_time_req,
3207c478bd9Sstevel@tonic-gate 			output_cred_handle, actual_mechs,
3217c478bd9Sstevel@tonic-gate 			initiator_time_rec, acceptor_time_rec)
3227c478bd9Sstevel@tonic-gate 	OM_uint32		*minor_status;
3237c478bd9Sstevel@tonic-gate 	const gss_cred_id_t	input_cred_handle;
3247c478bd9Sstevel@tonic-gate 	const gss_name_t	desired_name;
3257c478bd9Sstevel@tonic-gate 	const gss_OID		desired_mech;
3267c478bd9Sstevel@tonic-gate 	gss_cred_usage_t	cred_usage;
3277c478bd9Sstevel@tonic-gate 	OM_uint32		initiator_time_req;
3287c478bd9Sstevel@tonic-gate 	OM_uint32		acceptor_time_req;
3297c478bd9Sstevel@tonic-gate 	gss_cred_id_t		*output_cred_handle;
3307c478bd9Sstevel@tonic-gate 	gss_OID_set		*actual_mechs;
3317c478bd9Sstevel@tonic-gate 	OM_uint32		*initiator_time_rec;
3327c478bd9Sstevel@tonic-gate 	OM_uint32		*acceptor_time_rec;
3337c478bd9Sstevel@tonic-gate {
3347c478bd9Sstevel@tonic-gate 	OM_uint32		status, time_req, time_rec, temp_minor_status;
3357c478bd9Sstevel@tonic-gate 	gss_mechanism 		mech;
3367c478bd9Sstevel@tonic-gate 	gss_union_name_t	union_name = NULL;
3377c478bd9Sstevel@tonic-gate 	gss_union_cred_t	union_cred, new_union_cred;
3387c478bd9Sstevel@tonic-gate 	gss_name_t		internal_name = GSS_C_NO_NAME;
3397c478bd9Sstevel@tonic-gate 	gss_name_t		allocated_name = GSS_C_NO_NAME;
3407c478bd9Sstevel@tonic-gate 	gss_cred_id_t		cred = NULL;
3417c478bd9Sstevel@tonic-gate 	gss_OID			new_mechs_array = NULL;
3427c478bd9Sstevel@tonic-gate 	gss_cred_id_t		*new_cred_array = NULL;
3437c478bd9Sstevel@tonic-gate 
344503a2b89SPeter Shoults 	status = val_add_cred_args(minor_status,
345503a2b89SPeter Shoults 				input_cred_handle,
3465e01956fSGlenn Barry 				desired_name,
3475e01956fSGlenn Barry 				desired_mech,
3485e01956fSGlenn Barry 				cred_usage,
3495e01956fSGlenn Barry 				initiator_time_req,
3505e01956fSGlenn Barry 				acceptor_time_req,
351503a2b89SPeter Shoults 				output_cred_handle,
352503a2b89SPeter Shoults 				actual_mechs,
353503a2b89SPeter Shoults 				initiator_time_rec,
354503a2b89SPeter Shoults 				acceptor_time_rec);
355503a2b89SPeter Shoults 	if (status != GSS_S_COMPLETE)
356503a2b89SPeter Shoults 		return (status);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	mech = __gss_get_mechanism(desired_mech);
3597c478bd9Sstevel@tonic-gate 	if (!mech)
3607c478bd9Sstevel@tonic-gate 		return (GSS_S_BAD_MECH);
3617c478bd9Sstevel@tonic-gate 	else if (!mech->gss_acquire_cred)
3627c478bd9Sstevel@tonic-gate 		return (GSS_S_UNAVAILABLE);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
3657c478bd9Sstevel@tonic-gate 		union_cred = malloc(sizeof (gss_union_cred_desc));
3667c478bd9Sstevel@tonic-gate 		if (union_cred == NULL)
3677c478bd9Sstevel@tonic-gate 			return (GSS_S_FAILURE);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
3707c478bd9Sstevel@tonic-gate 	} else {
371354d1447Swyllys 		/* Input Cred is non-NULL */
3727c478bd9Sstevel@tonic-gate 		union_cred = (gss_union_cred_t)input_cred_handle;
373354d1447Swyllys 
3747c478bd9Sstevel@tonic-gate 		if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
375354d1447Swyllys 			GSS_C_NO_CREDENTIAL) {
376354d1447Swyllys 			status = GSS_S_DUPLICATE_ELEMENT;
377354d1447Swyllys 			goto errout;
378354d1447Swyllys 		}
3797c478bd9Sstevel@tonic-gate 
380354d1447Swyllys 		/*
381354d1447Swyllys 		 * If no name was given, determine the name from the
382354d1447Swyllys 		 * existing credential.
383354d1447Swyllys 		 */
384354d1447Swyllys 		if (desired_name == GSS_C_NO_NAME) {
385354d1447Swyllys 			if (gss_import_name(minor_status,
386354d1447Swyllys 				&union_cred->auxinfo.name,
387354d1447Swyllys 				union_cred->auxinfo.name_type,
388354d1447Swyllys 				&allocated_name) == GSS_S_COMPLETE &&
389354d1447Swyllys 			    (gss_canonicalize_name(minor_status,
390354d1447Swyllys 					allocated_name,
391354d1447Swyllys 					&mech->mech_type,
392354d1447Swyllys 					NULL) == GSS_S_COMPLETE)) {
3937c478bd9Sstevel@tonic-gate 				internal_name = allocated_name;
3947c478bd9Sstevel@tonic-gate 			}
395354d1447Swyllys 		} /* else, get the name from the desired_name below */
396354d1447Swyllys 	}
397354d1447Swyllys 	if (desired_name != GSS_C_NO_NAME) {
398354d1447Swyllys 		/* may need to create a mechanism specific name */
399354d1447Swyllys 		union_name = (gss_union_name_t)desired_name;
400354d1447Swyllys 
401354d1447Swyllys 		if (union_name->mech_type &&
402354d1447Swyllys 			g_OID_equal(union_name->mech_type,
403354d1447Swyllys 					&mech->mech_type))
404354d1447Swyllys 			internal_name = union_name->mech_name;
405354d1447Swyllys 		else {
406354d1447Swyllys 			if (__gss_import_internal_name(minor_status,
407354d1447Swyllys 				&mech->mech_type, union_name,
408354d1447Swyllys 				&allocated_name) != GSS_S_COMPLETE) {
409354d1447Swyllys 				status = GSS_S_BAD_NAME;
410354d1447Swyllys 				goto errout;
411354d1447Swyllys 			}
412354d1447Swyllys 			internal_name = allocated_name;
4137c478bd9Sstevel@tonic-gate 		}
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (cred_usage == GSS_C_ACCEPT)
4177c478bd9Sstevel@tonic-gate 		time_req = acceptor_time_req;
4187c478bd9Sstevel@tonic-gate 	else if (cred_usage == GSS_C_INITIATE)
4197c478bd9Sstevel@tonic-gate 		time_req = initiator_time_req;
4207c478bd9Sstevel@tonic-gate 	else if (cred_usage == GSS_C_BOTH)
4217c478bd9Sstevel@tonic-gate 		time_req = (acceptor_time_req > initiator_time_req) ?
4227c478bd9Sstevel@tonic-gate 			acceptor_time_req : initiator_time_req;
4235e01956fSGlenn Barry 	else
4245e01956fSGlenn Barry 		time_req = 0;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	status = mech->gss_acquire_cred(mech->context, minor_status,
4277c478bd9Sstevel@tonic-gate 				internal_name, time_req,
4287c478bd9Sstevel@tonic-gate 				GSS_C_NULL_OID_SET, cred_usage,
4297c478bd9Sstevel@tonic-gate 				&cred, NULL, &time_rec);
4307c478bd9Sstevel@tonic-gate 
4315e01956fSGlenn Barry 	if (status != GSS_S_COMPLETE) {
4325e01956fSGlenn Barry 		map_error(minor_status, mech);
4337c478bd9Sstevel@tonic-gate 		goto errout;
4345e01956fSGlenn Barry 	}
4357c478bd9Sstevel@tonic-gate 
436354d1447Swyllys 	/* may need to set credential auxinfo structure */
4377c478bd9Sstevel@tonic-gate 	if (union_cred->auxinfo.creation_time == 0) {
4387c478bd9Sstevel@tonic-gate 		union_cred->auxinfo.creation_time = time(NULL);
4397c478bd9Sstevel@tonic-gate 		union_cred->auxinfo.time_rec = time_rec;
4407c478bd9Sstevel@tonic-gate 		union_cred->auxinfo.cred_usage = cred_usage;
4417c478bd9Sstevel@tonic-gate 
4423dba6097Smp 	/*
4433dba6097Smp 	 * If internal_name is GSS_C_NO_NAME a cred with no associated
4443dba6097Smp 	 * name was requested: don't set auxinfo.name or auxinfo.name_type.
4453dba6097Smp 	 */
4463dba6097Smp 		if (internal_name != GSS_C_NO_NAME) {
4473dba6097Smp 			if ((status = mech->gss_display_name(mech->context,
4483dba6097Smp 					&temp_minor_status, internal_name,
4493dba6097Smp 					&union_cred->auxinfo.name,
4503dba6097Smp 					&union_cred->auxinfo.name_type)) !=
4513dba6097Smp 				GSS_S_COMPLETE)
4527c478bd9Sstevel@tonic-gate 				goto errout;
4537c478bd9Sstevel@tonic-gate 		}
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/* now add the new credential elements */
4577c478bd9Sstevel@tonic-gate 	new_mechs_array = (gss_OID)
4587c478bd9Sstevel@tonic-gate 		malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	new_cred_array = (gss_cred_id_t *)
4617c478bd9Sstevel@tonic-gate 		malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (!new_mechs_array || !new_cred_array) {
4647c478bd9Sstevel@tonic-gate 		status = GSS_S_FAILURE;
4657c478bd9Sstevel@tonic-gate 		goto errout;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	if (acceptor_time_rec)
4697c478bd9Sstevel@tonic-gate 		if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
4707c478bd9Sstevel@tonic-gate 			*acceptor_time_rec = time_rec;
4717c478bd9Sstevel@tonic-gate 	if (initiator_time_rec)
4727c478bd9Sstevel@tonic-gate 		if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
4737c478bd9Sstevel@tonic-gate 			*initiator_time_rec = time_rec;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/*
4767c478bd9Sstevel@tonic-gate 	 * OK, expand the mechanism array and the credential array
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	(void) memcpy(new_mechs_array, union_cred->mechs_array,
4797c478bd9Sstevel@tonic-gate 		sizeof (gss_OID_desc) * union_cred->count);
4807c478bd9Sstevel@tonic-gate 	(void) memcpy(new_cred_array, union_cred->cred_array,
4817c478bd9Sstevel@tonic-gate 		sizeof (gss_cred_id_t) * union_cred->count);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	new_cred_array[union_cred->count] = cred;
4847c478bd9Sstevel@tonic-gate 	if ((new_mechs_array[union_cred->count].elements =
4857c478bd9Sstevel@tonic-gate 			malloc(mech->mech_type.length)) == NULL)
4867c478bd9Sstevel@tonic-gate 		goto errout;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	g_OID_copy(&new_mechs_array[union_cred->count],
4897c478bd9Sstevel@tonic-gate 			&mech->mech_type);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (actual_mechs) {
4927c478bd9Sstevel@tonic-gate 		*actual_mechs = create_actual_mechs(new_mechs_array,
4937c478bd9Sstevel@tonic-gate 					union_cred->count + 1);
4947c478bd9Sstevel@tonic-gate 		if (*actual_mechs == NULL) {
4957c478bd9Sstevel@tonic-gate 			free(new_mechs_array[union_cred->count].elements);
4967c478bd9Sstevel@tonic-gate 			goto errout;
4977c478bd9Sstevel@tonic-gate 		}
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	if (output_cred_handle == NULL) {
5017c478bd9Sstevel@tonic-gate 		free(union_cred->mechs_array);
5027c478bd9Sstevel@tonic-gate 		free(union_cred->cred_array);
5037c478bd9Sstevel@tonic-gate 		new_union_cred = union_cred;
5047c478bd9Sstevel@tonic-gate 	} else {
5057c478bd9Sstevel@tonic-gate 		new_union_cred = malloc(sizeof (gss_union_cred_desc));
5067c478bd9Sstevel@tonic-gate 		if (new_union_cred == NULL) {
5077c478bd9Sstevel@tonic-gate 			free(new_mechs_array[union_cred->count].elements);
5087c478bd9Sstevel@tonic-gate 			goto errout;
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 		*new_union_cred = *union_cred;
5117c478bd9Sstevel@tonic-gate 		*output_cred_handle = (gss_cred_id_t)new_union_cred;
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	new_union_cred->mechs_array = new_mechs_array;
5157c478bd9Sstevel@tonic-gate 	new_union_cred->cred_array = new_cred_array;
5167c478bd9Sstevel@tonic-gate 	new_union_cred->count++;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/* We're done with the internal name. Free it if we allocated it. */
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (allocated_name)
5217c478bd9Sstevel@tonic-gate 		(void) __gss_release_internal_name(&temp_minor_status,
5227c478bd9Sstevel@tonic-gate 					&mech->mech_type,
5237c478bd9Sstevel@tonic-gate 					&allocated_name);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate errout:
5287c478bd9Sstevel@tonic-gate 	if (new_mechs_array)
5297c478bd9Sstevel@tonic-gate 		free(new_mechs_array);
5307c478bd9Sstevel@tonic-gate 	if (new_cred_array)
5317c478bd9Sstevel@tonic-gate 		free(new_cred_array);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (cred != NULL && mech->gss_release_cred)
5347c478bd9Sstevel@tonic-gate 		mech->gss_release_cred(mech->context,
5357c478bd9Sstevel@tonic-gate 				&temp_minor_status, &cred);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	if (allocated_name)
5387c478bd9Sstevel@tonic-gate 		(void) __gss_release_internal_name(&temp_minor_status,
5397c478bd9Sstevel@tonic-gate 					&mech->mech_type,
5407c478bd9Sstevel@tonic-gate 					&allocated_name);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
5437c478bd9Sstevel@tonic-gate 		if (union_cred->auxinfo.name.value)
5447c478bd9Sstevel@tonic-gate 			free(union_cred->auxinfo.name.value);
5457c478bd9Sstevel@tonic-gate 		free(union_cred);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	return (status);
5497c478bd9Sstevel@tonic-gate }
550