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 * NB: __gss_convert_name_to_union_name will 227 * "consume" (free) the name. 228 */ 229 if (internal_name != NULL) { 230 temp_status = __gss_convert_name_to_union_name( 231 &t_minstat, mech, 232 internal_name, &tmp_src_name); 233 if (temp_status != GSS_S_COMPLETE) { 234 *minor_status = t_minstat; 235 map_error(minor_status, mech); 236 if (output_token->length) 237 (void) gss_release_buffer( 238 &t_minstat, 239 output_token); 240 return (temp_status); 241 } 242 if (src_name != NULL) { 243 *src_name = tmp_src_name; 244 } 245 } else if (src_name != NULL) { 246 *src_name = GSS_C_NO_NAME; 247 } 248 249 /* Ensure we're returning correct creds format */ 250 if ((flags & GSS_C_DELEG_FLAG) && 251 tmp_d_cred != GSS_C_NO_CREDENTIAL) { 252 /* 253 * If we got back an OID different from the original 254 * token OID, assume the delegated_cred is already 255 * a proper union_cred and just return it. Don't 256 * try to re-wrap it. This is for SPNEGO or other 257 * pseudo-mechanisms. 258 */ 259 if (*mech_type != GSS_C_NO_OID && 260 token_mech_type != GSS_C_NO_OID && 261 !g_OID_equal(*mech_type, token_mech_type)) { 262 *d_cred = tmp_d_cred; 263 } else { 264 gss_union_cred_t d_u_cred = NULL; 265 266 d_u_cred = malloc(sizeof (gss_union_cred_desc)); 267 if (d_u_cred == NULL) { 268 status = GSS_S_FAILURE; 269 goto error_out; 270 } 271 (void) memset(d_u_cred, 0, 272 sizeof (gss_union_cred_desc)); 273 274 d_u_cred->count = 1; 275 276 status = generic_gss_copy_oid( 277 &t_minstat, 278 *mech_type, 279 &d_u_cred->mechs_array); 280 281 if (status != GSS_S_COMPLETE) { 282 free(d_u_cred); 283 goto error_out; 284 } 285 286 d_u_cred->cred_array = malloc( 287 sizeof (gss_cred_id_t)); 288 if (d_u_cred->cred_array != NULL) { 289 d_u_cred->cred_array[0] = tmp_d_cred; 290 } else { 291 free(d_u_cred); 292 status = GSS_S_FAILURE; 293 goto error_out; 294 } 295 296 if (status != GSS_S_COMPLETE) { 297 free(d_u_cred->cred_array); 298 free(d_u_cred); 299 goto error_out; 300 } 301 302 internal_name = GSS_C_NO_NAME; 303 304 d_u_cred->auxinfo.creation_time = time(0); 305 d_u_cred->auxinfo.time_rec = 0; 306 307 if (mech->gss_inquire_cred) { 308 status = mech->gss_inquire_cred( 309 mech->context, 310 minor_status, 311 tmp_d_cred, 312 &internal_name, 313 &d_u_cred->auxinfo.time_rec, 314 &d_u_cred->auxinfo.cred_usage, 315 NULL); 316 } 317 318 if (status != GSS_S_COMPLETE) 319 map_error(minor_status, mech); 320 321 if (internal_name != NULL) { 322 temp_status = 323 __gss_convert_name_to_union_name( 324 &t_minstat, mech, 325 internal_name, &tmp_src_name); 326 if (temp_status != GSS_S_COMPLETE) { 327 *minor_status = t_minstat; 328 map_error(minor_status, mech); 329 if (output_token->length) 330 (void) gss_release_buffer( 331 &t_minstat, 332 output_token); 333 free(d_u_cred->cred_array); 334 free(d_u_cred); 335 return (temp_status); 336 } 337 } 338 339 if (tmp_src_name != NULL) { 340 status = gss_display_name( 341 &t_minstat, 342 tmp_src_name, 343 &d_u_cred->auxinfo.name, 344 &d_u_cred->auxinfo.name_type); 345 } 346 347 *d_cred = (gss_cred_id_t)d_u_cred; 348 } 349 } 350 if (ret_flags != NULL) { 351 *ret_flags = flags; 352 } 353 354 if (src_name == NULL && tmp_src_name != NULL) 355 (void) gss_release_name(&t_minstat, 356 &tmp_src_name); 357 return (status); 358 } else { 359 360 status = GSS_S_BAD_MECH; 361 } 362 363 error_out: 364 if (union_ctx_id) { 365 if (union_ctx_id->mech_type) { 366 if (union_ctx_id->mech_type->elements) 367 free(union_ctx_id->mech_type->elements); 368 free(union_ctx_id->mech_type); 369 } 370 free(union_ctx_id); 371 *context_handle = GSS_C_NO_CONTEXT; 372 } 373 374 #if 0 375 /* 376 * Solaris Kerberos 377 * Don't release, it causes a problem with error token. 378 */ 379 if (output_token->length) 380 (void) gss_release_buffer(&t_minstat, output_token); 381 #endif 382 383 if (src_name) 384 *src_name = GSS_C_NO_NAME; 385 386 if (tmp_src_name != GSS_C_NO_NAME) 387 (void) gss_release_buffer(&t_minstat, 388 (gss_buffer_t)tmp_src_name); 389 390 return (status); 391 } 392 #endif /* LEAN_CLIENT */ 393