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