int main (int argc, char **argv) { TALLOC_CTX *mem_ctx = talloc_init("ktutil"); krb5_context context; krb5_keytab keytab; krb5_kt_cursor cursor; krb5_keytab_entry entry; krb5_error_code ret; char *keytab_name = NULL; if (mem_ctx == NULL) { printf("talloc_init() failed\n"); exit(1); } if (argc != 2) { printf("Usage: %s KEYTAB\n", argv[0]); exit(1); } keytab_name = argv[1]; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "krb5_context"); } ret = smb_krb5_open_keytab_relative(context, keytab_name, false, &keytab); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "open keytab"); } ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "krb5_kt_start_seq_get"); } for (ret = krb5_kt_next_entry(context, keytab, &entry, &cursor); ret == 0; ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) { char *principal = NULL; char *enctype_str = NULL; krb5_enctype enctype = smb_get_enctype_from_kt_entry(&entry); ret = smb_krb5_unparse_name(mem_ctx, context, entry.principal, &principal); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "krb5_enctype_to_string"); } ret = smb_krb5_enctype_to_string(context, enctype, &enctype_str); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "krb5_enctype_to_string"); } printf("%s (%s)\n", principal, enctype_str); TALLOC_FREE(principal); SAFE_FREE(enctype_str); smb_krb5_kt_free_entry(context, &entry); } ret = krb5_kt_end_seq_get(context, keytab, &cursor); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "krb5_kt_end_seq_get"); } ret = krb5_kt_close(context, keytab); if (ret) { smb_krb5_err(mem_ctx, context, 1, ret, "krb5_kt_close"); } krb5_free_context(context); talloc_free(mem_ctx); return 0; }
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, const char *realm, time_t time_offset, const DATA_BLOB *ticket, char **principal, struct PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key, bool use_replay_cache) { NTSTATUS sret = NT_STATUS_LOGON_FAILURE; NTSTATUS pac_ret; DATA_BLOB auth_data; krb5_context context = NULL; krb5_auth_context auth_context = NULL; krb5_data packet; krb5_ticket *tkt = NULL; krb5_rcache rcache = NULL; krb5_keyblock *keyblock = NULL; time_t authtime; krb5_error_code ret = 0; int flags = 0; krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; bool auth_ok = False; bool got_auth_data = False; struct named_mutex *mutex = NULL; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); *principal = NULL; *pac_data = NULL; *ap_rep = data_blob_null; *session_key = data_blob_null; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret))); return NT_STATUS_LOGON_FAILURE; } if (time_offset != 0) { krb5_set_real_time(context, time(NULL) + time_offset, 0); } ret = krb5_set_default_realm(context, realm); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret))); goto out; } /* This whole process is far more complex than I would like. We have to go through all this to allow us to store the secret internally, instead of using /etc/krb5.keytab */ ret = krb5_auth_con_init(context, &auth_context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret))); goto out; } krb5_auth_con_getflags( context, auth_context, &flags ); if ( !use_replay_cache ) { /* Disable default use of a replay cache */ flags &= ~KRB5_AUTH_CONTEXT_DO_TIME; krb5_auth_con_setflags( context, auth_context, flags ); } if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) { goto out; } strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret))); goto out; } if ( use_replay_cache ) { /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 code surrounding the replay cache... */ mutex = grab_named_mutex(talloc_tos(), "replay cache mutex", 10); if (mutex == NULL) { DEBUG(1,("ads_verify_ticket: unable to protect " "replay cache with mutex.\n")); ret = KRB5_CC_IO; goto out; } /* JRA. We must set the rcache here. This will prevent replay attacks. */ ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache " "failed (%s)\n", error_message(ret))); goto out; } ret = krb5_auth_con_setrcache(context, auth_context, rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache " "failed (%s)\n", error_message(ret))); goto out; } } /* Try secrets.tdb first and fallback to the krb5.keytab if necessary */ auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, ticket, &tkt, &keyblock, &ret); if (!auth_ok && (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW)) { goto auth_failed; } if (!auth_ok && lp_use_kerberos_keytab()) { auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); } if ( use_replay_cache ) { TALLOC_FREE(mutex); #if 0 /* Heimdal leaks here, if we fix the leak, MIT crashes */ if (rcache) { krb5_rc_close(context, rcache); } #endif } auth_failed: if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); /* Try map the error return in case it's something like * a clock skew error. */ sret = krb5_to_nt_status(ret); if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { sret = NT_STATUS_LOGON_FAILURE; } DEBUG(10,("ads_verify_ticket: returning error %s\n", nt_errstr(sret) )); goto out; } authtime = get_authtime_from_tkt(tkt); client_principal = get_principal_from_tkt(tkt); ret = krb5_mk_rep(context, auth_context, &packet); if (ret) { DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", error_message(ret))); goto out; } *ap_rep = data_blob(packet.data, packet.length); if (packet.data) { kerberos_free_data_contents(context, &packet); ZERO_STRUCT(packet); } get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); #if 0 file_save("/tmp/ticket.dat", ticket->data, ticket->length); #endif /* continue when no PAC is retrieved or we couldn't decode the PAC (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or Kerberos tickets encrypted using a DES key) - Guenther */ got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt); if (!got_auth_data) { DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n")); } if (got_auth_data) { pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data); if (!NT_STATUS_IS_OK(pac_ret)) { DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret))); *pac_data = NULL; } data_blob_free(&auth_data); } #if 0 #if defined(HAVE_KRB5_TKT_ENC_PART2) /* MIT */ if (tkt->enc_part2) { file_save("/tmp/authdata.dat", tkt->enc_part2->authorization_data[0]->contents, tkt->enc_part2->authorization_data[0]->length); } #else /* Heimdal */ if (tkt->ticket.authorization_data) { file_save("/tmp/authdata.dat", tkt->ticket.authorization_data->val->ad_data.data, tkt->ticket.authorization_data->val->ad_data.length); } #endif #endif if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) { DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); sret = NT_STATUS_LOGON_FAILURE; goto out; } sret = NT_STATUS_OK; out: TALLOC_FREE(mutex); if (!NT_STATUS_IS_OK(sret)) { data_blob_free(&auth_data); } if (!NT_STATUS_IS_OK(sret)) { data_blob_free(ap_rep); } if (host_princ) { krb5_free_principal(context, host_princ); } if (keyblock) { krb5_free_keyblock(context, keyblock); } if (tkt != NULL) { krb5_free_ticket(context, tkt); } SAFE_FREE(host_princ_s); if (auth_context) { krb5_auth_con_free(context, auth_context); } if (context) { krb5_free_context(context); } return sret; }
static bool ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) { krb5_error_code ret = 0; bool auth_ok = False; krb5_keytab keytab = NULL; krb5_kt_cursor kt_cursor; krb5_keytab_entry kt_entry; char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; char *entry_princ_s = NULL; fstring my_name, my_fqdn; int i; int number_matched_principals = 0; krb5_data packet; *pp_tkt = NULL; *keyblock = NULL; *perr = 0; /* Generate the list of principal names which we expect * clients might want to use for authenticating to the file * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */ fstrcpy(my_name, global_myname()); my_fqdn[0] = '\0'; name_to_fqdn(my_fqdn, global_myname()); if (asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) { goto out; } ZERO_STRUCT(kt_entry); ZERO_STRUCT(kt_cursor); ret = smb_krb5_open_keytab(context, NULL, False, &keytab); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_open_keytab failed (%s)\n", error_message(ret))); goto out; } /* Iterate through the keytab. For each key, if the principal * name case-insensitively matches one of the allowed formats, * try verifying the ticket using that principal. */ ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret))); goto out; } while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) { ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto out; } for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { if (!strequal(entry_princ_s, valid_princ_formats[i])) { continue; } number_matched_principals++; packet.length = ticket->length; packet.data = (char *)ticket->data; *pp_tkt = NULL; ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, kt_entry.principal, keytab, NULL, pp_tkt, keyblock); if (ret) { DEBUG(10,("ads_keytab_verify_ticket: " "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n", entry_princ_s, error_message(ret))); /* workaround for MIT: * as krb5_ktfile_get_entry will explicitly * close the krb5_keytab as soon as krb5_rd_req * has successfully decrypted the ticket but the * ticket is not valid yet (due to clockskew) * there is no point in querying more keytab * entries - Guenther */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW) { break; } } else { DEBUG(3,("ads_keytab_verify_ticket: " "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n", entry_princ_s)); auth_ok = True; break; } } /* Free the name we parsed. */ SAFE_FREE(entry_princ_s); /* Free the entry we just read. */ smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); } krb5_kt_end_seq_get(context, keytab, &kt_cursor); ZERO_STRUCT(kt_cursor); out: for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { SAFE_FREE(valid_princ_formats[i]); } if (!auth_ok) { if (!number_matched_principals) { DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n")); } else { DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n", number_matched_principals)); } } SAFE_FREE(entry_princ_s); { krb5_keytab_entry zero_kt_entry; ZERO_STRUCT(zero_kt_entry); if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { smb_krb5_kt_free_entry(context, &kt_entry); } } { krb5_kt_cursor zero_csr; ZERO_STRUCT(zero_csr); if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { krb5_kt_end_seq_get(context, keytab, &kt_cursor); } } if (keytab) { krb5_kt_close(context, keytab); } *perr = ret; return auth_ok; }
struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *ctx, const char *principal, int kvno, const krb5_enctype enctype, TALLOC_CTX *mem_ctx) { krb5_error_code ret = 0; krb5_kt_cursor cursor; krb5_keytab_entry kt_entry; struct libnet_keytab_entry *entry = NULL; ZERO_STRUCT(kt_entry); ZERO_STRUCT(cursor); ret = krb5_kt_start_seq_get(ctx->context, ctx->keytab, &cursor); if (ret) { DEBUG(10, ("krb5_kt_start_seq_get failed: %s\n", error_message(ret))); return NULL; } while (krb5_kt_next_entry(ctx->context, ctx->keytab, &kt_entry, &cursor) == 0) { krb5_keyblock *keyp; char *princ_s = NULL; entry = NULL; if (kt_entry.vno != kvno) { goto cont; } keyp = KRB5_KT_KEY(&kt_entry); if (KRB5_KEY_TYPE(keyp) != enctype) { goto cont; } entry = talloc_zero(mem_ctx, struct libnet_keytab_entry); if (!entry) { DEBUG(3, ("talloc failed\n")); goto fail; } ret = smb_krb5_unparse_name(entry, ctx->context, kt_entry.principal, &princ_s); if (ret) { goto cont; } if (strcmp(principal, princ_s) != 0) { goto cont; } entry->principal = talloc_strdup(entry, princ_s); if (!entry->principal) { DEBUG(3, ("talloc_strdup_failed\n")); goto fail; } entry->name = talloc_move(entry, &princ_s); entry->password = data_blob_talloc(entry, KRB5_KEY_DATA(keyp), KRB5_KEY_LENGTH(keyp)); if (!entry->password.data) { DEBUG(3, ("data_blob_talloc failed\n")); goto fail; } DEBUG(10, ("found entry\n")); smb_krb5_kt_free_entry(ctx->context, &kt_entry); break; fail: smb_krb5_kt_free_entry(ctx->context, &kt_entry); TALLOC_FREE(entry); break; cont: smb_krb5_kt_free_entry(ctx->context, &kt_entry); TALLOC_FREE(entry); continue; } krb5_kt_end_seq_get(ctx->context, ctx->keytab, &cursor); return entry; }
/** * Remove all entries that have the given principal, kvno and enctype. */ static krb5_error_code libnet_keytab_remove_entries(krb5_context context, krb5_keytab keytab, const char *principal, int kvno, const krb5_enctype enctype, bool ignore_kvno) { krb5_error_code ret; krb5_kt_cursor cursor; krb5_keytab_entry kt_entry; ZERO_STRUCT(kt_entry); ZERO_STRUCT(cursor); ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { return 0; } while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) { krb5_keyblock *keyp; char *princ_s = NULL; if (kt_entry.vno != kvno && !ignore_kvno) { goto cont; } keyp = KRB5_KT_KEY(&kt_entry); if (KRB5_KEY_TYPE(keyp) != enctype) { goto cont; } ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &princ_s); if (ret) { DEBUG(5, ("smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto cont; } if (strcmp(principal, princ_s) != 0) { goto cont; } /* match found - remove */ DEBUG(10, ("found entry for principal %s, kvno %d, " "enctype %d - trying to remove it\n", princ_s, kt_entry.vno, KRB5_KEY_TYPE(keyp))); ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n", error_message(ret))); goto cont; } ret = krb5_kt_remove_entry(context, keytab, &kt_entry); if (ret) { DEBUG(5, ("krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto cont; } DEBUG(10, ("removed entry for principal %s, kvno %d, " "enctype %d\n", princ_s, kt_entry.vno, KRB5_KEY_TYPE(keyp))); ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { DEBUG(5, ("krb5_kt_start_seq_get failed (%s)\n", error_message(ret))); goto cont; } cont: smb_krb5_kt_free_entry(context, &kt_entry); TALLOC_FREE(princ_s); } ret = krb5_kt_end_seq_get(context, keytab, &cursor); if (ret) { DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n", error_message(ret))); } return ret; }
static krb5_error_code ads_keytab_verify_for_principal(krb5_context context, krb5_auth_context auth_context, const krb5_keytab_entry * kt_entry, const DATA_BLOB * ticket, const char * svc_principal, krb5_ticket ** pp_tkt, krb5_keyblock ** keyblock) { krb5_error_code ret = 0; krb5_keytab keytab = NULL; krb5_data packet; char * entry_princ_s = NULL; ret = krb5_kt_default(context, &keytab); if (ret) { DEBUG(1, ("ads_keytab_verify_for_principal: krb5_kt_default failed (%s)\n", error_message(ret))); goto out; } ret = smb_krb5_unparse_name(context, kt_entry->principal, &entry_princ_s); if (ret) { DEBUG(1, ("ads_keytab_verify_for_principal: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto out; } if (!strequal(entry_princ_s, svc_principal)) { ret = KRB5KRB_AP_ERR_BADMATCH; goto out; } packet.length = ticket->length; packet.data = (char *)ticket->data; *pp_tkt = NULL; ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, kt_entry, keytab, pp_tkt, keyblock); if (ret) { DEBUG(3,("ads_keytab_verify_for_principal: " "failed for principal %s: %s\n", entry_princ_s, error_message(ret))); goto out; } DEBUG(3,("ads_keytab_verify_for_principal: succeeded for principal %s\n", entry_princ_s)); out: /* Free the name we parsed. */ SAFE_FREE(entry_princ_s); if (keytab) { krb5_kt_close(context, keytab); keytab = NULL; } return ret; }
static krb5_error_code get_key_from_keytab(krb5_context context, krb5_const_principal server, krb5_enctype enctype, krb5_kvno kvno, krb5_keyblock **out_key) { krb5_keytab_entry entry; krb5_error_code ret; krb5_keytab keytab; char *name = NULL; /* We have to open a new keytab handle here, as MIT does an implicit open/getnext/close on krb5_kt_get_entry. We may be in the middle of a keytab enumeration when this is called. JRA. */ ret = krb5_kt_default(context, &keytab); if (ret) { DEBUG(0,("get_key_from_keytab: failed to open keytab: %s\n", error_message(ret))); return ret; } if ( DEBUGLEVEL >= 10 ) { if (smb_krb5_unparse_name(context, server, &name) == 0) { DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n", kvno, enctype, name)); SAFE_FREE(name); } } ret = krb5_kt_get_entry(context, keytab, server, kvno, enctype, &entry); if (ret) { DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret))); goto out; } #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */ ret = krb5_copy_keyblock(context, &entry.keyblock, out_key); #elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */ ret = krb5_copy_keyblock(context, &entry.key, out_key); #else #error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT #endif if (ret) { DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret))); goto out; } smb_krb5_kt_free_entry(context, &entry); out: krb5_kt_close(context, keytab); return ret; }
/* does the ccache have a valid TGT? */ static time_t get_tgt_time(const char *ccname) { krb5_context context; krb5_ccache ccache; krb5_cc_cursor cur; krb5_creds creds; krb5_principal principal; time_t credtime = 0; char *realm = NULL; TALLOC_CTX *mem_ctx; if (krb5_init_context(&context)) { syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); return 0; } if (krb5_cc_resolve(context, ccname, &ccache)) { syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__); goto err_cache; } if (krb5_cc_set_flags(context, ccache, 0)) { syslog(LOG_DEBUG, "%s: unable to set flags", __func__); goto err_cache; } if (krb5_cc_get_principal(context, ccache, &principal)) { syslog(LOG_DEBUG, "%s: unable to get principal", __func__); goto err_princ; } if (krb5_cc_start_seq_get(context, ccache, &cur)) { syslog(LOG_DEBUG, "%s: unable to seq start", __func__); goto err_ccstart; } if ((realm = smb_krb5_principal_get_realm(context, principal)) == NULL) { syslog(LOG_DEBUG, "%s: unable to get realm", __func__); goto err_ccstart; } mem_ctx = talloc_init("cifs.upcall"); while (!credtime && !krb5_cc_next_cred(context, ccache, &cur, &creds)) { char *name; if (smb_krb5_unparse_name(mem_ctx, context, creds.server, &name)) { syslog(LOG_DEBUG, "%s: unable to unparse name", __func__); goto err_endseq; } if (krb5_realm_compare(context, creds.server, principal) && strnequal(name, KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE) && strnequal(name+KRB5_TGS_NAME_SIZE+1, realm, strlen(realm)) && creds.times.endtime > time(NULL)) credtime = creds.times.endtime; krb5_free_cred_contents(context, &creds); TALLOC_FREE(name); } err_endseq: TALLOC_FREE(mem_ctx); krb5_cc_end_seq_get(context, ccache, &cur); err_ccstart: krb5_free_principal(context, principal); err_princ: #if defined(KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); #endif krb5_cc_close(context, ccache); err_cache: krb5_free_context(context); return credtime; }