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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * glue routine for gss_accept_sec_context 27 */ 28 29 #include <mechglueP.h> 30 #include "gssapiP_generic.h" 31 #ifdef HAVE_STDLIB_H 32 #include <stdlib.h> 33 #endif 34 #include <string.h> 35 #include <errno.h> 36 #include <syslog.h> 37 38 #ifndef LEAN_CLIENT 39 static OM_uint32 40 val_acc_sec_ctx_args( 41 OM_uint32 *minor_status, 42 gss_ctx_id_t *context_handle, 43 gss_buffer_t input_token_buffer, 44 gss_name_t *src_name, 45 gss_OID *mech_type, 46 gss_buffer_t output_token, 47 gss_cred_id_t *d_cred) 48 { 49 50 /* Initialize outputs. */ 51 52 if (minor_status != NULL) 53 *minor_status = 0; 54 55 if (src_name != NULL) 56 *src_name = GSS_C_NO_NAME; 57 58 if (mech_type != NULL) 59 *mech_type = GSS_C_NO_OID; 60 61 if (output_token != GSS_C_NO_BUFFER) { 62 output_token->length = 0; 63 output_token->value = NULL; 64 } 65 66 if (d_cred != NULL) 67 *d_cred = GSS_C_NO_CREDENTIAL; 68 69 /* Validate arguments. */ 70 71 if (minor_status == NULL) 72 return (GSS_S_CALL_INACCESSIBLE_WRITE); 73 74 if (context_handle == NULL) 75 return (GSS_S_CALL_INACCESSIBLE_WRITE); 76 77 if (input_token_buffer == GSS_C_NO_BUFFER) 78 return (GSS_S_CALL_INACCESSIBLE_READ); 79 80 if (output_token == GSS_C_NO_BUFFER) 81 return (GSS_S_CALL_INACCESSIBLE_WRITE); 82 83 return (GSS_S_COMPLETE); 84 } 85 86 OM_uint32 87 gss_accept_sec_context(minor_status, 88 context_handle, 89 verifier_cred_handle, 90 input_token_buffer, 91 input_chan_bindings, 92 src_name, 93 mech_type, 94 output_token, 95 ret_flags, 96 time_rec, 97 d_cred) 98 99 OM_uint32 *minor_status; 100 gss_ctx_id_t *context_handle; 101 const gss_cred_id_t verifier_cred_handle; 102 const gss_buffer_t input_token_buffer; 103 const gss_channel_bindings_t input_chan_bindings; 104 gss_name_t *src_name; 105 gss_OID *mech_type; 106 gss_buffer_t output_token; 107 OM_uint32 *ret_flags; 108 OM_uint32 *time_rec; 109 gss_cred_id_t *d_cred; /* delegated cred handle */ 110 111 { 112 OM_uint32 status, temp_status, t_minstat; 113 gss_union_ctx_id_t union_ctx_id; 114 gss_union_cred_t union_cred; 115 gss_cred_id_t input_cred_handle = GSS_C_NO_CREDENTIAL; 116 gss_cred_id_t tmp_d_cred = GSS_C_NO_CREDENTIAL; 117 gss_name_t internal_name = GSS_C_NO_NAME; 118 gss_name_t tmp_src_name = GSS_C_NO_NAME; 119 gss_OID_desc token_mech_type_desc; 120 gss_OID token_mech_type = &token_mech_type_desc; 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 (input_token_buffer == GSS_C_NO_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 mech_type, 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 if (mech_type && (*mech_type != GSS_C_NULL_OID)) 212 map_error_oid(minor_status, *mech_type); 213 else { 214 map_error(minor_status, mech); 215 } 216 goto error_out; 217 } 218 219 220 /* 221 * if src_name is non-NULL, 222 * convert internal_name into a union name equivalent 223 * First call the mechanism specific display_name() 224 * then call gss_import_name() to create 225 * the union name struct cast to src_name 226 */ 227 if (internal_name != NULL) { 228 temp_status = __gss_convert_name_to_union_name( 229 &t_minstat, mech, 230 internal_name, &tmp_src_name); 231 if (temp_status != GSS_S_COMPLETE) { 232 *minor_status = t_minstat; 233 map_error(minor_status, mech); 234 if (output_token->length) 235 (void) gss_release_buffer( 236 &t_minstat, 237 output_token); 238 if (internal_name != GSS_C_NO_NAME) 239 mech->gss_release_name( 240 mech->context, 241 &t_minstat, 242 &internal_name); 243 return (temp_status); 244 } 245 if (src_name != NULL) { 246 *src_name = tmp_src_name; 247 } 248 } else if (src_name != NULL) { 249 *src_name = GSS_C_NO_NAME; 250 } 251 252 /* Ensure we're returning correct creds format */ 253 if ((flags & GSS_C_DELEG_FLAG) && 254 tmp_d_cred != GSS_C_NO_CREDENTIAL) { 255 /* 256 * If we got back an OID different from the original 257 * token OID, assume the delegated_cred is already 258 * a proper union_cred and just return it. Don't 259 * try to re-wrap it. This is for SPNEGO or other 260 * pseudo-mechanisms. 261 */ 262 if (*mech_type != GSS_C_NO_OID && 263 token_mech_type != GSS_C_NO_OID && 264 !g_OID_equal(*mech_type, token_mech_type)) { 265 *d_cred = tmp_d_cred; 266 } else { 267 gss_union_cred_t d_u_cred = NULL; 268 269 d_u_cred = malloc(sizeof (gss_union_cred_desc)); 270 if (d_u_cred == NULL) { 271 status = GSS_S_FAILURE; 272 goto error_out; 273 } 274 (void) memset(d_u_cred, 0, 275 sizeof (gss_union_cred_desc)); 276 277 d_u_cred->count = 1; 278 279 status = generic_gss_copy_oid( 280 &t_minstat, 281 *mech_type, 282 &d_u_cred->mechs_array); 283 284 if (status != GSS_S_COMPLETE) { 285 free(d_u_cred); 286 goto error_out; 287 } 288 289 d_u_cred->cred_array = malloc( 290 sizeof (gss_cred_id_t)); 291 if (d_u_cred->cred_array != NULL) { 292 d_u_cred->cred_array[0] = tmp_d_cred; 293 } else { 294 free(d_u_cred); 295 status = GSS_S_FAILURE; 296 goto error_out; 297 } 298 299 if (status != GSS_S_COMPLETE) { 300 free(d_u_cred->cred_array); 301 free(d_u_cred); 302 goto error_out; 303 } 304 305 internal_name = GSS_C_NO_NAME; 306 307 d_u_cred->auxinfo.creation_time = time(0); 308 d_u_cred->auxinfo.time_rec = 0; 309 310 if (mech->gss_inquire_cred) { 311 status = mech->gss_inquire_cred( 312 mech->context, 313 minor_status, 314 tmp_d_cred, 315 &internal_name, 316 &d_u_cred->auxinfo.time_rec, 317 &d_u_cred->auxinfo.cred_usage, 318 NULL); 319 } 320 321 if (status != GSS_S_COMPLETE) 322 map_error(minor_status, mech); 323 324 if (internal_name != NULL) { 325 temp_status = 326 __gss_convert_name_to_union_name( 327 &t_minstat, mech, 328 internal_name, &tmp_src_name); 329 if (temp_status != GSS_S_COMPLETE) { 330 *minor_status = t_minstat; 331 map_error(minor_status, mech); 332 if (output_token->length) 333 (void) gss_release_buffer( 334 &t_minstat, 335 output_token); 336 free(d_u_cred->cred_array); 337 free(d_u_cred); 338 return (temp_status); 339 } 340 } 341 342 if (tmp_src_name != NULL) { 343 status = gss_display_name( 344 &t_minstat, 345 tmp_src_name, 346 &d_u_cred->auxinfo.name, 347 &d_u_cred->auxinfo.name_type); 348 } 349 350 *d_cred = (gss_cred_id_t)d_u_cred; 351 } 352 } 353 if (ret_flags != NULL) { 354 *ret_flags = flags; 355 } 356 357 if (src_name == NULL && tmp_src_name != NULL) 358 (void) gss_release_name(&t_minstat, 359 &tmp_src_name); 360 return (status); 361 } else { 362 363 status = GSS_S_BAD_MECH; 364 } 365 366 error_out: 367 if (union_ctx_id) { 368 if (union_ctx_id->mech_type) { 369 if (union_ctx_id->mech_type->elements) 370 free(union_ctx_id->mech_type->elements); 371 free(union_ctx_id->mech_type); 372 } 373 free(union_ctx_id); 374 *context_handle = GSS_C_NO_CONTEXT; 375 } 376 377 #if 0 378 /* 379 * Solaris Kerberos 380 * Don't release, it causes a problem with error token. 381 */ 382 if (output_token->length) 383 (void) gss_release_buffer(&t_minstat, output_token); 384 #endif 385 386 if (src_name) 387 *src_name = GSS_C_NO_NAME; 388 389 if (tmp_src_name != GSS_C_NO_NAME) 390 (void) gss_release_buffer(&t_minstat, 391 (gss_buffer_t)tmp_src_name); 392 393 return (status); 394 } 395 #endif /* LEAN_CLIENT */ 396