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 2004 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, temp_minor_status; 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_mechanism mech; 76 77 /* check parameters first */ 78 if (minor_status == NULL) 79 return (GSS_S_CALL_INACCESSIBLE_WRITE); 80 *minor_status = 0; 81 82 if (context_handle == NULL || output_token == NULL) 83 return (GSS_S_CALL_INACCESSIBLE_WRITE); 84 85 /* clear optional fields */ 86 output_token->value = NULL; 87 output_token->length = 0; 88 if (src_name) 89 *src_name = NULL; 90 91 if (mech_type) 92 *mech_type = NULL; 93 94 if (d_cred) 95 *d_cred = NULL; 96 /* 97 * if context_handle is GSS_C_NO_CONTEXT, allocate a union context 98 * descriptor to hold the mech type information as well as the 99 * underlying mechanism context handle. Otherwise, cast the 100 * value of *context_handle to the union context variable. 101 */ 102 103 if (*context_handle == GSS_C_NO_CONTEXT) { 104 105 if (GSS_EMPTY_BUFFER(input_token_buffer)) 106 return (GSS_S_CALL_INACCESSIBLE_READ); 107 108 /* Get the token mech type */ 109 status = __gss_get_mech_type(token_mech_type, 110 input_token_buffer); 111 112 if (status) 113 return (status); 114 115 status = GSS_S_FAILURE; 116 union_ctx_id = (gss_union_ctx_id_t) 117 malloc(sizeof (gss_union_ctx_id_desc)); 118 if (!union_ctx_id) 119 return (GSS_S_FAILURE); 120 121 union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT; 122 status = generic_gss_copy_oid(&temp_minor_status, 123 token_mech_type, 124 &union_ctx_id->mech_type); 125 if (status != GSS_S_COMPLETE) { 126 free(union_ctx_id); 127 return (status); 128 } 129 130 /* set the new context handle to caller's data */ 131 *context_handle = (gss_ctx_id_t)union_ctx_id; 132 } else { 133 union_ctx_id = (gss_union_ctx_id_t)*context_handle; 134 token_mech_type = union_ctx_id->mech_type; 135 } 136 137 /* 138 * get the appropriate cred handle from the union cred struct. 139 * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will 140 * use the default credential. 141 */ 142 union_cred = (gss_union_cred_t)verifier_cred_handle; 143 input_cred_handle = __gss_get_mechanism_cred(union_cred, 144 token_mech_type); 145 146 /* 147 * now select the approprate underlying mechanism routine and 148 * call it. 149 */ 150 151 mech = __gss_get_mechanism(token_mech_type); 152 if (mech && mech->gss_accept_sec_context) { 153 status = mech->gss_accept_sec_context( 154 mech->context, 155 minor_status, 156 &union_ctx_id->internal_ctx_id, 157 input_cred_handle, 158 input_token_buffer, 159 input_chan_bindings, 160 &internal_name, 161 mech_type, 162 output_token, 163 ret_flags, 164 time_rec, 165 d_cred ? &tmp_d_cred : NULL); 166 167 /* If there's more work to do, keep going... */ 168 if (status == GSS_S_CONTINUE_NEEDED) 169 return (GSS_S_CONTINUE_NEEDED); 170 171 /* if the call failed, return with failure */ 172 if (status != GSS_S_COMPLETE) 173 goto error_out; 174 175 /* 176 * if src_name is non-NULL, 177 * convert internal_name into a union name equivalent 178 * First call the mechanism specific display_name() 179 * then call gss_import_name() to create 180 * the union name struct cast to src_name 181 */ 182 if (internal_name != NULL) { 183 temp_status = __gss_convert_name_to_union_name( 184 &temp_minor_status, mech, 185 internal_name, &tmp_src_name); 186 if (temp_status != GSS_S_COMPLETE) { 187 *minor_status = temp_minor_status; 188 if (output_token->length) 189 (void) gss_release_buffer( 190 &temp_minor_status, 191 output_token); 192 if (internal_name != GSS_C_NO_NAME) 193 mech->gss_release_name( 194 mech->context, 195 &temp_minor_status, 196 &internal_name); 197 return (temp_status); 198 } 199 if (src_name != NULL) { 200 *src_name = tmp_src_name; 201 } 202 } else if (src_name != NULL) { 203 *src_name = GSS_C_NO_NAME; 204 } 205 206 /* Ensure we're returning correct creds format */ 207 if ((ret_flags && GSS_C_DELEG_FLAG) && 208 tmp_d_cred != GSS_C_NO_CREDENTIAL) { 209 gss_union_cred_t d_u_cred = NULL; 210 211 d_u_cred = malloc(sizeof (gss_union_cred_desc)); 212 if (d_u_cred == NULL) { 213 status = GSS_S_FAILURE; 214 goto error_out; 215 } 216 (void) memset(d_u_cred, 0, 217 sizeof (gss_union_cred_desc)); 218 219 d_u_cred->count = 1; 220 221 status = generic_gss_copy_oid(&temp_minor_status, 222 token_mech_type, 223 &d_u_cred->mechs_array); 224 225 if (status != GSS_S_COMPLETE) { 226 free(d_u_cred); 227 goto error_out; 228 } 229 230 d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t)); 231 if (d_u_cred->cred_array != NULL) { 232 d_u_cred->cred_array[0] = tmp_d_cred; 233 } else { 234 free(d_u_cred); 235 status = GSS_S_FAILURE; 236 goto error_out; 237 } 238 239 if (status != GSS_S_COMPLETE) { 240 free(d_u_cred->cred_array); 241 free(d_u_cred); 242 goto error_out; 243 } 244 245 internal_name = GSS_C_NO_NAME; 246 247 d_u_cred->auxinfo.creation_time = time(0); 248 d_u_cred->auxinfo.time_rec = 0; 249 250 if (mech->gss_inquire_cred) { 251 status = mech->gss_inquire_cred(mech->context, 252 minor_status, 253 tmp_d_cred, 254 &internal_name, 255 &d_u_cred->auxinfo.time_rec, 256 &d_u_cred->auxinfo.cred_usage, 257 NULL); 258 } 259 260 if (internal_name != NULL) { 261 temp_status = __gss_convert_name_to_union_name( 262 &temp_minor_status, mech, 263 internal_name, &tmp_src_name); 264 if (temp_status != GSS_S_COMPLETE) { 265 *minor_status = temp_minor_status; 266 if (output_token->length) 267 (void) gss_release_buffer( 268 &temp_minor_status, 269 output_token); 270 free(d_u_cred->cred_array); 271 free(d_u_cred); 272 return (temp_status); 273 } 274 } 275 276 if (tmp_src_name != NULL) { 277 status = gss_display_name( 278 &temp_minor_status, 279 tmp_src_name, 280 &d_u_cred->auxinfo.name, 281 &d_u_cred->auxinfo.name_type); 282 } 283 284 *d_cred = (gss_cred_id_t)d_u_cred; 285 } 286 287 if (src_name == NULL && tmp_src_name != NULL) 288 (void) gss_release_name(&temp_minor_status, 289 &tmp_src_name); 290 return (status); 291 } else { 292 293 status = GSS_S_BAD_MECH; 294 } 295 296 error_out: 297 if (union_ctx_id) { 298 if (union_ctx_id->mech_type) { 299 if (union_ctx_id->mech_type->elements) 300 free(union_ctx_id->mech_type->elements); 301 free(union_ctx_id->mech_type); 302 } 303 free(union_ctx_id); 304 *context_handle = GSS_C_NO_CONTEXT; 305 } 306 307 if (output_token->length) 308 (void) gss_release_buffer(&temp_minor_status, output_token); 309 310 if (src_name) 311 *src_name = GSS_C_NO_NAME; 312 313 if (tmp_src_name != GSS_C_NO_NAME) 314 (void) gss_release_buffer(&temp_minor_status, 315 (gss_buffer_t)tmp_src_name); 316 317 return (status); 318 } 319