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