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