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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * glue routine for gss_accept_sec_context 29 */ 30 31 #include <mechglueP.h> 32 #ifdef HAVE_STDLIB_H 33 #include <stdlib.h> 34 #endif 35 #include <string.h> 36 #include <errno.h> 37 38 static OM_uint32 39 val_acc_sec_ctx_args( 40 OM_uint32 *minor_status, 41 gss_ctx_id_t *context_handle, 42 gss_buffer_t input_token_buffer, 43 gss_name_t *src_name, 44 gss_OID *mech_type, 45 gss_buffer_t output_token, 46 gss_cred_id_t *d_cred) 47 { 48 49 /* Initialize outputs. */ 50 51 if (minor_status != NULL) 52 *minor_status = 0; 53 54 if (src_name != NULL) 55 *src_name = GSS_C_NO_NAME; 56 57 if (mech_type != NULL) 58 *mech_type = GSS_C_NO_OID; 59 60 if (output_token != GSS_C_NO_BUFFER) { 61 output_token->length = 0; 62 output_token->value = NULL; 63 } 64 65 if (d_cred != NULL) 66 *d_cred = GSS_C_NO_CREDENTIAL; 67 68 /* Validate arguments. */ 69 70 if (minor_status == NULL) 71 return (GSS_S_CALL_INACCESSIBLE_WRITE); 72 73 if (context_handle == NULL) 74 return (GSS_S_CALL_INACCESSIBLE_WRITE); 75 76 if (input_token_buffer == GSS_C_NO_BUFFER) 77 return (GSS_S_CALL_INACCESSIBLE_READ); 78 79 if (output_token == GSS_C_NO_BUFFER) 80 return (GSS_S_CALL_INACCESSIBLE_WRITE); 81 82 return (GSS_S_COMPLETE); 83 } 84 85 OM_uint32 86 gss_accept_sec_context(minor_status, 87 context_handle, 88 verifier_cred_handle, 89 input_token_buffer, 90 input_chan_bindings, 91 src_name, 92 mech_type, 93 output_token, 94 ret_flags, 95 time_rec, 96 d_cred) 97 98 OM_uint32 *minor_status; 99 gss_ctx_id_t *context_handle; 100 const gss_cred_id_t verifier_cred_handle; 101 const gss_buffer_t input_token_buffer; 102 const gss_channel_bindings_t input_chan_bindings; 103 gss_name_t *src_name; 104 gss_OID *mech_type; 105 gss_buffer_t output_token; 106 OM_uint32 *ret_flags; 107 OM_uint32 *time_rec; 108 gss_cred_id_t *d_cred; /* delegated cred handle */ 109 110 { 111 OM_uint32 status, temp_status, t_minstat; 112 gss_union_ctx_id_t union_ctx_id; 113 gss_union_cred_t union_cred; 114 gss_cred_id_t input_cred_handle = GSS_C_NO_CREDENTIAL; 115 gss_cred_id_t tmp_d_cred = GSS_C_NO_CREDENTIAL; 116 gss_name_t internal_name = GSS_C_NO_NAME; 117 gss_name_t tmp_src_name = GSS_C_NO_NAME; 118 gss_OID_desc token_mech_type_desc; 119 gss_OID token_mech_type = &token_mech_type_desc; 120 gss_OID actual_mech = GSS_C_NO_OID; 121 OM_uint32 flags; 122 gss_mechanism mech; 123 124 status = val_acc_sec_ctx_args(minor_status, 125 context_handle, 126 input_token_buffer, 127 src_name, 128 mech_type, 129 output_token, 130 d_cred); 131 if (status != GSS_S_COMPLETE) 132 return (status); 133 134 /* 135 * if context_handle is GSS_C_NO_CONTEXT, allocate a union context 136 * descriptor to hold the mech type information as well as the 137 * underlying mechanism context handle. Otherwise, cast the 138 * value of *context_handle to the union context variable. 139 */ 140 141 if (*context_handle == GSS_C_NO_CONTEXT) { 142 143 if (GSS_EMPTY_BUFFER(input_token_buffer)) 144 return (GSS_S_CALL_INACCESSIBLE_READ); 145 146 /* Get the token mech type */ 147 status = __gss_get_mech_type(token_mech_type, 148 input_token_buffer); 149 150 if (status) 151 return (status); 152 153 status = GSS_S_FAILURE; 154 union_ctx_id = (gss_union_ctx_id_t) 155 malloc(sizeof (gss_union_ctx_id_desc)); 156 if (!union_ctx_id) 157 return (GSS_S_FAILURE); 158 159 union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT; 160 status = generic_gss_copy_oid(&t_minstat, 161 token_mech_type, 162 &union_ctx_id->mech_type); 163 if (status != GSS_S_COMPLETE) { 164 free(union_ctx_id); 165 return (status); 166 } 167 168 /* set the new context handle to caller's data */ 169 *context_handle = (gss_ctx_id_t)union_ctx_id; 170 } else { 171 union_ctx_id = (gss_union_ctx_id_t)*context_handle; 172 token_mech_type = union_ctx_id->mech_type; 173 } 174 175 /* 176 * get the appropriate cred handle from the union cred struct. 177 * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will 178 * use the default credential. 179 */ 180 union_cred = (gss_union_cred_t)verifier_cred_handle; 181 input_cred_handle = __gss_get_mechanism_cred(union_cred, 182 token_mech_type); 183 184 /* 185 * now select the approprate underlying mechanism routine and 186 * call it. 187 */ 188 189 mech = __gss_get_mechanism(token_mech_type); 190 if (mech && mech->gss_accept_sec_context) { 191 status = mech->gss_accept_sec_context( 192 mech->context, 193 minor_status, 194 &union_ctx_id->internal_ctx_id, 195 input_cred_handle, 196 input_token_buffer, 197 input_chan_bindings, 198 &internal_name, 199 &actual_mech, 200 output_token, 201 &flags, 202 time_rec, 203 d_cred ? &tmp_d_cred : NULL); 204 205 /* If there's more work to do, keep going... */ 206 if (status == GSS_S_CONTINUE_NEEDED) 207 return (GSS_S_CONTINUE_NEEDED); 208 209 /* if the call failed, return with failure */ 210 if (status != GSS_S_COMPLETE) 211 goto error_out; 212 213 if (mech_type != NULL) 214 *mech_type = actual_mech; 215 216 /* 217 * if src_name is non-NULL, 218 * convert internal_name into a union name equivalent 219 * First call the mechanism specific display_name() 220 * then call gss_import_name() to create 221 * the union name struct cast to src_name 222 */ 223 if (internal_name != NULL) { 224 temp_status = __gss_convert_name_to_union_name( 225 &t_minstat, mech, 226 internal_name, &tmp_src_name); 227 if (temp_status != GSS_S_COMPLETE) { 228 *minor_status = t_minstat; 229 if (output_token->length) 230 (void) gss_release_buffer( 231 &t_minstat, 232 output_token); 233 if (internal_name != GSS_C_NO_NAME) 234 mech->gss_release_name( 235 mech->context, 236 &t_minstat, 237 &internal_name); 238 return (temp_status); 239 } 240 if (src_name != NULL) { 241 *src_name = tmp_src_name; 242 } 243 } else if (src_name != NULL) { 244 *src_name = GSS_C_NO_NAME; 245 } 246 247 /* Ensure we're returning correct creds format */ 248 if ((flags & GSS_C_DELEG_FLAG) && 249 tmp_d_cred != GSS_C_NO_CREDENTIAL) { 250 /* 251 * If we got back an OID different from the original 252 * token OID, assume the delegated_cred is already 253 * a proper union_cred and just return it. Don't 254 * try to re-wrap it. This is for SPNEGO or other 255 * pseudo-mechanisms. 256 */ 257 if (actual_mech != GSS_C_NO_OID && 258 token_mech_type != GSS_C_NO_OID && 259 !g_OID_equal(actual_mech, token_mech_type)) { 260 *d_cred = tmp_d_cred; 261 } else { 262 gss_union_cred_t d_u_cred = NULL; 263 264 d_u_cred = malloc(sizeof (gss_union_cred_desc)); 265 if (d_u_cred == NULL) { 266 status = GSS_S_FAILURE; 267 goto error_out; 268 } 269 (void) memset(d_u_cred, 0, 270 sizeof (gss_union_cred_desc)); 271 272 d_u_cred->count = 1; 273 274 status = generic_gss_copy_oid( 275 &t_minstat, 276 actual_mech, 277 &d_u_cred->mechs_array); 278 279 if (status != GSS_S_COMPLETE) { 280 free(d_u_cred); 281 goto error_out; 282 } 283 284 d_u_cred->cred_array = malloc( 285 sizeof (gss_cred_id_t)); 286 if (d_u_cred->cred_array != NULL) { 287 d_u_cred->cred_array[0] = tmp_d_cred; 288 } else { 289 free(d_u_cred); 290 status = GSS_S_FAILURE; 291 goto error_out; 292 } 293 294 if (status != GSS_S_COMPLETE) { 295 free(d_u_cred->cred_array); 296 free(d_u_cred); 297 goto error_out; 298 } 299 300 internal_name = GSS_C_NO_NAME; 301 302 d_u_cred->auxinfo.creation_time = time(0); 303 d_u_cred->auxinfo.time_rec = 0; 304 305 if (mech->gss_inquire_cred) { 306 status = mech->gss_inquire_cred( 307 mech->context, 308 minor_status, 309 tmp_d_cred, 310 &internal_name, 311 &d_u_cred->auxinfo.time_rec, 312 &d_u_cred->auxinfo.cred_usage, 313 NULL); 314 } 315 316 if (internal_name != NULL) { 317 temp_status = 318 __gss_convert_name_to_union_name( 319 &t_minstat, mech, 320 internal_name, &tmp_src_name); 321 if (temp_status != GSS_S_COMPLETE) { 322 *minor_status = t_minstat; 323 if (output_token->length) 324 (void) gss_release_buffer( 325 &t_minstat, 326 output_token); 327 free(d_u_cred->cred_array); 328 free(d_u_cred); 329 return (temp_status); 330 } 331 } 332 333 if (tmp_src_name != NULL) { 334 status = gss_display_name( 335 &t_minstat, 336 tmp_src_name, 337 &d_u_cred->auxinfo.name, 338 &d_u_cred->auxinfo.name_type); 339 } 340 341 *d_cred = (gss_cred_id_t)d_u_cred; 342 } 343 } 344 if (ret_flags != NULL) { 345 *ret_flags = flags; 346 } 347 348 if (src_name == NULL && tmp_src_name != NULL) 349 (void) gss_release_name(&t_minstat, 350 &tmp_src_name); 351 return (status); 352 } else { 353 354 status = GSS_S_BAD_MECH; 355 } 356 357 error_out: 358 if (union_ctx_id) { 359 if (union_ctx_id->mech_type) { 360 if (union_ctx_id->mech_type->elements) 361 free(union_ctx_id->mech_type->elements); 362 free(union_ctx_id->mech_type); 363 } 364 free(union_ctx_id); 365 *context_handle = GSS_C_NO_CONTEXT; 366 } 367 368 if (output_token->length) 369 (void) gss_release_buffer(&t_minstat, output_token); 370 371 if (src_name) 372 *src_name = GSS_C_NO_NAME; 373 374 if (tmp_src_name != GSS_C_NO_NAME) 375 (void) gss_release_buffer(&t_minstat, 376 (gss_buffer_t)tmp_src_name); 377 378 return (status); 379 } 380