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_acquire_cred 28 */ 29 #include <mechglueP.h> 30 #include <stdio.h> 31 #ifdef HAVE_STDLIB_H 32 #include <stdlib.h> 33 #endif 34 #include <string.h> 35 #include <errno.h> 36 #include <time.h> 37 38 /* local functions */ 39 static gss_OID_set create_actual_mechs(const gss_OID, int); 40 41 static gss_OID_set 42 create_actual_mechs(mechs_array, count) 43 const gss_OID mechs_array; 44 int count; 45 { 46 gss_OID_set actual_mechs; 47 int i; 48 OM_uint32 minor; 49 50 actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc)); 51 if (!actual_mechs) 52 return (NULL); 53 54 actual_mechs->elements = (gss_OID) 55 malloc(sizeof (gss_OID_desc) * count); 56 if (!actual_mechs->elements) { 57 free(actual_mechs); 58 return (NULL); 59 } 60 61 actual_mechs->count = 0; 62 63 for (i = 0; i < count; i++) { 64 actual_mechs->elements[i].elements = (void *) 65 malloc(mechs_array[i].length); 66 if (actual_mechs->elements[i].elements == NULL) { 67 (void) gss_release_oid_set(&minor, &actual_mechs); 68 return (NULL); 69 } 70 g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]); 71 actual_mechs->count++; 72 } 73 74 return (actual_mechs); 75 } 76 77 static OM_uint32 78 val_acq_cred_args( 79 OM_uint32 *minor_status, 80 gss_cred_id_t *output_cred_handle, 81 gss_OID_set *actual_mechs, 82 OM_uint32 *time_rec) 83 { 84 85 /* Initialize outputs. */ 86 87 if (minor_status != NULL) 88 *minor_status = 0; 89 90 if (output_cred_handle != NULL) 91 *output_cred_handle = GSS_C_NO_CREDENTIAL; 92 93 if (actual_mechs != NULL) 94 *actual_mechs = GSS_C_NULL_OID_SET; 95 96 if (time_rec != NULL) 97 *time_rec = 0; 98 99 /* Validate arguments. */ 100 101 if (minor_status == NULL) 102 return (GSS_S_CALL_INACCESSIBLE_WRITE); 103 104 if (output_cred_handle == NULL) 105 return (GSS_S_CALL_INACCESSIBLE_WRITE); 106 107 return (GSS_S_COMPLETE); 108 } 109 110 OM_uint32 111 gss_acquire_cred(minor_status, 112 desired_name, 113 time_req, 114 desired_mechs, 115 cred_usage, 116 output_cred_handle, 117 actual_mechs, 118 time_rec) 119 120 OM_uint32 * minor_status; 121 const gss_name_t desired_name; 122 OM_uint32 time_req; 123 const gss_OID_set desired_mechs; 124 int cred_usage; 125 gss_cred_id_t *output_cred_handle; 126 gss_OID_set * actual_mechs; 127 OM_uint32 * time_rec; 128 129 { 130 OM_uint32 major = GSS_S_FAILURE; 131 OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE; 132 gss_OID_set_desc default_OID_set; 133 gss_OID_set mechs; 134 gss_OID_desc default_OID; 135 gss_mechanism mech; 136 int i; 137 gss_union_cred_t creds; 138 139 major = val_acq_cred_args(minor_status, 140 output_cred_handle, 141 actual_mechs, 142 time_rec); 143 if (major != GSS_S_COMPLETE) 144 return (major); 145 146 /* Initial value needed below. */ 147 major = GSS_S_FAILURE; 148 149 /* 150 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an 151 * appropriate default. We use the first mechanism in the 152 * mechansim list as the default. This set is created with 153 * statics thus needs not be freed 154 */ 155 if (desired_mechs == GSS_C_NULL_OID_SET) { 156 mech = __gss_get_mechanism(NULL); 157 if (mech == NULL) 158 return (GSS_S_BAD_MECH); 159 160 mechs = &default_OID_set; 161 default_OID_set.count = 1; 162 default_OID_set.elements = &default_OID; 163 default_OID.length = mech->mech_type.length; 164 default_OID.elements = mech->mech_type.elements; 165 } else 166 mechs = desired_mechs; 167 168 if (mechs->count == NULL) 169 return (GSS_S_BAD_MECH); 170 171 /* allocate the output credential structure */ 172 creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc)); 173 if (creds == NULL) 174 return (GSS_S_FAILURE); 175 176 /* initialize to 0s */ 177 (void) memset(creds, 0, sizeof (gss_union_cred_desc)); 178 179 /* for each requested mech attempt to obtain a credential */ 180 for (i = 0; i < mechs->count; i++) { 181 major = gss_add_cred(minor_status, (gss_cred_id_t)creds, 182 desired_name, 183 &mechs->elements[i], 184 cred_usage, time_req, time_req, NULL, 185 NULL, &initTimeOut, &acceptTimeOut); 186 if (major == GSS_S_COMPLETE) { 187 /* update the credential's time */ 188 if (cred_usage == GSS_C_ACCEPT) { 189 if (outTime > acceptTimeOut) 190 outTime = acceptTimeOut; 191 } else if (cred_usage == GSS_C_INITIATE) { 192 if (outTime > initTimeOut) 193 outTime = initTimeOut; 194 } else { 195 /* 196 * time_rec is the lesser of the 197 * init/accept times 198 */ 199 if (initTimeOut > acceptTimeOut) 200 outTime = (outTime > acceptTimeOut) ? 201 acceptTimeOut : outTime; 202 else 203 outTime = (outTime > initTimeOut) ? 204 initTimeOut : outTime; 205 } 206 } 207 } /* for */ 208 209 /* ensure that we have at least one credential element */ 210 if (creds->count < 1) { 211 free(creds); 212 return (major); 213 } 214 215 /* 216 * fill in output parameters 217 * setup the actual mechs output parameter 218 */ 219 if (actual_mechs != NULL) { 220 if ((*actual_mechs = create_actual_mechs(creds->mechs_array, 221 creds->count)) == NULL) { 222 (void) gss_release_cred(minor_status, 223 (gss_cred_id_t *)&creds); 224 *minor_status = 0; 225 return (GSS_S_FAILURE); 226 } 227 } 228 229 if (time_rec) 230 *time_rec = outTime; 231 232 233 *output_cred_handle = (gss_cred_id_t)creds; 234 return (GSS_S_COMPLETE); 235 } 236 237 static OM_uint32 238 val_add_cred_args( 239 OM_uint32 *minor_status, 240 gss_cred_id_t input_cred_handle, 241 gss_cred_id_t *output_cred_handle, 242 gss_OID_set *actual_mechs, 243 OM_uint32 *initiator_time_rec, 244 OM_uint32 *acceptor_time_rec) 245 { 246 247 /* Initialize outputs. */ 248 249 if (minor_status != NULL) 250 *minor_status = 0; 251 252 if (output_cred_handle != NULL) 253 *output_cred_handle = GSS_C_NO_CREDENTIAL; 254 255 if (actual_mechs != NULL) 256 *actual_mechs = GSS_C_NO_OID_SET; 257 258 if (acceptor_time_rec != NULL) 259 *acceptor_time_rec = 0; 260 261 if (initiator_time_rec != NULL) 262 *initiator_time_rec = 0; 263 264 /* Validate arguments. */ 265 266 if (minor_status == NULL) 267 return (GSS_S_CALL_INACCESSIBLE_WRITE); 268 269 if (input_cred_handle == GSS_C_NO_CREDENTIAL && 270 output_cred_handle == NULL) 271 272 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); 273 274 return (GSS_S_COMPLETE); 275 } 276 277 /* V2 INTERFACE */ 278 OM_uint32 279 gss_add_cred(minor_status, input_cred_handle, 280 desired_name, desired_mech, cred_usage, 281 initiator_time_req, acceptor_time_req, 282 output_cred_handle, actual_mechs, 283 initiator_time_rec, acceptor_time_rec) 284 OM_uint32 *minor_status; 285 const gss_cred_id_t input_cred_handle; 286 const gss_name_t desired_name; 287 const gss_OID desired_mech; 288 gss_cred_usage_t cred_usage; 289 OM_uint32 initiator_time_req; 290 OM_uint32 acceptor_time_req; 291 gss_cred_id_t *output_cred_handle; 292 gss_OID_set *actual_mechs; 293 OM_uint32 *initiator_time_rec; 294 OM_uint32 *acceptor_time_rec; 295 { 296 OM_uint32 status, time_req, time_rec, temp_minor_status; 297 gss_mechanism mech; 298 gss_union_name_t union_name = NULL; 299 gss_union_cred_t union_cred, new_union_cred; 300 gss_name_t internal_name = GSS_C_NO_NAME; 301 gss_name_t allocated_name = GSS_C_NO_NAME; 302 gss_cred_id_t cred = NULL; 303 gss_OID new_mechs_array = NULL; 304 gss_cred_id_t *new_cred_array = NULL; 305 306 status = val_add_cred_args(minor_status, 307 input_cred_handle, 308 output_cred_handle, 309 actual_mechs, 310 initiator_time_rec, 311 acceptor_time_rec); 312 if (status != GSS_S_COMPLETE) 313 return (status); 314 315 mech = __gss_get_mechanism(desired_mech); 316 if (!mech) 317 return (GSS_S_BAD_MECH); 318 else if (!mech->gss_acquire_cred) 319 return (GSS_S_UNAVAILABLE); 320 321 if (input_cred_handle == GSS_C_NO_CREDENTIAL) { 322 union_cred = malloc(sizeof (gss_union_cred_desc)); 323 if (union_cred == NULL) 324 return (GSS_S_FAILURE); 325 326 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc)); 327 } else { 328 /* Input Cred is non-NULL */ 329 union_cred = (gss_union_cred_t)input_cred_handle; 330 331 if (__gss_get_mechanism_cred(union_cred, desired_mech) != 332 GSS_C_NO_CREDENTIAL) { 333 status = GSS_S_DUPLICATE_ELEMENT; 334 goto errout; 335 } 336 337 /* 338 * If no name was given, determine the name from the 339 * existing credential. 340 */ 341 if (desired_name == GSS_C_NO_NAME) { 342 if (gss_import_name(minor_status, 343 &union_cred->auxinfo.name, 344 union_cred->auxinfo.name_type, 345 &allocated_name) == GSS_S_COMPLETE && 346 (gss_canonicalize_name(minor_status, 347 allocated_name, 348 &mech->mech_type, 349 NULL) == GSS_S_COMPLETE)) { 350 internal_name = allocated_name; 351 } 352 } /* else, get the name from the desired_name below */ 353 } 354 if (desired_name != GSS_C_NO_NAME) { 355 /* may need to create a mechanism specific name */ 356 union_name = (gss_union_name_t)desired_name; 357 358 if (union_name->mech_type && 359 g_OID_equal(union_name->mech_type, 360 &mech->mech_type)) 361 internal_name = union_name->mech_name; 362 else { 363 if (__gss_import_internal_name(minor_status, 364 &mech->mech_type, union_name, 365 &allocated_name) != GSS_S_COMPLETE) { 366 status = GSS_S_BAD_NAME; 367 goto errout; 368 } 369 internal_name = allocated_name; 370 } 371 } 372 373 if (cred_usage == GSS_C_ACCEPT) 374 time_req = acceptor_time_req; 375 else if (cred_usage == GSS_C_INITIATE) 376 time_req = initiator_time_req; 377 else if (cred_usage == GSS_C_BOTH) 378 time_req = (acceptor_time_req > initiator_time_req) ? 379 acceptor_time_req : initiator_time_req; 380 381 status = mech->gss_acquire_cred(mech->context, minor_status, 382 internal_name, time_req, 383 GSS_C_NULL_OID_SET, cred_usage, 384 &cred, NULL, &time_rec); 385 386 if (status != GSS_S_COMPLETE) 387 goto errout; 388 389 /* may need to set credential auxinfo structure */ 390 if (union_cred->auxinfo.creation_time == 0) { 391 union_cred->auxinfo.creation_time = time(NULL); 392 union_cred->auxinfo.time_rec = time_rec; 393 union_cred->auxinfo.cred_usage = cred_usage; 394 395 /* 396 * If internal_name is GSS_C_NO_NAME a cred with no associated 397 * name was requested: don't set auxinfo.name or auxinfo.name_type. 398 */ 399 if (internal_name != GSS_C_NO_NAME) { 400 if ((status = mech->gss_display_name(mech->context, 401 &temp_minor_status, internal_name, 402 &union_cred->auxinfo.name, 403 &union_cred->auxinfo.name_type)) != 404 GSS_S_COMPLETE) 405 goto errout; 406 } 407 } 408 409 /* now add the new credential elements */ 410 new_mechs_array = (gss_OID) 411 malloc(sizeof (gss_OID_desc) * (union_cred->count+1)); 412 413 new_cred_array = (gss_cred_id_t *) 414 malloc(sizeof (gss_cred_id_t) * (union_cred->count+1)); 415 416 if (!new_mechs_array || !new_cred_array) { 417 status = GSS_S_FAILURE; 418 goto errout; 419 } 420 421 if (acceptor_time_rec) 422 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) 423 *acceptor_time_rec = time_rec; 424 if (initiator_time_rec) 425 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) 426 *initiator_time_rec = time_rec; 427 428 /* 429 * OK, expand the mechanism array and the credential array 430 */ 431 (void) memcpy(new_mechs_array, union_cred->mechs_array, 432 sizeof (gss_OID_desc) * union_cred->count); 433 (void) memcpy(new_cred_array, union_cred->cred_array, 434 sizeof (gss_cred_id_t) * union_cred->count); 435 436 new_cred_array[union_cred->count] = cred; 437 if ((new_mechs_array[union_cred->count].elements = 438 malloc(mech->mech_type.length)) == NULL) 439 goto errout; 440 441 g_OID_copy(&new_mechs_array[union_cred->count], 442 &mech->mech_type); 443 444 if (actual_mechs) { 445 *actual_mechs = create_actual_mechs(new_mechs_array, 446 union_cred->count + 1); 447 if (*actual_mechs == NULL) { 448 free(new_mechs_array[union_cred->count].elements); 449 goto errout; 450 } 451 } 452 453 if (output_cred_handle == NULL) { 454 free(union_cred->mechs_array); 455 free(union_cred->cred_array); 456 new_union_cred = union_cred; 457 } else { 458 new_union_cred = malloc(sizeof (gss_union_cred_desc)); 459 if (new_union_cred == NULL) { 460 free(new_mechs_array[union_cred->count].elements); 461 goto errout; 462 } 463 *new_union_cred = *union_cred; 464 *output_cred_handle = (gss_cred_id_t)new_union_cred; 465 } 466 467 new_union_cred->mechs_array = new_mechs_array; 468 new_union_cred->cred_array = new_cred_array; 469 new_union_cred->count++; 470 471 /* We're done with the internal name. Free it if we allocated it. */ 472 473 if (allocated_name) 474 (void) __gss_release_internal_name(&temp_minor_status, 475 &mech->mech_type, 476 &allocated_name); 477 478 return (GSS_S_COMPLETE); 479 480 errout: 481 if (new_mechs_array) 482 free(new_mechs_array); 483 if (new_cred_array) 484 free(new_cred_array); 485 486 if (cred != NULL && mech->gss_release_cred) 487 mech->gss_release_cred(mech->context, 488 &temp_minor_status, &cred); 489 490 if (allocated_name) 491 (void) __gss_release_internal_name(&temp_minor_status, 492 &mech->mech_type, 493 &allocated_name); 494 495 if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) { 496 if (union_cred->auxinfo.name.value) 497 free(union_cred->auxinfo.name.value); 498 free(union_cred); 499 } 500 501 return (status); 502 } 503