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