/* * Decrypt the ticket in req using an entry in keytab matching server (if * given). Set req->ticket->server to the principal of the keytab entry used. * Store the decrypting key in *keyblock_out if it is not NULL. */ static krb5_error_code decrypt_ticket(krb5_context context, const krb5_ap_req *req, krb5_const_principal server, krb5_keytab keytab, krb5_keyblock *keyblock_out) { krb5_error_code ret; krb5_keytab_entry ent; krb5_kt_cursor cursor; #ifdef LEAN_CLIENT return KRB5KRB_AP_WRONG_PRINC; #else /* If we have an explicit server principal, try just that one. */ if (!is_matching(context, server)) return try_one_princ(context, req, server, keytab, keyblock_out); if (keytab->ops->start_seq_get == NULL) { /* We can't iterate over the keytab. Try the principal asserted by the * client if it's allowed by the server parameter. */ if (!krb5_sname_match(context, server, req->ticket->server)) return KRB5KRB_AP_WRONG_PRINC; return try_one_princ(context, req, req->ticket->server, keytab, keyblock_out); } ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) goto cleanup; while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) { if (ent.key.enctype == req->ticket->enc_part.enctype && krb5_sname_match(context, server, ent.principal)) { ret = try_one_entry(context, req, &ent, keyblock_out); if (ret == 0) { TRACE_RD_REQ_DECRYPT_ANY(context, ent.principal, &ent.key); (void)krb5_free_keytab_entry_contents(context, &ent); break; } } (void)krb5_free_keytab_entry_contents(context, &ent); } (void)krb5_kt_end_seq_get(context, keytab, &cursor); cleanup: switch (ret) { case KRB5_KT_KVNONOTFOUND: case KRB5_KT_NOTFOUND: case KRB5_KT_END: case KRB5KRB_AP_ERR_BAD_INTEGRITY: ret = KRB5KRB_AP_WRONG_PRINC; break; default: break; } return ret; #endif /* LEAN_CLIENT */ }
krb5_error_code _adcli_krb5_keytab_clear (krb5_context k5, krb5_keytab keytab, krb5_boolean (* match_func) (krb5_context, krb5_keytab_entry *, void *), void *match_data) { krb5_kt_cursor cursor; krb5_keytab_entry entry; krb5_error_code code; code = krb5_kt_start_seq_get (k5, keytab, &cursor); if (code == KRB5_KT_END || code == ENOENT) return 0; else if (code != 0) return code; for (;;) { code = krb5_kt_next_entry (k5, keytab, &entry, &cursor); if (code != 0) break; /* See if we should remove this entry */ if (!match_func (k5, &entry, match_data)) { krb5_free_keytab_entry_contents (k5, &entry); continue; } /* * Here we close the cursor, remove the entry and then * start all over again from the beginning. Dumb but works. */ code = krb5_kt_end_seq_get (k5, keytab, &cursor); return_val_if_fail (code == 0, code); code = krb5_kt_remove_entry (k5, keytab, &entry); krb5_free_keytab_entry_contents (k5, &entry); if (code != 0) return code; code = krb5_kt_start_seq_get (k5, keytab, &cursor); return_val_if_fail (code == 0, code); } if (code == KRB5_KT_END) code = 0; krb5_kt_end_seq_get (k5, keytab, &cursor); return code; }
krb5_error_code _adcli_krb5_keytab_add_entries (krb5_context k5, krb5_keytab keytab, krb5_principal principal, krb5_kvno kvno, krb5_data *password, krb5_enctype *enctypes, krb5_data *salt) { krb5_keytab_entry entry; krb5_error_code code; int i; for (i = 0; enctypes[i] != 0; i++) { memset (&entry, 0, sizeof(entry)); code = krb5_c_string_to_key (k5, enctypes[i], password, salt, &entry.key); if (code != 0) return code; entry.principal = principal; entry.vno = kvno; code = krb5_kt_add_entry (k5, keytab, &entry); entry.principal = NULL; krb5_free_keytab_entry_contents (k5, &entry); if (code != 0) return code; } return 0; }
bool KRB5Keytab::cursor::next() { krb5_free_keytab_entry_contents(g_context.get(), &m_entry); memset(&m_entry, 0, sizeof(m_entry)); krb5_error_code ret = krb5_kt_next_entry(g_context.get(), m_keytab.m_keytab, &m_entry, &m_cursor); m_princ.reset_no_free(m_entry.principal); return ret == 0; }
krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry) { #if defined(HAVE_KRB5_KT_FREE_ENTRY) return krb5_kt_free_entry(context, kt_entry); #elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS) return krb5_free_keytab_entry_contents(context, kt_entry); #else #error UNKNOWN_KT_FREE_FUNCTION #endif }
KRB5Keytab::cursor::~cursor() { krb5_free_keytab_entry_contents(g_context.get(), &m_entry); memset(&m_entry, 0, sizeof(m_entry)); // Tell m_princ to not free its contents! m_princ.reset_no_free(NULL); krb5_error_code ret = krb5_kt_end_seq_get(g_context.get(), m_keytab.m_keytab, &m_cursor); if (ret) { // FIXME: shouldn't throw from destructor... throw KRB5Exception("krb5_kt_end_seq_get", ret); } }
bool next() { krb5_free_keytab_entry_contents(kt_->getContext(), &ktentry_); memset(&ktentry_, 0, sizeof(ktentry_)); krb5_error_code code = krb5_kt_next_entry(kt_->getContext(), kt_->get(), &ktentry_, &cursor_); if (code == KRB5_KT_END) { return false; } else { raiseIf(kt_->getContext(), code, "reading next credential"); } return true; }
krb5_error_code sss_krb5_kt_have_content(krb5_context context, krb5_keytab keytab) { #ifdef HAVE_KRB5_KT_HAVE_CONTENT return krb5_kt_have_content(context, keytab); #else krb5_keytab_entry entry; krb5_kt_cursor cursor; krb5_error_code kerr; krb5_error_code kerr_end; kerr = krb5_kt_start_seq_get(context, keytab, &cursor); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_start_seq_get failed, assuming no entries.\n"); return KRB5_KT_NOTFOUND; } kerr = krb5_kt_next_entry(context, keytab, &entry, &cursor); kerr_end = krb5_kt_end_seq_get(context, keytab, &cursor); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_next_entry failed, assuming no entries.\n"); return KRB5_KT_NOTFOUND; } kerr = krb5_free_keytab_entry_contents(context, &entry); if (kerr_end != 0) { DEBUG(SSSDBG_TRACE_FUNC, "krb5_kt_end_seq_get failed, ignored.\n"); } if (kerr != 0) { DEBUG(SSSDBG_TRACE_FUNC, "krb5_free_keytab_entry_contents failed, ignored.\n"); } return 0; #endif }
/* Decrypt the ticket in req using a principal looked up from keytab. */ static krb5_error_code try_one_princ(krb5_context context, const krb5_ap_req *req, krb5_const_principal princ, krb5_keytab keytab, krb5_keyblock *keyblock_out) { krb5_error_code ret; krb5_keytab_entry ent; ret = krb5_kt_get_entry(context, keytab, princ, req->ticket->enc_part.kvno, req->ticket->enc_part.enctype, &ent); if (ret) return ret; ret = try_one_entry(context, req, &ent, keyblock_out); if (ret == 0) TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key); (void)krb5_free_keytab_entry_contents(context, &ent); if (ret) return ret; return 0; }
int main(int argc, char **argv) { krb5_context kcontext = NULL; krb5_keytab kt = NULL; krb5_keytab_entry entry; krb5_kt_cursor cursor = NULL; krb5_error_code krb5_err; int matched = 0; char svc_name[] = "host"; int svc_name_len = strlen (svc_name); krb5_err = krb5_init_context(&kcontext); if (krb5_err) { goto Error; } krb5_err = krb5_kt_default(kcontext, &kt); if (krb5_err) { goto Error; } krb5_err = krb5_kt_start_seq_get(kcontext, kt, &cursor); if (krb5_err) { goto Error; } while ((matched == 0) && (krb5_err = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) { krb5_data *nameData = krb5_princ_name (kcontext, entry.principal); if (NULL != nameData->data && svc_name_len == nameData->length && 0 == strncmp (svc_name, nameData->data, nameData->length)) { matched = 1; } krb5_free_keytab_entry_contents(kcontext, &entry); } krb5_err = krb5_kt_end_seq_get(kcontext, kt, &cursor); Error: if (NULL != kt) { krb5_kt_close (kcontext, kt); } if (NULL != kcontext) { krb5_free_context (kcontext); } // Return 0 if we got match or -1 if err or no match return (0 != krb5_err) ? -1 : matched ? 0 : -1; }
/* * Given a keytab, extract the principal name of the (first) entry with * the highest kvno in the keytab. This provides compatibility with the * rxkad KeyFile behavior of always using the highest kvno entry when * printing tickets. We could return the kvno as well, but krb5_kt_get_entry * can find the highest kvno on its own. * * Returns 0 on success, krb5 errors on failure. */ static int pick_principal(krb5_context context, krb5_keytab kt, krb5_principal *service_principal) { krb5_error_code code; krb5_kvno vno = 0; krb5_kt_cursor c; krb5_keytab_entry n_entry; /* Nothing to do */ if (*service_principal != NULL) return 0; memset(&n_entry, 0, sizeof(n_entry)); code = krb5_kt_start_seq_get(context, kt, &c); if (code != 0) goto cleanup; while (code == 0 && krb5_kt_next_entry(context, kt, &n_entry, &c) == 0) { if (n_entry.vno > vno) { vno = n_entry.vno; (void)krb5_free_principal(context, *service_principal); code = krb5_copy_principal(context, n_entry.principal, service_principal); } (void)krb5_free_keytab_entry_contents(context, &n_entry); } if (code != 0) { (void)krb5_kt_end_seq_get(context, kt, &c); goto cleanup; } code = krb5_kt_end_seq_get(context, kt, &c); cleanup: return code; }
/* Decrypt the ticket in req using a principal looked up from keytab. * explicit_server should be true if this is the only usable principal. */ static krb5_error_code try_one_princ(krb5_context context, const krb5_ap_req *req, krb5_const_principal princ, krb5_keytab keytab, krb5_boolean explicit_server, krb5_keyblock *keyblock_out) { krb5_error_code ret; krb5_keytab_entry ent; krb5_kvno tkt_kvno = req->ticket->enc_part.kvno; krb5_enctype tkt_etype = req->ticket->enc_part.enctype; krb5_principal tkt_server = req->ticket->server; ret = krb5_kt_get_entry(context, keytab, princ, tkt_kvno, tkt_etype, &ent); if (ret) { return keytab_fetch_error(context, ret, princ, tkt_server, tkt_kvno, explicit_server); } ret = try_one_entry(context, req, &ent, keyblock_out); if (ret == 0) TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key); (void)krb5_free_keytab_entry_contents(context, &ent); if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) return integrity_error(context, princ, req->ticket->server); return ret; }
static int gss_create_principal(AFPObj *obj) { int rv = -1; #ifdef HAVE_KERBEROS krb5_context context; krb5_error_code ret; const char *error_msg; krb5_keytab keytab; krb5_keytab_entry entry; krb5_principal service_principal; char *principal; krb5_kt_cursor cursor; if (krb5_init_context(&context)) { LOG(log_error, logtype_afpd, "gss_create_principal: failed to intialize a krb5_context"); goto exit; } if ((ret = krb5_kt_default(context, &keytab))) goto krb5_error; if (obj->options.k5service && obj->options.fqdn && obj->options.k5realm) { LOG(log_debug, logtype_afpd, "gss_create_principal: using service principal specified in options"); if ((ret = krb5_build_principal(context, &service_principal, strlen(obj->options.k5realm), obj->options.k5realm, obj->options.k5service, obj->options.fqdn, NULL))) goto krb5_error; if ((ret = krb5_kt_get_entry(context, keytab, service_principal, 0, // kvno - wildcard 0, // enctype - wildcard &entry)) == KRB5_KT_NOTFOUND) { krb5_unparse_name(context, service_principal, &principal); LOG(log_error, logtype_afpd, "gss_create_principal: specified service principal '%s' not found in keytab", principal); #ifdef HAVE_KRB5_FREE_UNPARSED_NAME krb5_free_unparsed_name(context, principal); #else krb5_xfree(principal); #endif goto krb5_cleanup; } krb5_free_principal(context, service_principal); if (ret) goto krb5_error; } else { LOG(log_debug, logtype_afpd, "gss_create_principal: using first entry from keytab as service principal"); if ((ret = krb5_kt_start_seq_get(context, keytab, &cursor))) goto krb5_error; ret = krb5_kt_next_entry(context, keytab, &entry, &cursor); krb5_kt_end_seq_get(context, keytab, &cursor); if (ret) goto krb5_error; } krb5_unparse_name(context, entry.principal, &principal); #ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS krb5_free_keytab_entry_contents(context, &entry); #elif defined(HAVE_KRB5_KT_FREE_ENTRY) krb5_kt_free_entry(context, &entry); #endif set_principal(obj, principal); free(principal); rv = 0; goto krb5_cleanup; krb5_error: if (ret) { error_msg = krb5_get_error_message(context, ret); LOG(log_note, logtype_afpd, "Can't get principal from default keytab: %s", (char *)error_msg); #ifdef HAVE_KRB5_FREE_ERROR_MESSAGE krb5_free_error_message(context, error_msg); #else krb5_xfree(error_msg); #endif } krb5_cleanup: krb5_kt_close(context, keytab); krb5_free_context(context); #else /* ! HAVE_KERBEROS */ if (!obj->options.k5service || !obj->options.fqdn || !obj->options.k5realm) goto exit; char principal[255]; size_t len = snprintf(principal, sizeof(principal), "%s/%s@%s", obj->options.k5service, obj->options.fqdn, obj->options.k5realm); (void)set_principal(obj, principal); rv = 0; #endif /* HAVE_KERBEROS */ exit: return rv; }
/* * Decrypt the ticket in req using an entry in keytab matching server (if * given). Set req->ticket->server to the principal of the keytab entry used. * Store the decrypting key in *keyblock_out if it is not NULL. */ static krb5_error_code decrypt_ticket(krb5_context context, const krb5_ap_req *req, krb5_const_principal server, krb5_keytab keytab, krb5_keyblock *keyblock_out) { krb5_error_code ret; krb5_keytab_entry ent; krb5_kt_cursor cursor; krb5_principal tkt_server = req->ticket->server; krb5_kvno tkt_kvno = req->ticket->enc_part.kvno; krb5_enctype tkt_etype = req->ticket->enc_part.enctype; krb5_boolean similar_enctype; krb5_boolean tkt_server_mismatch = FALSE, found_server_match = FALSE; krb5_boolean found_tkt_server = FALSE, found_enctype = FALSE; krb5_boolean found_kvno = FALSE, found_higher_kvno = FALSE; #ifdef LEAN_CLIENT return KRB5KRB_AP_WRONG_PRINC; #else /* If we have an explicit server principal, try just that one. */ if (!is_matching(context, server)) { return try_one_princ(context, req, server, keytab, TRUE, keyblock_out); } if (keytab->ops->start_seq_get == NULL) { /* We can't iterate over the keytab. Try the principal asserted by the * client if it's allowed by the server parameter. */ if (!krb5_sname_match(context, server, tkt_server)) return nomatch_error(context, server, tkt_server); return try_one_princ(context, req, tkt_server, keytab, FALSE, keyblock_out); } /* Scan all keys in the keytab, in case the ticket server is an alias for * one of the principals in the keytab. */ ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { k5_change_error_message_code(context, ret, KRB5KRB_AP_ERR_NOKEY); return KRB5KRB_AP_ERR_NOKEY; } while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) { /* Only try keys which match the server principal. */ if (!krb5_sname_match(context, server, ent.principal)) { if (krb5_principal_compare(context, ent.principal, tkt_server)) tkt_server_mismatch = TRUE; continue; } found_server_match = TRUE; if (krb5_c_enctype_compare(context, ent.key.enctype, tkt_etype, &similar_enctype) != 0) similar_enctype = FALSE; if (krb5_principal_compare(context, ent.principal, tkt_server)) { found_tkt_server = TRUE; if (ent.vno == tkt_kvno) { found_kvno = TRUE; if (similar_enctype) found_enctype = TRUE; } else if (ent.vno > tkt_kvno) { found_higher_kvno = TRUE; } } /* Only try keys with similar enctypes to the ticket enctype. */ if (similar_enctype) { /* Coerce inexact matches to the request enctype. */ ent.key.enctype = tkt_etype; if (try_one_entry(context, req, &ent, keyblock_out) == 0) { TRACE_RD_REQ_DECRYPT_ANY(context, ent.principal, &ent.key); (void)krb5_free_keytab_entry_contents(context, &ent); break; } } (void)krb5_free_keytab_entry_contents(context, &ent); } (void)krb5_kt_end_seq_get(context, keytab, &cursor); if (ret != KRB5_KT_END) return ret; return iteration_error(context, server, tkt_server, tkt_kvno, tkt_etype, tkt_server_mismatch, found_server_match, found_tkt_server, found_kvno, found_higher_kvno, found_enctype); #endif /* LEAN_CLIENT */ }
/* * create Kerberos memory cache */ int krb5_create_cache(struct main_args *margs,char *domain) { krb5_keytab keytab = 0; krb5_keytab_entry entry; krb5_kt_cursor cursor; krb5_creds *creds=NULL; krb5_creds *tgt_creds=NULL; krb5_principal *principal_list = NULL; krb5_principal principal = NULL; char *service; char *keytab_name=NULL,*principal_name=NULL,*mem_cache=NULL; char buf[KT_PATH_MAX], *p; int nprinc=0; int i; int retval=0; int found=0; krb5_error_code code = 0; kparam.context=NULL; if (!domain || !strcmp(domain,"")) return(1); /* * Initialise Kerberos */ code = krb5_init_context(&kparam.context); if (code) { fprintf(stderr, "%s| %s: Error while initialising Kerberos library : %s\n",LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } /* * getting default keytab name */ if (margs->debug) fprintf(stderr, "%s| %s: Get default keytab file name\n",LogTime(), PROGRAM); krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX); p = strchr(buf, ':'); /* Find the end if "FILE:" */ if (p) p++; /* step past : */ keytab_name = strdup(p ? p : buf); if (margs->debug) fprintf(stderr, "%s| %s: Got default keytab file name %s\n",LogTime(), PROGRAM, keytab_name); code = krb5_kt_resolve(kparam.context, keytab_name, &keytab); if (code) { fprintf(stderr, "%s| %s: Error while resolving keytab %s : %s\n", LogTime(), PROGRAM, keytab_name,error_message(code)); retval=1; goto cleanup; } code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor); if (code) { fprintf(stderr, "%s| %s: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } if (margs->debug) fprintf(stderr, "%s| %s: Get principal name from keytab %s\n",LogTime(), PROGRAM, keytab_name); nprinc=0; while ((code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) { principal_list=realloc(principal_list,sizeof(krb5_principal)*(nprinc+1)); krb5_copy_principal(kparam.context,entry.principal,&principal_list[nprinc++]); if (margs->debug) #ifdef HAVE_HEIMDAL_KERBEROS fprintf(stderr, "%s| %s: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm); #else fprintf(stderr, "%s| %s: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data); #endif #ifdef HAVE_HEIMDAL_KERBEROS if (!strcasecmp(domain, entry.principal->realm)) #else if (!strcasecmp(domain,krb5_princ_realm(kparam.context, entry.principal)->data)) #endif { code = krb5_unparse_name(kparam.context, entry.principal, &principal_name); if (code) { fprintf(stderr, "%s| %s: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code)); } else { if (margs->debug) fprintf(stderr, "%s| %s: Found principal name: %s\n", LogTime(), PROGRAM, principal_name); found=1; } } #if defined(HAVE_HEIMDAL_KERBEROS) || ( defined(HAVE_KRB5_KT_FREE_ENTRY) && HAVE_DECL_KRB5_KT_FREE_ENTRY==1) code = krb5_kt_free_entry(kparam.context,&entry); #else code = krb5_free_keytab_entry_contents(kparam.context,&entry); #endif if (code) { fprintf(stderr, "%s| %s: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM, error_message(code)); retval=1; break; } if (found) break; } if (code && code != KRB5_KT_END) { fprintf(stderr, "%s| %s: Error while scanning keytab : %s\n", LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor); if (code) { fprintf(stderr, "%s| %s: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } /* * prepare memory credential cache */ #ifndef HAVE_KRB5_MEMORY_CACHE mem_cache=malloc(strlen("FILE:/tmp/squid_ldap_")+16); snprintf(mem_cache,strlen("FILE:/tmp/squid_ldap_")+16,"FILE:/tmp/squid_ldap_%d",(int)getpid()); #else mem_cache=malloc(strlen("MEMORY:squid_ldap_")+16); snprintf(mem_cache,strlen("MEMORY:squid_ldap_")+16,"MEMORY:squid_ldap_%d",(int)getpid()); #endif setenv("KRB5CCNAME",mem_cache,1); if (margs->debug) fprintf(stderr, "%s| %s: Set credential cache to %s\n",LogTime(), PROGRAM,mem_cache); code = krb5_cc_resolve(kparam.context, mem_cache , &kparam.cc); if (code) { fprintf(stderr, "%s| %s: Error while resolving memory ccache : %s\n",LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } /* * if no principal name found in keytab for domain use the prinipal name which can get a TGT */ if (!principal_name) { if (margs->debug) { fprintf(stderr, "%s| %s: Did not find a principal in keytab for domain %s.\n",LogTime(), PROGRAM,domain); fprintf(stderr, "%s| %s: Try to get principal of trusted domain.\n",LogTime(), PROGRAM); } creds = malloc(sizeof(*creds)); memset(creds, 0, sizeof(*creds)); for (i=0;i<nprinc;i++) { /* * get credentials */ code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name); if (code) { if (margs->debug) fprintf(stderr, "%s| %s: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code)); goto loop_end; } if (margs->debug) fprintf(stderr, "%s| %s: Keytab entry has principal: %s\n", LogTime(), PROGRAM, principal_name); #if HAVE_GET_INIT_CREDS_KEYTAB code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0, NULL, NULL); #else service=malloc(strlen("krbtgt")+2*strlen(domain)+3); snprintf(service,strlen("krbtgt")+2*strlen(domain)+3,"krbtgt/%s@%s",domain,domain); creds->client=principal_list[i]; code = krb5_parse_name(kparam.context,service,&creds->server); if (service) free(service); code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0); #endif if (code) { if (margs->debug) fprintf(stderr, "%s| %s: Error while initialising credentials from keytab : %s\n",LogTime(), PROGRAM, error_message(code)); goto loop_end; } code = krb5_cc_initialize(kparam.context, kparam.cc, principal_list[i]); if (code) { fprintf(stderr, "%s| %s: Error while initializing memory caches : %s\n",LogTime(), PROGRAM, error_message(code)); goto loop_end; } code = krb5_cc_store_cred(kparam.context, kparam.cc, creds); if (code) { if (margs->debug) fprintf(stderr, "%s| %s: Error while storing credentials : %s\n",LogTime(), PROGRAM, error_message(code)); goto loop_end; } if (creds->server) krb5_free_principal(kparam.context,creds->server); #ifdef HAVE_HEIMDAL_KERBEROS service=malloc(strlen("krbtgt")+strlen(domain)+strlen(principal_list[i]->realm)+3); snprintf(service,strlen("krbtgt")+strlen(domain)+strlen(principal_list[i]->realm)+3,"krbtgt/%s@%s",domain,principal_list[i]->realm); #else service=malloc(strlen("krbtgt")+strlen(domain)+strlen(krb5_princ_realm(kparam.context, principal_list[i])->data)+3); snprintf(service,strlen("krbtgt")+strlen(domain)+strlen(krb5_princ_realm(kparam.context, principal_list[i])->data)+3,"krbtgt/%s@%s",domain,krb5_princ_realm(kparam.context, principal_list[i])->data); #endif code = krb5_parse_name(kparam.context,service,&creds->server); if (service) free(service); if (code) { fprintf(stderr, "%s| %s: Error while initialising TGT credentials : %s\n",LogTime(), PROGRAM, error_message(code)); goto loop_end; } code = krb5_get_credentials(kparam.context, 0, kparam.cc, creds, &tgt_creds); if (code) { if (margs->debug) fprintf(stderr, "%s| %s: Error while getting tgt : %s\n",LogTime(), PROGRAM, error_message(code)); goto loop_end; } else { if (margs->debug) fprintf(stderr, "%s| %s: Found trusted principal name: %s\n", LogTime(), PROGRAM, principal_name); break; } loop_end: if (principal_name) free(principal_name); principal_name=NULL; } if (tgt_creds) krb5_free_creds(kparam.context,tgt_creds); tgt_creds=NULL; if (creds) krb5_free_creds(kparam.context,creds); creds=NULL; } if (principal_name) { if (margs->debug) fprintf(stderr, "%s| %s: Got principal name %s\n",LogTime(), PROGRAM, principal_name); /* * build principal */ code = krb5_parse_name(kparam.context, principal_name, &principal); if (code) { fprintf(stderr, "%s| %s: Error while parsing name %s : %s\n", LogTime(), PROGRAM, principal_name,error_message(code)); retval=1; goto cleanup; } creds = malloc(sizeof(*creds)); memset(creds, 0, sizeof(*creds)); /* * get credentials */ #if HAVE_GET_INIT_CREDS_KEYTAB code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, NULL); #else service=malloc(strlen("krbtgt")+2*strlen(domain)+3); snprintf(service,strlen("krbtgt")+2*strlen(domain)+3,"krbtgt/%s@%s",domain,domain); creds->client=principal; code = krb5_parse_name(kparam.context,service,&creds->server); if (service) free(service); code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0); #endif if (code) { fprintf(stderr, "%s| %s: Error while initialising credentials from keytab : %s\n",LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } code = krb5_cc_initialize(kparam.context, kparam.cc, principal); if (code) { fprintf(stderr, "%s| %s: Error while initializing memory caches : %s\n",LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } code = krb5_cc_store_cred(kparam.context, kparam.cc, creds); if (code) { fprintf(stderr, "%s| %s: Error while storing credentials : %s\n",LogTime(), PROGRAM, error_message(code)); retval=1; goto cleanup; } if (margs->debug) fprintf(stderr, "%s| %s: Stored credentials\n",LogTime(), PROGRAM); } else { if (margs->debug) fprintf(stderr, "%s| %s: Got no principal name\n",LogTime(), PROGRAM); retval=1; } cleanup: if (keytab) krb5_kt_close(kparam.context, keytab); if (keytab_name) free(keytab_name); if (principal_name) free(principal_name); if (mem_cache) free(mem_cache); if (principal) krb5_free_principal(kparam.context,principal); for (i=0;i<nprinc;i++) { if (principal_list[i]) krb5_free_principal(kparam.context,principal_list[i]); } if (principal_list) free(principal_list); if (creds) krb5_free_creds(kparam.context,creds); return(retval); }
~State() { krb5_free_keytab_entry_contents(kt_->getContext(), &ktentry_); krb5_error_code code = krb5_kt_end_seq_get(kt_->getContext(), kt_->get(), &cursor_); raiseIf(kt_->getContext(), code, "ending read of keytab " + kt_->getName()); }
krb5_error_code sss_extract_pac(krb5_context ctx, krb5_ccache ccache, krb5_principal server_principal, krb5_principal client_principal, krb5_keytab keytab, krb5_authdata ***_pac_authdata) { #ifdef HAVE_PAC_RESPONDER krb5_error_code kerr; krb5_creds mcred; krb5_creds cred; krb5_authdata **pac_authdata = NULL; krb5_pac pac = NULL; int ret; krb5_ticket *ticket = NULL; krb5_keytab_entry entry; memset(&entry, 0, sizeof(entry)); memset(&mcred, 0, sizeof(mcred)); memset(&cred, 0, sizeof(mcred)); mcred.server = server_principal; mcred.client = client_principal; kerr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_retrieve_cred failed.\n"); goto done; } kerr = krb5_decode_ticket(&cred.ticket, &ticket); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_decode_ticket failed.\n"); goto done; } kerr = krb5_server_decrypt_ticket_keytab(ctx, keytab, ticket); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_server_decrypt_ticket_keytab failed.\n"); goto done; } kerr = sss_krb5_find_authdata(ctx, ticket->enc_part2->authorization_data, NULL, KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_find_authdata failed.\n"); goto done; } if (pac_authdata == NULL || pac_authdata[0] == NULL) { DEBUG(SSSDBG_OP_FAILURE, "No PAC authdata available.\n"); kerr = ENOENT; goto done; } if (pac_authdata[1] != NULL) { DEBUG(SSSDBG_OP_FAILURE, "More than one PAC autdata found.\n"); kerr = EINVAL; goto done; } kerr = krb5_pac_parse(ctx, pac_authdata[0]->contents, pac_authdata[0]->length, &pac); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_parse failed.\n"); goto done; } kerr = krb5_kt_get_entry(ctx, keytab, ticket->server, ticket->enc_part.kvno, ticket->enc_part.enctype, &entry); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_get_entry failed.\n"); goto done; } kerr = krb5_pac_verify(ctx, pac, 0, NULL, &entry.key, NULL); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_verify failed.\n"); goto done; } ret = unsetenv("_SSS_LOOPS"); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to unset _SSS_LOOPS, " "sss_pac_make_request will most certainly fail.\n"); } *_pac_authdata = pac_authdata; kerr = 0; done: if (kerr != 0) { krb5_free_authdata(ctx, pac_authdata); } if (entry.magic != 0) { krb5_free_keytab_entry_contents(ctx, &entry); } krb5_pac_free(ctx, pac); if (ticket != NULL) { krb5_free_ticket(ctx, ticket); } krb5_free_cred_contents(ctx, &cred); return kerr; #else return ENOTSUP; #endif }
krb5_error_code sss_krb5_free_keytab_entry_contents(krb5_context context, krb5_keytab_entry *entry) { return krb5_free_keytab_entry_contents(context, entry); }
static void do_keytab(const char *name) { krb5_error_code ret; krb5_keytab kt; krb5_keytab_entry entry; krb5_kt_cursor cursor; unsigned int i; char buf[BUFSIZ]; /* Hopefully large enough for any type */ char *pname; if (name == NULL && use_client_keytab) { ret = krb5_kt_client_default(context, &kt); if (ret) { com_err(progname, ret, _("while getting default client keytab")); exit(1); } } else if (name == NULL) { ret = krb5_kt_default(context, &kt); if (ret) { com_err(progname, ret, _("while getting default keytab")); exit(1); } } else { ret = krb5_kt_resolve(context, name, &kt); if (ret) { com_err(progname, ret, _("while resolving keytab %s"), name); exit(1); } } ret = krb5_kt_get_name(context, kt, buf, BUFSIZ); if (ret) { com_err(progname, ret, _("while getting keytab name")); exit(1); } printf("Keytab name: %s\n", buf); ret = krb5_kt_start_seq_get(context, kt, &cursor); if (ret) { com_err(progname, ret, _("while starting keytab scan")); exit(1); } /* XXX Translating would disturb table alignment; skip for now. */ if (show_time) { printf("KVNO Timestamp"); fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' '); printf("Principal\n"); printf("---- "); fillit(stdout, timestamp_width, (int) '-'); printf(" "); fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-'); printf("\n"); } else { printf("KVNO Principal\n"); printf("---- ------------------------------------------------" "--------------------------\n"); } while ((ret = krb5_kt_next_entry(context, kt, &entry, &cursor)) == 0) { ret = krb5_unparse_name(context, entry.principal, &pname); if (ret) { com_err(progname, ret, _("while unparsing principal name")); exit(1); } printf("%4d ", entry.vno); if (show_time) { printtime(entry.timestamp); printf(" "); } printf("%s", pname); if (show_etype) printf(" (%s) " , etype_string(entry.key.enctype)); if (show_keys) { printf(" (0x"); for (i = 0; i < entry.key.length; i++) printf("%02x", entry.key.contents[i]); printf(")"); } printf("\n"); krb5_free_unparsed_name(context, pname); krb5_free_keytab_entry_contents(context, &entry); } if (ret && ret != KRB5_KT_END) { com_err(progname, ret, _("while scanning keytab")); exit(1); } ret = krb5_kt_end_seq_get(context, kt, &cursor); if (ret) { com_err(progname, ret, _("while ending keytab scan")); exit(1); } exit(0); }
char* server_principal_details(const char* service, const char* hostname) { char match[1024]; size_t match_len = 0; char* result = NULL; int code; krb5_context kcontext; krb5_keytab kt = NULL; krb5_kt_cursor cursor = NULL; krb5_keytab_entry entry; char* pname = NULL; // Generate the principal prefix we want to match snprintf(match, 1024, "%s/%s@", service, hostname); match_len = strlen(match); code = krb5_init_context(&kcontext); if (code) { PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", "Cannot initialize Kerberos5 context", code)); return NULL; } if ((code = krb5_kt_default(kcontext, &kt))) { PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", "Cannot get default keytab", code)); goto end; } if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) { PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", "Cannot get sequence cursor from keytab", code)); goto end; } while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) { if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) { PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", "Cannot parse principal name from keytab", code)); goto end; } if (strncmp(pname, match, match_len) == 0) { result = malloc(strlen(pname) + 1); strcpy(result, pname); krb5_free_unparsed_name(kcontext, pname); krb5_free_keytab_entry_contents(kcontext, &entry); break; } krb5_free_unparsed_name(kcontext, pname); krb5_free_keytab_entry_contents(kcontext, &entry); } if (result == NULL) { PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", "Principal not found in keytab", -1)); } end: if (cursor) krb5_kt_end_seq_get(kcontext, kt, &cursor); if (kt) krb5_kt_close(kcontext, kt); krb5_free_context(kcontext); return result; }
/* * Print a krb5 ticket in our service key, for the supplied client principal. * The path to a keytab is mandatory, but the service principal may be * guessed from the keytab contents if desired. The keytab entry must be * one of the allowed_enctypes (a zero-terminated list) if a non-NULL * parameter is passed. */ krb5_error_code get_credv5_akimpersonate(krb5_context context, char* keytab, krb5_principal service_principal, krb5_principal client_principal, time_t starttime, time_t endtime, const int *allowed_enctypes, krb5_creds** out_creds /* out */ ) { krb5_error_code code; krb5_keytab kt = 0; krb5_keytab_entry entry[1]; krb5_creds *creds = 0; krb5_enctype enctype; krb5_keyblock session_key[1]; #if USING_HEIMDAL Ticket *ticket_reply; EncTicketPart *enc_tkt_reply; #else krb5_ticket *ticket_reply; krb5_enc_tkt_part *enc_tkt_reply; #endif *out_creds = NULL; enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */ memset(entry, 0, sizeof *entry); memset(session_key, 0, sizeof *session_key); ticket_reply = NULL; enc_tkt_reply = NULL; creds = calloc(1, sizeof(*creds)); if (creds == NULL) { code = ENOMEM; goto cleanup; } code = alloc_ticket(&ticket_reply); if (code != 0) goto cleanup; code = alloc_enc_tkt_part(&enc_tkt_reply); if (code != 0) goto cleanup; /* Empty list of allowed etypes must fail. Do it here to avoid issues. */ if (allowed_enctypes != NULL && *allowed_enctypes == 0) { code = KRB5_BAD_ENCTYPE; goto cleanup; } if (allowed_enctypes == NULL) allowed_enctypes = any_enctype; if (keytab != NULL) code = krb5_kt_resolve(context, keytab, &kt); else code = krb5_kt_default(context, &kt); if (code != 0) goto cleanup; code = pick_enctype_and_principal(context, kt, allowed_enctypes, &enctype, &service_principal, entry); if (code != 0) goto cleanup; /* Conjure up a random session key */ deref_keyblock_enctype(session_key) = enctype; #if USING_HEIMDAL code = krb5_generate_random_keyblock(context, enctype, session_key); #else code = krb5_c_make_random_key(context, enctype, session_key); #endif if (code != 0) goto cleanup; populate_enc_tkt(session_key, client_principal, starttime, endtime, enc_tkt_reply); code = encrypt_enc_tkt(context, service_principal, entry, ticket_reply, enc_tkt_reply); if (code != 0) goto cleanup; code = populate_creds(context, service_principal, client_principal, session_key, ticket_reply, enc_tkt_reply, creds); if (code != 0) goto cleanup; /* return creds */ *out_creds = creds; creds = NULL; cleanup: if (deref_enc_data(&ticket_reply->enc_part) != NULL) free(deref_enc_data(&ticket_reply->enc_part)); krb5_free_keytab_entry_contents(context, entry); if (client_principal != NULL) krb5_free_principal(context, client_principal); if (service_principal != NULL) krb5_free_principal(context, service_principal); if (kt != NULL) krb5_kt_close(context, kt); if (creds != NULL) krb5_free_creds(context, creds); krb5_free_keyblock_contents(context, session_key); free_ticket(ticket_reply); free_enc_tkt_part(enc_tkt_reply); return code; }
krb5_error_code KRB5_CALLCONV krb5_kt_free_entry (krb5_context context, krb5_keytab_entry *entry) { return krb5_free_keytab_entry_contents (context, entry); }
krb5_error_code KRB5_CALLCONV krb5_server_decrypt_ticket_keytab(krb5_context context, const krb5_keytab keytab, krb5_ticket *ticket) { krb5_error_code retval; krb5_keytab_entry ktent; retval = KRB5_KT_NOTFOUND; if (keytab->ops->start_seq_get == NULL) { retval = krb5_kt_get_entry(context, keytab, ticket->server, ticket->enc_part.kvno, ticket->enc_part.enctype, &ktent); if (retval == 0) { retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket); (void) krb5_free_keytab_entry_contents(context, &ktent); } } else { krb5_error_code code; krb5_kt_cursor cursor; retval = krb5_kt_start_seq_get(context, keytab, &cursor); if (retval != 0) goto map_error; while ((code = krb5_kt_next_entry(context, keytab, &ktent, &cursor)) == 0) { if (ktent.key.enctype != ticket->enc_part.enctype) continue; retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket); if (retval == 0) { krb5_principal tmp; retval = krb5_copy_principal(context, ktent.principal, &tmp); if (retval == 0) { krb5_free_principal(context, ticket->server); ticket->server = tmp; } (void) krb5_free_keytab_entry_contents(context, &ktent); break; } (void) krb5_free_keytab_entry_contents(context, &ktent); } code = krb5_kt_end_seq_get(context, keytab, &cursor); if (code != 0) retval = code; } map_error: switch (retval) { case KRB5_KT_KVNONOTFOUND: case KRB5_KT_NOTFOUND: case KRB5KRB_AP_ERR_BAD_INTEGRITY: retval = KRB5KRB_AP_WRONG_PRINC; break; default: break; } return retval; }
static void kt_test(krb5_context context, const char *name) { krb5_error_code kret; krb5_keytab kt; const char *type; char buf[BUFSIZ]; char *p; krb5_keytab_entry kent, kent2; krb5_principal princ; krb5_kt_cursor cursor, cursor2; int cnt; kret = krb5_kt_resolve(context, name, &kt); CHECK(kret, "resolve"); type = krb5_kt_get_type(context, kt); CHECK_STR(type, "getting kt type"); printf(" Type is: %s\n", type); kret = krb5_kt_get_name(context, kt, buf, sizeof(buf)); CHECK(kret, "get_name"); printf(" Name is: %s\n", buf); /* Check that length checks fail */ /* The buffer is allocated too small - to allow for valgrind test of overflows */ p = malloc(strlen(buf)); kret = krb5_kt_get_name(context, kt, p, 1); if(kret != KRB5_KT_NAME_TOOLONG) { CHECK(kret, "get_name - size 1"); } kret = krb5_kt_get_name(context, kt, p, strlen(buf)); if(kret != KRB5_KT_NAME_TOOLONG) { CHECK(kret, "get_name"); } free(p); /* Try to lookup unknown principal - when keytab does not exist*/ kret = krb5_parse_name(context, "test/[email protected]", &princ); CHECK(kret, "parsing principal"); kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent); if((kret != KRB5_KT_NOTFOUND) && (kret != ENOENT)) { CHECK(kret, "Getting non-existant entry"); } /* =================== Add entries to keytab ================= */ /* * Add the following for this principal * enctype 1, kvno 1, key = "1" * enctype 2, kvno 1, key = "1" * enctype 1, kvno 2, key = "2" */ memset(&kent, 0, sizeof(kent)); kent.magic = KV5M_KEYTAB_ENTRY; kent.principal = princ; kent.timestamp = 327689; kent.vno = 1; kent.key.magic = KV5M_KEYBLOCK; kent.key.enctype = 1; kent.key.length = 1; kent.key.contents = (krb5_octet *) "1"; kret = krb5_kt_add_entry(context, kt, &kent); CHECK(kret, "Adding initial entry"); kent.key.enctype = 2; kret = krb5_kt_add_entry(context, kt, &kent); CHECK(kret, "Adding second entry"); kent.key.enctype = 1; kent.vno = 2; kent.key.contents = (krb5_octet *) "2"; kret = krb5_kt_add_entry(context, kt, &kent); CHECK(kret, "Adding third entry"); /* Free memory */ krb5_free_principal(context, princ); /* ============== Test iterating over contents of keytab ========= */ kret = krb5_kt_start_seq_get(context, kt, &cursor); CHECK(kret, "Start sequence get"); memset(&kent, 0, sizeof(kent)); cnt = 0; while((kret = krb5_kt_next_entry(context, kt, &kent, &cursor)) == 0) { if(((kent.vno != 1) && (kent.vno != 2)) || ((kent.key.enctype != 1) && (kent.key.enctype != 2)) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Error in read contents\n"); exit(1); } if((kent.magic != KV5M_KEYTAB_ENTRY) || (kent.key.magic != KV5M_KEYBLOCK)) { fprintf(stderr, "Magic number in sequence not proper\n"); exit(1); } cnt++; krb5_free_keytab_entry_contents(context, &kent); } if (kret != KRB5_KT_END) { CHECK(kret, "getting next entry"); } if(cnt != 3) { fprintf(stderr, "Mismatch in number of entries in keytab"); } kret = krb5_kt_end_seq_get(context, kt, &cursor); CHECK(kret, "End sequence get"); /* ========================== get_entry tests ============== */ /* Try to lookup unknown principal - now that keytab exists*/ kret = krb5_parse_name(context, "test3/[email protected]", &princ); CHECK(kret, "parsing principal"); kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent); if((kret != KRB5_KT_NOTFOUND)) { CHECK(kret, "Getting non-existant entry"); } krb5_free_principal(context, princ); /* Try to lookup known principal */ kret = krb5_parse_name(context, "test/[email protected]", &princ); CHECK(kret, "parsing principal"); kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent); CHECK(kret, "looking up principal"); /* Ensure a valid answer - we did not specify an enctype or kvno */ if (!krb5_principal_compare(context, princ, kent.principal) || ((kent.vno != 1) && (kent.vno != 2)) || ((kent.key.enctype != 1) && (kent.key.enctype != 2)) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Retrieved principal does not check\n"); exit(1); } krb5_free_keytab_entry_contents(context, &kent); /* Try to lookup a specific enctype - but unspecified kvno - should give * max kvno */ kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent); CHECK(kret, "looking up principal"); /* Ensure a valid answer - we did specified an enctype */ if (!krb5_principal_compare(context, princ, kent.principal) || (kent.vno != 2) || (kent.key.enctype != 1) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Retrieved principal does not check\n"); exit(1); } krb5_free_keytab_entry_contents(context, &kent); /* Try to lookup unspecified enctype, but a specified kvno */ kret = krb5_kt_get_entry(context, kt, princ, 2, 0, &kent); CHECK(kret, "looking up principal"); /* Ensure a valid answer - we did not specify a kvno */ if (!krb5_principal_compare(context, princ, kent.principal) || (kent.vno != 2) || (kent.key.enctype != 1) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Retrieved principal does not check\n"); exit(1); } krb5_free_keytab_entry_contents(context, &kent); /* Try to lookup specified enctype and kvno */ kret = krb5_kt_get_entry(context, kt, princ, 1, 1, &kent); CHECK(kret, "looking up principal"); if (!krb5_principal_compare(context, princ, kent.principal) || (kent.vno != 1) || (kent.key.enctype != 1) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Retrieved principal does not check\n"); exit(1); } krb5_free_keytab_entry_contents(context, &kent); /* Try lookup with active iterators. */ kret = krb5_kt_start_seq_get(context, kt, &cursor); CHECK(kret, "Start sequence get(2)"); kret = krb5_kt_start_seq_get(context, kt, &cursor2); CHECK(kret, "Start sequence get(3)"); kret = krb5_kt_next_entry(context, kt, &kent, &cursor); CHECK(kret, "getting next entry(2)"); krb5_free_keytab_entry_contents(context, &kent); kret = krb5_kt_next_entry(context, kt, &kent, &cursor); CHECK(kret, "getting next entry(3)"); kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2); CHECK(kret, "getting next entry(4)"); krb5_free_keytab_entry_contents(context, &kent2); kret = krb5_kt_get_entry(context, kt, kent.principal, 0, 0, &kent2); CHECK(kret, "looking up principal(2)"); krb5_free_keytab_entry_contents(context, &kent2); kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2); CHECK(kret, "getting next entry(5)"); if (!krb5_principal_compare(context, kent.principal, kent2.principal)) { fprintf(stderr, "iterators not in sync\n"); exit(1); } krb5_free_keytab_entry_contents(context, &kent); krb5_free_keytab_entry_contents(context, &kent2); kret = krb5_kt_next_entry(context, kt, &kent, &cursor); CHECK(kret, "getting next entry(6)"); kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2); CHECK(kret, "getting next entry(7)"); krb5_free_keytab_entry_contents(context, &kent); krb5_free_keytab_entry_contents(context, &kent2); kret = krb5_kt_end_seq_get(context, kt, &cursor); CHECK(kret, "ending sequence get(1)"); kret = krb5_kt_end_seq_get(context, kt, &cursor2); CHECK(kret, "ending sequence get(2)"); /* Try to lookup specified enctype and kvno - that does not exist*/ kret = krb5_kt_get_entry(context, kt, princ, 3, 1, &kent); if(kret != KRB5_KT_KVNONOTFOUND) { CHECK(kret, "looking up specific principal, kvno, enctype"); } krb5_free_principal(context, princ); /* ========================= krb5_kt_remove_entry =========== */ /* Lookup the keytab entry w/ 2 kvno - and delete version 2 - ensure gone */ kret = krb5_parse_name(context, "test/[email protected]", &princ); CHECK(kret, "parsing principal"); kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent); CHECK(kret, "looking up principal"); /* Ensure a valid answer - we are looking for max(kvno) and enc=1 */ if (!krb5_principal_compare(context, princ, kent.principal) || (kent.vno != 2) || (kent.key.enctype != 1) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Retrieved principal does not check\n"); exit(1); } /* Delete it */ kret = krb5_kt_remove_entry(context, kt, &kent); CHECK(kret, "Removing entry"); krb5_free_keytab_entry_contents(context, &kent); /* And ensure gone */ kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent); CHECK(kret, "looking up principal"); /* Ensure a valid answer - kvno should now be 1 - we deleted 2 */ if (!krb5_principal_compare(context, princ, kent.principal) || (kent.vno != 1) || (kent.key.enctype != 1) || (kent.key.length != 1) || (kent.key.contents[0] != kent.vno +'0')) { fprintf(stderr, "Delete principal check failed\n"); exit(1); } krb5_free_keytab_entry_contents(context, &kent); krb5_free_principal(context, princ); /* ======================= Finally close ======================= */ kret = krb5_kt_close(context, kt); CHECK(kret, "close"); }
/* Return the list of etypes available for client in keytab. */ static krb5_error_code lookup_etypes_for_keytab(krb5_context context, krb5_keytab keytab, krb5_principal client, krb5_enctype **etypes_out) { krb5_kt_cursor cursor; krb5_keytab_entry entry; krb5_enctype *p, *etypes = NULL, etype; krb5_kvno max_kvno = 0, vno; krb5_error_code ret; krb5_boolean match; size_t count = 0; *etypes_out = NULL; if (keytab->ops->start_seq_get == NULL) return EINVAL; ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret != 0) return ret; while (!(ret = krb5_kt_next_entry(context, keytab, &entry, &cursor))) { /* Extract what we need from the entry and free it. */ etype = entry.key.enctype; vno = entry.vno; match = krb5_principal_compare(context, entry.principal, client); krb5_free_keytab_entry_contents(context, &entry); /* Filter out old or non-matching entries and invalid enctypes. */ if (vno < max_kvno || !match || !krb5_c_valid_enctype(etype)) continue; /* Update max_kvno and reset the list if we find a newer kvno. */ if (vno > max_kvno) { max_kvno = vno; free(etypes); etypes = NULL; count = 0; } /* Leave room for the terminator and possibly a second entry. */ p = realloc(etypes, (count + 3) * sizeof(*etypes)); if (p == NULL) { ret = ENOMEM; goto cleanup; } etypes = p; etypes[count++] = etype; /* All DES key types work with des-cbc-crc, which is more likely to be * accepted by the KDC (since MIT KDCs refuse des-cbc-md5). */ if (etype == ENCTYPE_DES_CBC_MD5 || etype == ENCTYPE_DES_CBC_MD4) etypes[count++] = ENCTYPE_DES_CBC_CRC; etypes[count] = 0; } if (ret != KRB5_KT_END) goto cleanup; ret = 0; *etypes_out = etypes; etypes = NULL; cleanup: krb5_kt_end_seq_get(context, keytab, &cursor); free(etypes); return ret; }
static krb5_error_code reload_keys(void) { krb5_error_code ret; krb5_keytab fkeytab = NULL; krb5_kt_cursor c; krb5_keytab_entry kte; int i, n_nkeys, o_nkeys; krb5_keytab_entry *n_ktent = NULL, *o_ktent; struct stat tstat; if (stat(checkfile_path, &tstat) == 0) { if (have_keytab_keys && tstat.st_mtime == last_reload) { /* We haven't changed since the last time we loaded our keys, so * there's nothing to do. */ ret = 0; goto cleanup; } last_reload = tstat.st_mtime; } else if (have_keytab_keys) { /* stat() failed, but we already have keys, so don't do anything. */ ret = 0; goto cleanup; } if (keytab_name != NULL) ret = krb5_kt_resolve(k5ctx, keytab_name, &fkeytab); else ret = krb5_kt_default(k5ctx, &fkeytab); if (ret != 0) goto cleanup; ret = krb5_kt_start_seq_get(k5ctx, fkeytab, &c); if (ret != 0) goto cleanup; n_nkeys = 0; while (krb5_kt_next_entry(k5ctx, fkeytab, &kte, &c) == 0) { krb5_free_keytab_entry_contents(k5ctx, &kte); n_nkeys++; } krb5_kt_end_seq_get(k5ctx, fkeytab, &c); if (n_nkeys == 0) { ret = KRB5_KT_NOTFOUND; goto cleanup; } n_ktent = calloc(n_nkeys, sizeof(krb5_keytab_entry)); if (n_ktent == NULL) { ret = KRB5_KT_NOTFOUND; goto cleanup; } ret = krb5_kt_start_seq_get(k5ctx, fkeytab, &c); if (ret != 0) goto cleanup; for (i = 0; i < n_nkeys; i++) if (krb5_kt_next_entry(k5ctx, fkeytab, &n_ktent[i], &c) != 0) break; krb5_kt_end_seq_get(k5ctx, fkeytab, &c); if (i < n_nkeys) goto cleanup; have_keytab_keys = 1; o_ktent = ktent; ktent = n_ktent; o_nkeys = nkeys; nkeys = n_nkeys; /* for cleanup */ n_ktent = o_ktent; n_nkeys = o_nkeys; cleanup: if (n_ktent != NULL) { for (i = 0; i < n_nkeys; i++) krb5_free_keytab_entry_contents(k5ctx, &n_ktent[i]); free(n_ktent); } if (fkeytab != NULL) { krb5_kt_close(k5ctx, fkeytab); } return ret; }