1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * Copyright 2000 by the Massachusetts Institute of Technology. 9 * All Rights Reserved. 10 * 11 * Export of this software from the United States of America may 12 * require a specific license from the United States Government. 13 * It is the responsibility of any person or organization contemplating 14 * export to obtain such a license before exporting. 15 * 16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 17 * distribute this software and its documentation for any purpose and 18 * without fee is hereby granted, provided that the above copyright 19 * notice appear in all copies and that both that copyright notice and 20 * this permission notice appear in supporting documentation, and that 21 * the name of M.I.T. not be used in advertising or publicity pertaining 22 * to distribution of the software without specific, written prior 23 * permission. Furthermore if you modify this software you must label 24 * your software as modified software and not distribute it in such a 25 * fashion that it might be confused with the original M.I.T. software. 26 * M.I.T. makes no representations about the suitability of 27 * this software for any purpose. It is provided "as is" without express 28 * or implied warranty. 29 * 30 */ 31 /* 32 * Copyright 1993 by OpenVision Technologies, Inc. 33 * 34 * Permission to use, copy, modify, distribute, and sell this software 35 * and its documentation for any purpose is hereby granted without fee, 36 * provided that the above copyright notice appears in all copies and 37 * that both that copyright notice and this permission notice appear in 38 * supporting documentation, and that the name of OpenVision not be used 39 * in advertising or publicity pertaining to distribution of the software 40 * without specific, written prior permission. OpenVision makes no 41 * representations about the suitability of this software for any 42 * purpose. It is provided "as is" without express or implied warranty. 43 * 44 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 45 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 46 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 47 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 48 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 49 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 50 * PERFORMANCE OF THIS SOFTWARE. 51 */ 52 53 /* 54 * Copyright (C) 1998 by the FundsXpress, INC. 55 * 56 * All rights reserved. 57 * 58 * Export of this software from the United States of America may require 59 * a specific license from the United States Government. It is the 60 * responsibility of any person or organization contemplating export to 61 * obtain such a license before exporting. 62 * 63 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 64 * distribute this software and its documentation for any purpose and 65 * without fee is hereby granted, provided that the above copyright 66 * notice appear in all copies and that both that copyright notice and 67 * this permission notice appear in supporting documentation, and that 68 * the name of FundsXpress. not be used in advertising or publicity pertaining 69 * to distribution of the software without specific, written prior 70 * permission. FundsXpress makes no representations about the suitability of 71 * this software for any purpose. It is provided "as is" without express 72 * or implied warranty. 73 * 74 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 75 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 76 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 77 */ 78 79 #include "k5-int.h" 80 #include "gss_libinit.h" 81 #include "gssapiP_krb5.h" 82 #include "mglueP.h" 83 #ifdef HAVE_STRING_H 84 #include <string.h> 85 #else 86 #include <strings.h> 87 #endif 88 89 #if defined(USE_LOGIN_LIBRARY) 90 #include <Kerberos/KerberosLoginPrivate.h> 91 #elif defined(USE_LEASH) 92 #ifdef _WIN64 93 #define LEASH_DLL "leashw64.dll" 94 #else 95 #define LEASH_DLL "leashw32.dll" 96 #endif 97 static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL; 98 static HANDLE hLeashDLL = INVALID_HANDLE_VALUE; 99 #endif 100 101 k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER; 102 static char *krb5_gss_keytab = NULL; 103 104 /* Heimdal calls this gsskrb5_register_acceptor_identity. */ 105 OM_uint32 KRB5_CALLCONV 106 krb5_gss_register_acceptor_identity(const char *keytab) 107 { 108 size_t len; 109 char *new, *old; 110 int err; 111 112 err = gssint_initialize_library(); 113 if (err != 0) 114 return GSS_S_FAILURE; 115 116 if (keytab == NULL) 117 return GSS_S_FAILURE; 118 119 len = strlen(keytab); 120 new = malloc(len + 1); 121 if (new == NULL) 122 return GSS_S_FAILURE; 123 strcpy(new, keytab); 124 125 err = k5_mutex_lock(&gssint_krb5_keytab_lock); 126 if (err) { 127 free(new); 128 return GSS_S_FAILURE; 129 } 130 old = krb5_gss_keytab; 131 krb5_gss_keytab = new; 132 k5_mutex_unlock(&gssint_krb5_keytab_lock); 133 if (old != NULL) 134 free(old); 135 return GSS_S_COMPLETE; 136 } 137 138 /* get credentials corresponding to a key in the krb5 keytab. 139 If the default name is requested, return the name in output_princ. 140 If output_princ is non-NULL, the caller will use or free it, regardless 141 of the return value. 142 If successful, set the keytab-specific fields in cred 143 */ 144 145 static OM_uint32 146 acquire_accept_cred(context, minor_status, desired_name, output_princ, cred) 147 krb5_context context; 148 OM_uint32 *minor_status; 149 gss_name_t desired_name; 150 krb5_principal *output_princ; 151 krb5_gss_cred_id_rec *cred; 152 { 153 krb5_error_code code; 154 krb5_principal princ; 155 krb5_keytab kt; 156 krb5_keytab_entry entry; 157 158 *output_princ = NULL; 159 cred->keytab = NULL; 160 161 /* open the default keytab */ 162 163 code = gssint_initialize_library(); 164 if (code != 0) { 165 *minor_status = code; 166 return GSS_S_FAILURE; 167 } 168 code = k5_mutex_lock(&gssint_krb5_keytab_lock); 169 if (code) { 170 *minor_status = code; 171 return GSS_S_FAILURE; 172 } 173 if (krb5_gss_keytab != NULL) { 174 code = krb5_kt_resolve(context, krb5_gss_keytab, &kt); 175 k5_mutex_unlock(&gssint_krb5_keytab_lock); 176 } else { 177 k5_mutex_unlock(&gssint_krb5_keytab_lock); 178 code = krb5_kt_default(context, &kt); 179 } 180 181 if (code) { 182 *minor_status = code; 183 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */ 184 return(GSS_S_NO_CRED); 185 } 186 187 if (desired_name != GSS_C_NO_NAME) { 188 princ = (krb5_principal) desired_name; 189 if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) { 190 (void) krb5_kt_close(context, kt); 191 if (code == KRB5_KT_NOTFOUND) 192 *minor_status = KG_KEYTAB_NOMATCH; 193 else 194 *minor_status = code; 195 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */ 196 return(GSS_S_NO_CRED); 197 } 198 krb5_kt_free_entry(context, &entry); 199 200 /* Open the replay cache for this principal. */ 201 if ((code = krb5_get_server_rcache(context, 202 krb5_princ_component(context, princ, 0), 203 &cred->rcache))) { 204 *minor_status = code; 205 return(GSS_S_FAILURE); 206 } 207 208 } 209 210 /* hooray. we made it */ 211 212 cred->keytab = kt; 213 214 return(GSS_S_COMPLETE); 215 } 216 217 /* get credentials corresponding to the default credential cache. 218 If the default name is requested, return the name in output_princ. 219 If output_princ is non-NULL, the caller will use or free it, regardless 220 of the return value. 221 If successful, set the ccache-specific fields in cred. 222 */ 223 224 static OM_uint32 225 acquire_init_cred(context, minor_status, desired_name, output_princ, cred) 226 krb5_context context; 227 OM_uint32 *minor_status; 228 gss_name_t desired_name; 229 krb5_principal *output_princ; 230 krb5_gss_cred_id_rec *cred; 231 { 232 krb5_error_code code; 233 krb5_ccache ccache; 234 krb5_principal princ, tmp_princ; 235 krb5_flags flags; 236 krb5_cc_cursor cur; 237 krb5_creds creds; 238 int got_endtime; 239 int caller_provided_ccache_name = 0; 240 241 cred->ccache = NULL; 242 243 /* load the GSS ccache name into the kg_context */ 244 245 if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) 246 return(GSS_S_FAILURE); 247 248 /* check to see if the caller provided a ccache name if so 249 * we will just use that and not search the cache collection */ 250 if (GSS_ERROR(kg_caller_provided_ccache_name (minor_status, &caller_provided_ccache_name))) { 251 return(GSS_S_FAILURE); 252 } 253 254 #if defined(USE_LOGIN_LIBRARY) || defined(USE_LEASH) 255 if (desired_name && !caller_provided_ccache_name) { 256 #if defined(USE_LOGIN_LIBRARY) 257 KLStatus err = klNoErr; 258 char *ccache_name = NULL; 259 KLPrincipal kl_desired_princ = NULL; 260 261 err = __KLCreatePrincipalFromKerberos5Principal ((krb5_principal) desired_name, 262 &kl_desired_princ); 263 264 if (!err) { 265 err = KLAcquireInitialTickets (kl_desired_princ, NULL, NULL, &ccache_name); 266 } 267 268 if (!err) { 269 err = krb5_cc_resolve (context, ccache_name, &ccache); 270 } 271 272 if (err) { 273 *minor_status = err; 274 return(GSS_S_CRED_UNAVAIL); 275 } 276 277 if (kl_desired_princ != NULL) { KLDisposePrincipal (kl_desired_princ); } 278 if (ccache_name != NULL) { KLDisposeString (ccache_name); } 279 280 #elif defined(USE_LEASH) 281 if ( hLeashDLL == INVALID_HANDLE_VALUE ) { 282 hLeashDLL = LoadLibrary(LEASH_DLL); 283 if ( hLeashDLL != INVALID_HANDLE_VALUE ) { 284 (FARPROC) pLeash_AcquireInitialTicketsIfNeeded = 285 GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded"); 286 } 287 } 288 289 if ( pLeash_AcquireInitialTicketsIfNeeded ) { 290 char ccname[256]=""; 291 pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname)); 292 if (!ccname[0]) { 293 *minor_status = KRB5_CC_NOTFOUND; 294 return(GSS_S_NO_CRED); 295 } 296 297 if ((code = krb5_cc_resolve (context, ccname, &ccache))) { 298 *minor_status = code; 299 return(GSS_S_NO_CRED); 300 } 301 } else { 302 /* leash dll not available, open the default credential cache */ 303 304 if ((code = krb5int_cc_default(context, &ccache))) { 305 *minor_status = code; 306 return(GSS_S_NO_CRED); 307 } 308 } 309 #endif /* USE_LEASH */ 310 } else 311 #endif /* USE_LOGIN_LIBRARY || USE_LEASH */ 312 { 313 /* open the default credential cache */ 314 315 if ((code = krb5int_cc_default(context, &ccache))) { 316 *minor_status = code; 317 return(GSS_S_NO_CRED); 318 } 319 } 320 321 /* turn off OPENCLOSE mode while extensive frobbing is going on */ 322 /* 323 * SUNW14resync 324 * Added calls to krb5_cc_set_flags(... KRB5_TC_OPENCLOSE) 325 * on the error returns cuz the 1.4 krb5_cc_close does not always close 326 * the file like it used to and caused STC test gss.27 to fail. 327 */ 328 flags = 0; /* turns off OPENCLOSE mode */ 329 if ((code = krb5_cc_set_flags(context, ccache, flags))) { 330 (void)krb5_cc_close(context, ccache); 331 *minor_status = code; 332 return(GSS_S_NO_CRED); 333 } 334 335 /* get out the principal name and see if it matches */ 336 337 if ((code = krb5_cc_get_principal(context, ccache, &princ))) { 338 /* Solaris Kerberos */ 339 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 340 (void)krb5_cc_close(context, ccache); 341 *minor_status = code; 342 return(GSS_S_FAILURE); 343 } 344 345 if (desired_name != (gss_name_t) NULL) { 346 if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) { 347 (void)krb5_free_principal(context, princ); 348 /* Solaris Kerberos */ 349 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 350 (void)krb5_cc_close(context, ccache); 351 *minor_status = KG_CCACHE_NOMATCH; 352 return(GSS_S_NO_CRED); 353 } 354 (void)krb5_free_principal(context, princ); 355 princ = (krb5_principal) desired_name; 356 } else { 357 *output_princ = princ; 358 } 359 360 /* iterate over the ccache, find the tgt */ 361 362 if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) { 363 /* Solaris Kerberos */ 364 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 365 (void)krb5_cc_close(context, ccache); 366 *minor_status = code; 367 return(GSS_S_FAILURE); 368 } 369 370 /* this is hairy. If there's a tgt for the principal's local realm 371 in here, that's what we want for the expire time. But if 372 there's not, then we want to use the first key. */ 373 374 got_endtime = 0; 375 376 code = krb5_build_principal_ext(context, &tmp_princ, 377 krb5_princ_realm(context, princ)->length, 378 krb5_princ_realm(context, princ)->data, 379 6, "krbtgt", 380 krb5_princ_realm(context, princ)->length, 381 krb5_princ_realm(context, princ)->data, 382 0); 383 if (code) { 384 /* Solaris Kerberos */ 385 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 386 (void)krb5_cc_close(context, ccache); 387 *minor_status = code; 388 return(GSS_S_FAILURE); 389 } 390 while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) { 391 if (krb5_principal_compare(context, tmp_princ, creds.server)) { 392 cred->tgt_expire = creds.times.endtime; 393 got_endtime = 1; 394 *minor_status = 0; 395 code = 0; 396 krb5_free_cred_contents(context, &creds); 397 break; 398 } 399 if (got_endtime == 0) { 400 cred->tgt_expire = creds.times.endtime; 401 got_endtime = 1; 402 } 403 krb5_free_cred_contents(context, &creds); 404 } 405 krb5_free_principal(context, tmp_princ); 406 407 if (code && code != KRB5_CC_END) { 408 /* this means some error occurred reading the ccache */ 409 (void)krb5_cc_end_seq_get(context, ccache, &cur); 410 /* Solaris Kerberos */ 411 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 412 (void)krb5_cc_close(context, ccache); 413 *minor_status = code; 414 return(GSS_S_FAILURE); 415 } else if (! got_endtime) { 416 /* this means the ccache was entirely empty */ 417 (void)krb5_cc_end_seq_get(context, ccache, &cur); 418 /* Solaris Kerberos */ 419 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 420 (void)krb5_cc_close(context, ccache); 421 *minor_status = KG_EMPTY_CCACHE; 422 return(GSS_S_FAILURE); 423 } else { 424 /* this means that we found an endtime to use. */ 425 if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) { 426 /* Solaris Kerberos */ 427 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); 428 (void)krb5_cc_close(context, ccache); 429 *minor_status = code; 430 return(GSS_S_FAILURE); 431 } 432 flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ 433 if ((code = krb5_cc_set_flags(context, ccache, flags))) { 434 (void)krb5_cc_close(context, ccache); 435 *minor_status = code; 436 return(GSS_S_FAILURE); 437 } 438 } 439 440 /* the credentials match and are valid */ 441 442 cred->ccache = ccache; 443 /* minor_status is set while we are iterating over the ccache */ 444 return(GSS_S_COMPLETE); 445 } 446 447 /*ARGSUSED*/ 448 OM_uint32 449 krb5_gss_acquire_cred(minor_status, desired_name, time_req, 450 desired_mechs, cred_usage, output_cred_handle, 451 actual_mechs, time_rec) 452 OM_uint32 *minor_status; 453 gss_name_t desired_name; 454 OM_uint32 time_req; 455 gss_OID_set desired_mechs; 456 gss_cred_usage_t cred_usage; 457 gss_cred_id_t *output_cred_handle; 458 gss_OID_set *actual_mechs; 459 OM_uint32 *time_rec; 460 { 461 krb5_context context; 462 size_t i; 463 krb5_gss_cred_id_t cred; 464 gss_OID_set ret_mechs; 465 int req_old, req_new; 466 OM_uint32 ret; 467 krb5_error_code code; 468 469 code = gssint_initialize_library(); 470 if (code) { 471 *minor_status = code; 472 return GSS_S_FAILURE; 473 } 474 475 code = krb5_gss_init_context(&context); 476 if (code) { 477 *minor_status = code; 478 return GSS_S_FAILURE; 479 } 480 481 /* make sure all outputs are valid */ 482 483 *output_cred_handle = NULL; 484 if (actual_mechs) 485 *actual_mechs = NULL; 486 if (time_rec) 487 *time_rec = 0; 488 489 /* validate the name */ 490 491 /*SUPPRESS 29*/ 492 if ((desired_name != (gss_name_t) NULL) && 493 (! kg_validate_name(desired_name))) { 494 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 495 krb5_free_context(context); 496 return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); 497 } 498 499 /* verify that the requested mechanism set is the default, or 500 contains krb5 */ 501 502 if (desired_mechs == GSS_C_NULL_OID_SET) { 503 req_old = 1; 504 req_new = 1; 505 } else { 506 req_old = 0; 507 req_new = 0; 508 509 for (i=0; i<desired_mechs->count; i++) { 510 if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i]))) 511 req_old++; 512 if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i]))) 513 req_new++; 514 } 515 516 if (!req_old && !req_new) { 517 *minor_status = 0; 518 krb5_free_context(context); 519 return(GSS_S_BAD_MECH); 520 } 521 } 522 523 /* create the gss cred structure */ 524 525 if ((cred = 526 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) { 527 *minor_status = ENOMEM; 528 krb5_free_context(context); 529 return(GSS_S_FAILURE); 530 } 531 memset(cred, 0, sizeof(krb5_gss_cred_id_rec)); 532 533 cred->usage = cred_usage; 534 cred->princ = NULL; 535 cred->prerfc_mech = req_old; 536 cred->rfc_mech = req_new; 537 538 cred->keytab = NULL; 539 cred->ccache = NULL; 540 541 code = k5_mutex_init(&cred->lock); 542 if (code) { 543 *minor_status = code; 544 krb5_free_context(context); 545 return GSS_S_FAILURE; 546 } 547 /* Note that we don't need to lock this GSSAPI credential record 548 here, because no other thread can gain access to it until we 549 return it. */ 550 551 if ((cred_usage != GSS_C_INITIATE) && 552 (cred_usage != GSS_C_ACCEPT) && 553 (cred_usage != GSS_C_BOTH)) { 554 k5_mutex_destroy(&cred->lock); 555 xfree(cred); 556 *minor_status = (OM_uint32) G_BAD_USAGE; 557 krb5_free_context(context); 558 return(GSS_S_FAILURE); 559 } 560 561 /* if requested, acquire credentials for accepting */ 562 /* this will fill in cred->princ if the desired_name is not specified */ 563 564 if ((cred_usage == GSS_C_ACCEPT) || 565 (cred_usage == GSS_C_BOTH)) 566 if ((ret = acquire_accept_cred(context, minor_status, desired_name, 567 &(cred->princ), cred)) 568 != GSS_S_COMPLETE) { 569 if (cred->princ) 570 krb5_free_principal(context, cred->princ); 571 k5_mutex_destroy(&cred->lock); 572 xfree(cred); 573 /* minor_status set by acquire_accept_cred() */ 574 krb5_free_context(context); 575 return(ret); 576 } 577 578 /* if requested, acquire credentials for initiation */ 579 /* this will fill in cred->princ if it wasn't set above, and 580 the desired_name is not specified */ 581 582 if ((cred_usage == GSS_C_INITIATE) || 583 (cred_usage == GSS_C_BOTH)) 584 if ((ret = 585 acquire_init_cred(context, minor_status, 586 cred->princ?(gss_name_t)cred->princ:desired_name, 587 &(cred->princ), cred)) 588 != GSS_S_COMPLETE) { 589 if (cred->keytab) 590 krb5_kt_close(context, cred->keytab); 591 if (cred->princ) 592 krb5_free_principal(context, cred->princ); 593 k5_mutex_destroy(&cred->lock); 594 xfree(cred); 595 /* minor_status set by acquire_init_cred() */ 596 krb5_free_context(context); 597 return(ret); 598 } 599 600 /* Solaris Kerberos: 601 * if the princ wasn't filled in already, fill it in now unless 602 * a cred with no associated princ is requested (will invoke default 603 * behaviour when gss_accept_init_context() is called). 604 * Note MIT 1.4 has GSS_C_NO_CREDENTIAL instead of GSS_C_NO_NAME 605 */ 606 if (!cred->princ && (desired_name != GSS_C_NO_NAME)) 607 if ((code = krb5_copy_principal(context, (krb5_principal) desired_name, 608 &(cred->princ)))) { 609 if (cred->ccache) 610 (void)krb5_cc_close(context, cred->ccache); 611 if (cred->keytab) 612 (void)krb5_kt_close(context, cred->keytab); 613 k5_mutex_destroy(&cred->lock); 614 xfree(cred); 615 *minor_status = code; 616 krb5_free_context(context); 617 return(GSS_S_FAILURE); 618 } 619 620 /*** at this point, the cred structure has been completely created */ 621 622 /* compute time_rec */ 623 624 if (cred_usage == GSS_C_ACCEPT) { 625 if (time_rec) 626 *time_rec = GSS_C_INDEFINITE; 627 } else { 628 krb5_timestamp now; 629 630 if ((code = krb5_timeofday(context, &now))) { 631 if (cred->ccache) 632 (void)krb5_cc_close(context, cred->ccache); 633 if (cred->keytab) 634 (void)krb5_kt_close(context, cred->keytab); 635 if (cred->princ) 636 krb5_free_principal(context, cred->princ); 637 k5_mutex_destroy(&cred->lock); 638 xfree(cred); 639 *minor_status = code; 640 krb5_free_context(context); 641 return(GSS_S_FAILURE); 642 } 643 644 if (time_rec) 645 *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0; 646 } 647 648 /* create mechs */ 649 650 if (actual_mechs) { 651 if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status, 652 &ret_mechs)) || 653 (cred->prerfc_mech && 654 GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, 655 (const gss_OID) gss_mech_krb5_old, 656 &ret_mechs))) || 657 (cred->rfc_mech && 658 GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, 659 (const gss_OID) gss_mech_krb5, 660 &ret_mechs)))) { 661 if (cred->ccache) 662 (void)krb5_cc_close(context, cred->ccache); 663 if (cred->keytab) 664 (void)krb5_kt_close(context, cred->keytab); 665 if (cred->princ) 666 krb5_free_principal(context, cred->princ); 667 k5_mutex_destroy(&cred->lock); 668 xfree(cred); 669 /* *minor_status set above */ 670 krb5_free_context(context); 671 return(ret); 672 } 673 } 674 675 /* intern the credential handle */ 676 677 if (! kg_save_cred_id((gss_cred_id_t) cred)) { 678 free(ret_mechs->elements); 679 free(ret_mechs); 680 if (cred->ccache) 681 (void)krb5_cc_close(context, cred->ccache); 682 if (cred->keytab) 683 (void)krb5_kt_close(context, cred->keytab); 684 if (cred->princ) 685 krb5_free_principal(context, cred->princ); 686 k5_mutex_destroy(&cred->lock); 687 xfree(cred); 688 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 689 krb5_free_context(context); 690 return(GSS_S_FAILURE); 691 } 692 693 /* return success */ 694 695 *minor_status = 0; 696 *output_cred_handle = (gss_cred_id_t) cred; 697 if (actual_mechs) 698 *actual_mechs = ret_mechs; 699 700 krb5_free_context(context); 701 return(GSS_S_COMPLETE); 702 } 703