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