Home | History | Annotate | Download | only in libgss
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  *  glue routine for gss_accept_sec_context
     31  */
     32 
     33 #include <mechglueP.h>
     34 #ifdef HAVE_STDLIB_H
     35 #include <stdlib.h>
     36 #endif
     37 #include <string.h>
     38 #include <errno.h>
     39 
     40 OM_uint32
     41 gss_accept_sec_context(minor_status,
     42 			context_handle,
     43 			verifier_cred_handle,
     44 			input_token_buffer,
     45 			input_chan_bindings,
     46 			src_name,
     47 			mech_type,
     48 			output_token,
     49 			ret_flags,
     50 			time_rec,
     51 			d_cred)
     52 
     53 OM_uint32 			*minor_status;
     54 gss_ctx_id_t			*context_handle;
     55 const gss_cred_id_t		verifier_cred_handle;
     56 const gss_buffer_t		input_token_buffer;
     57 const gss_channel_bindings_t	input_chan_bindings;
     58 gss_name_t			*src_name;
     59 gss_OID				*mech_type;
     60 gss_buffer_t			output_token;
     61 OM_uint32			*ret_flags;
     62 OM_uint32			*time_rec;
     63 gss_cred_id_t			*d_cred; /* delegated cred handle */
     64 
     65 {
     66 	OM_uint32		status, temp_status, t_minstat;
     67 	gss_union_ctx_id_t	union_ctx_id;
     68 	gss_union_cred_t	union_cred;
     69 	gss_cred_id_t	input_cred_handle = GSS_C_NO_CREDENTIAL;
     70 	gss_cred_id_t	tmp_d_cred = GSS_C_NO_CREDENTIAL;
     71 	gss_name_t		internal_name = GSS_C_NO_NAME;
     72 	gss_name_t		tmp_src_name = GSS_C_NO_NAME;
     73 	gss_OID_desc	token_mech_type_desc;
     74 	gss_OID		token_mech_type = &token_mech_type_desc;
     75 	gss_OID		actual_mech = GSS_C_NO_OID;
     76 	OM_uint32	flags;
     77 	gss_mechanism	mech;
     78 
     79 	/* check parameters first */
     80 	if (minor_status == NULL)
     81 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
     82 	*minor_status = 0;
     83 
     84 	if (context_handle == NULL || output_token == NULL)
     85 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
     86 
     87 	/* clear optional fields */
     88 	output_token->value = NULL;
     89 	output_token->length = 0;
     90 	if (src_name)
     91 		*src_name = NULL;
     92 
     93 	if (mech_type)
     94 		*mech_type = NULL;
     95 
     96 	if (d_cred)
     97 		*d_cred = NULL;
     98 	/*
     99 	 * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
    100 	 * descriptor to hold the mech type information as well as the
    101 	 * underlying mechanism context handle. Otherwise, cast the
    102 	 * value of *context_handle to the union context variable.
    103 	 */
    104 
    105 	if (*context_handle == GSS_C_NO_CONTEXT) {
    106 
    107 		if (GSS_EMPTY_BUFFER(input_token_buffer))
    108 			return (GSS_S_CALL_INACCESSIBLE_READ);
    109 
    110 		/* Get the token mech type */
    111 		status = __gss_get_mech_type(token_mech_type,
    112 					input_token_buffer);
    113 
    114 		if (status)
    115 			return (status);
    116 
    117 		status = GSS_S_FAILURE;
    118 		union_ctx_id = (gss_union_ctx_id_t)
    119 			malloc(sizeof (gss_union_ctx_id_desc));
    120 		if (!union_ctx_id)
    121 			return (GSS_S_FAILURE);
    122 
    123 		union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
    124 		status = generic_gss_copy_oid(&t_minstat,
    125 					token_mech_type,
    126 					&union_ctx_id->mech_type);
    127 		if (status != GSS_S_COMPLETE) {
    128 			free(union_ctx_id);
    129 			return (status);
    130 		}
    131 
    132 		/* set the new context handle to caller's data */
    133 		*context_handle = (gss_ctx_id_t)union_ctx_id;
    134 	} else {
    135 		union_ctx_id = (gss_union_ctx_id_t)*context_handle;
    136 		token_mech_type = union_ctx_id->mech_type;
    137 	}
    138 
    139 	/*
    140 	 * get the appropriate cred handle from the union cred struct.
    141 	 * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
    142 	 * use the default credential.
    143 	 */
    144 	union_cred = (gss_union_cred_t)verifier_cred_handle;
    145 	input_cred_handle = __gss_get_mechanism_cred(union_cred,
    146 						token_mech_type);
    147 
    148 	/*
    149 	 * now select the approprate underlying mechanism routine and
    150 	 * call it.
    151 	 */
    152 
    153 	mech = __gss_get_mechanism(token_mech_type);
    154 	if (mech && mech->gss_accept_sec_context) {
    155 		status = mech->gss_accept_sec_context(
    156 					mech->context,
    157 					minor_status,
    158 					&union_ctx_id->internal_ctx_id,
    159 					input_cred_handle,
    160 					input_token_buffer,
    161 					input_chan_bindings,
    162 					&internal_name,
    163 					&actual_mech,
    164 					output_token,
    165 					&flags,
    166 					time_rec,
    167 					d_cred ? &tmp_d_cred : NULL);
    168 
    169 		/* If there's more work to do, keep going... */
    170 		if (status == GSS_S_CONTINUE_NEEDED)
    171 			return (GSS_S_CONTINUE_NEEDED);
    172 
    173 		/* if the call failed, return with failure */
    174 		if (status != GSS_S_COMPLETE)
    175 			goto error_out;
    176 
    177 		if (mech_type != NULL)
    178 			*mech_type = actual_mech;
    179 
    180 		/*
    181 		 * if src_name is non-NULL,
    182 		 * convert internal_name into a union name equivalent
    183 		 * First call the mechanism specific display_name()
    184 		 * then call gss_import_name() to create
    185 		 * the union name struct cast to src_name
    186 		 */
    187 		if (internal_name != NULL) {
    188 			temp_status = __gss_convert_name_to_union_name(
    189 				&t_minstat, mech,
    190 				internal_name, &tmp_src_name);
    191 			if (temp_status != GSS_S_COMPLETE) {
    192 				*minor_status = t_minstat;
    193 				if (output_token->length)
    194 					(void) gss_release_buffer(
    195 						&t_minstat,
    196 						output_token);
    197 				if (internal_name != GSS_C_NO_NAME)
    198 					mech->gss_release_name(
    199 						mech->context,
    200 						&t_minstat,
    201 						&internal_name);
    202 				return (temp_status);
    203 			}
    204 			if (src_name != NULL) {
    205 				*src_name = tmp_src_name;
    206 			}
    207 		} else if (src_name != NULL) {
    208 			*src_name = GSS_C_NO_NAME;
    209 		}
    210 
    211 		/* Ensure we're returning correct creds format */
    212 		if ((flags & GSS_C_DELEG_FLAG) &&
    213 		    tmp_d_cred != GSS_C_NO_CREDENTIAL) {
    214 			/*
    215 			 * If we got back an OID different from the original
    216 			 * token OID, assume the delegated_cred is already
    217 			 * a proper union_cred and just return it.  Don't
    218 			 * try to re-wrap it.  This is for SPNEGO or other
    219 			 * pseudo-mechanisms.
    220 			 */
    221 			if (actual_mech != GSS_C_NO_OID &&
    222 			    token_mech_type != GSS_C_NO_OID &&
    223 			    !g_OID_equal(actual_mech, token_mech_type)) {
    224 				*d_cred = tmp_d_cred;
    225 			} else {
    226 				gss_union_cred_t d_u_cred = NULL;
    227 
    228 				d_u_cred = malloc(sizeof (gss_union_cred_desc));
    229 				if (d_u_cred == NULL) {
    230 					status = GSS_S_FAILURE;
    231 					goto error_out;
    232 				}
    233 				(void) memset(d_u_cred, 0,
    234 					    sizeof (gss_union_cred_desc));
    235 
    236 				d_u_cred->count = 1;
    237 
    238 				status = generic_gss_copy_oid(
    239 					&t_minstat,
    240 					actual_mech,
    241 					&d_u_cred->mechs_array);
    242 
    243 				if (status != GSS_S_COMPLETE) {
    244 					free(d_u_cred);
    245 					goto error_out;
    246 				}
    247 
    248 				d_u_cred->cred_array = malloc(
    249 						sizeof (gss_cred_id_t));
    250 				if (d_u_cred->cred_array != NULL) {
    251 					d_u_cred->cred_array[0] = tmp_d_cred;
    252 				} else {
    253 					free(d_u_cred);
    254 					status = GSS_S_FAILURE;
    255 					goto error_out;
    256 				}
    257 
    258 				if (status != GSS_S_COMPLETE) {
    259 					free(d_u_cred->cred_array);
    260 					free(d_u_cred);
    261 					goto error_out;
    262 				}
    263 
    264 				internal_name = GSS_C_NO_NAME;
    265 
    266 				d_u_cred->auxinfo.creation_time = time(0);
    267 				d_u_cred->auxinfo.time_rec = 0;
    268 
    269 				if (mech->gss_inquire_cred) {
    270 					status = mech->gss_inquire_cred(
    271 						mech->context,
    272 						minor_status,
    273 						tmp_d_cred,
    274 						&internal_name,
    275 						&d_u_cred->auxinfo.time_rec,
    276 						&d_u_cred->auxinfo.cred_usage,
    277 						NULL);
    278 				}
    279 
    280 				if (internal_name != NULL) {
    281 					temp_status =
    282 					    __gss_convert_name_to_union_name(
    283 						&t_minstat, mech,
    284 						internal_name, &tmp_src_name);
    285 					if (temp_status != GSS_S_COMPLETE) {
    286 						*minor_status = t_minstat;
    287 						if (output_token->length)
    288 						    (void) gss_release_buffer(
    289 								&t_minstat,
    290 								output_token);
    291 						free(d_u_cred->cred_array);
    292 						free(d_u_cred);
    293 						return (temp_status);
    294 					}
    295 				}
    296 
    297 				if (tmp_src_name != NULL) {
    298 					status = gss_display_name(
    299 						&t_minstat,
    300 						tmp_src_name,
    301 						&d_u_cred->auxinfo.name,
    302 						&d_u_cred->auxinfo.name_type);
    303 				}
    304 
    305 				*d_cred = (gss_cred_id_t)d_u_cred;
    306 			}
    307 		}
    308 		if (ret_flags != NULL) {
    309 			*ret_flags = flags;
    310 		}
    311 
    312 		if (src_name == NULL && tmp_src_name != NULL)
    313 			(void) gss_release_name(&t_minstat,
    314 					&tmp_src_name);
    315 		return	(status);
    316 	} else {
    317 
    318 		status = GSS_S_BAD_MECH;
    319 	}
    320 
    321 error_out:
    322 	if (union_ctx_id) {
    323 		if (union_ctx_id->mech_type) {
    324 			if (union_ctx_id->mech_type->elements)
    325 				free(union_ctx_id->mech_type->elements);
    326 			free(union_ctx_id->mech_type);
    327 		}
    328 		free(union_ctx_id);
    329 		*context_handle = GSS_C_NO_CONTEXT;
    330 	}
    331 
    332 	if (output_token->length)
    333 		(void) gss_release_buffer(&t_minstat, output_token);
    334 
    335 	if (src_name)
    336 		*src_name = GSS_C_NO_NAME;
    337 
    338 	if (tmp_src_name != GSS_C_NO_NAME)
    339 		(void) gss_release_buffer(&t_minstat,
    340 			(gss_buffer_t)tmp_src_name);
    341 
    342 	return (status);
    343 }
    344