static krb5_error_code copy_one_entry(krb5_context context, krb5_keytab src_keytab, krb5_keytab dst_keytab, krb5_keytab_entry entry) { krb5_error_code ret; krb5_keytab_entry dummy; char *name_str; char *etype_str; ret = krb5_unparse_name (context, entry.principal, &name_str); if(ret) { krb5_set_error_message(context, ret, "krb5_unparse_name"); name_str = NULL; /* XXX */ return ret; } ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str); if(ret) { krb5_set_error_message(context, ret, "krb5_enctype_to_string"); etype_str = NULL; /* XXX */ return ret; } ret = krb5_kt_get_entry(context, dst_keytab, entry.principal, entry.vno, entry.keyblock.keytype, &dummy); if(ret == 0) { /* this entry is already in the new keytab, so no need to copy it; if the keyblocks are not the same, something is weird, so complain about that */ if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) { krb5_warn(context, 0, "entry with different keyvalue " "already exists for %s, keytype %s, kvno %d", name_str, etype_str, entry.vno); } krb5_kt_free_entry(context, &dummy); krb5_kt_free_entry (context, &entry); free(name_str); free(etype_str); return ret; } else if(ret != KRB5_KT_NOTFOUND) { krb5_set_error_message (context, ret, "fetching %s/%s/%u", name_str, etype_str, entry.vno); krb5_kt_free_entry (context, &entry); free(name_str); free(etype_str); return ret; } ret = krb5_kt_add_entry (context, dst_keytab, &entry); krb5_kt_free_entry (context, &entry); if (ret) { krb5_set_error_message (context, ret, "adding %s/%s/%u", name_str, etype_str, entry.vno); free(name_str); free(etype_str); return ret; } free(name_str); free(etype_str); return ret; }
static OM_uint32 acquire_acceptor_cred (OM_uint32 * minor_status, krb5_context context, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gsskrb5_cred handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec ) { OM_uint32 ret; krb5_error_code kret; ret = GSS_S_FAILURE; kret = get_keytab(context, &handle->keytab); if (kret) goto end; /* check that the requested principal exists in the keytab */ if (handle->principal) { krb5_keytab_entry entry; kret = krb5_kt_get_entry(context, handle->keytab, handle->principal, 0, 0, &entry); if (kret) goto end; krb5_kt_free_entry(context, &entry); ret = GSS_S_COMPLETE; } else { /* * Check if there is at least one entry in the keytab before * declaring it as an useful keytab. */ krb5_keytab_entry tmp; krb5_kt_cursor c; kret = krb5_kt_start_seq_get (context, handle->keytab, &c); if (kret) goto end; if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) { krb5_kt_free_entry(context, &tmp); ret = GSS_S_COMPLETE; /* ok found one entry */ } krb5_kt_end_seq_get (context, handle->keytab, &c); } end: if (ret != GSS_S_COMPLETE) { if (handle->keytab != NULL) krb5_kt_close(context, handle->keytab); if (kret != 0) { *minor_status = kret; } } return (ret); }
krb5_error_code krb5_kt_find_realm(krb5_context context, krb5_keytab keytab, krb5_principal princ, krb5_data *realm) { krb5_kt_cursor cur; krb5_keytab_entry ent; krb5_boolean match; krb5_data tmp_realm; krb5_error_code ret, ret2; ret = krb5_kt_start_seq_get(context, keytab, &cur); if (ret != 0) { return (ret); } while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cur)) == 0) { /* For the comparison the realms should be the same. */ memcpy(&tmp_realm, &ent.principal->realm, sizeof (krb5_data)); memcpy(&ent.principal->realm, &princ->realm, sizeof (krb5_data)); match = krb5_principal_compare(context, ent.principal, princ); /* Copy the realm back */ memcpy(&ent.principal->realm, &tmp_realm, sizeof (krb5_data)); if (match) { /* * A suitable entry was found in the keytab. * Copy its realm */ ret = krb5int_copy_data_contents(context, &ent.principal->realm, realm); if (ret) { krb5_kt_free_entry(context, &ent); krb5_kt_end_seq_get(context, keytab, &cur); return (ret); } krb5_kt_free_entry(context, &ent); break; } krb5_kt_free_entry(context, &ent); } ret2 = krb5_kt_end_seq_get(context, keytab, &cur); if (ret == KRB5_KT_END) { return (KRB5_KT_NOTFOUND); } return (ret ? ret : ret2); }
static krb5_error_code krb5_kt_get_entry_wrapped(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry) { krb5_keytab_entry tmp; krb5_error_code ret; krb5_kt_cursor cursor; if(id->get) return (*id->get)(context, id, principal, kvno, enctype, entry); ret = krb5_kt_start_seq_get (context, id, &cursor); if (ret) { /* This is needed for krb5_verify_init_creds, but keep error * string from previous error for the human. */ context->error_code = KRB5_KT_NOTFOUND; return KRB5_KT_NOTFOUND; } entry->vno = 0; while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { /* the file keytab might only store the lower 8 bits of the kvno, so only compare those bits */ if (kvno == tmp.vno || (tmp.vno < 256 && kvno % 256 == tmp.vno)) { krb5_kt_copy_entry_contents (context, &tmp, entry); krb5_kt_free_entry (context, &tmp); krb5_kt_end_seq_get(context, id, &cursor); return 0; } else if (kvno == 0 && tmp.vno > entry->vno) { if (entry->vno) krb5_kt_free_entry (context, entry); krb5_kt_copy_entry_contents (context, &tmp, entry); } } krb5_kt_free_entry(context, &tmp); } krb5_kt_end_seq_get (context, id, &cursor); if (entry->vno == 0) return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND, id, principal, enctype, kvno); return 0; }
KRB5_DEPRECATED KRB5_LIB_FUNCTION krb5_error_code KRB5_CALLCONV krb5_keytab_key_proc (krb5_context context, krb5_enctype enctype, krb5_salt salt, krb5_const_pointer keyseed, krb5_keyblock **key) { krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); krb5_keytab keytab = args->keytab; krb5_principal principal = args->principal; krb5_error_code ret; krb5_keytab real_keytab; krb5_keytab_entry entry; if(keytab == NULL) krb5_kt_default(context, &real_keytab); else real_keytab = keytab; ret = krb5_kt_get_entry (context, real_keytab, principal, 0, enctype, &entry); if (keytab == NULL) krb5_kt_close (context, real_keytab); if (ret) return ret; ret = krb5_copy_keyblock (context, &entry.keyblock, key); krb5_kt_free_entry(context, &entry); return ret; }
/* * Find the principal of the first entry of a keytab and return it. The * caller is responsible for freeing the result with krb5_free_principal. * Exit on error. */ krb5_principal kerberos_keytab_principal(krb5_context ctx, const char *path) { krb5_keytab keytab; krb5_kt_cursor cursor; krb5_keytab_entry entry; krb5_principal princ; krb5_error_code status; status = krb5_kt_resolve(ctx, path, &keytab); if (status != 0) bail_krb5(ctx, status, "error opening %s", path); status = krb5_kt_start_seq_get(ctx, keytab, &cursor); if (status != 0) bail_krb5(ctx, status, "error reading %s", path); status = krb5_kt_next_entry(ctx, keytab, &entry, &cursor); if (status == 0) { status = krb5_copy_principal(ctx, entry.principal, &princ); if (status != 0) bail_krb5(ctx, status, "error copying principal from %s", path); krb5_kt_free_entry(ctx, &entry); } if (status != 0) bail("no principal found in keytab file %s", path); krb5_kt_end_seq_get(ctx, keytab, &cursor); krb5_kt_close(ctx, keytab); return princ; }
static krb5_error_code mkt_close(krb5_context context, krb5_keytab id) { struct mkt_data *d = id->data, **dp; int i; HEIMDAL_MUTEX_lock(&mkt_mutex); if (d->refcount < 1) krb5_abortx(context, "krb5 internal error, memory keytab refcount < 1 on close"); if (--d->refcount > 0) { HEIMDAL_MUTEX_unlock(&mkt_mutex); return 0; } for (dp = &mkt_head; *dp != NULL; dp = &(*dp)->next) { if (*dp == d) { *dp = d->next; break; } } HEIMDAL_MUTEX_unlock(&mkt_mutex); free(d->name); for(i = 0; i < d->num_entries; i++) krb5_kt_free_entry(context, &d->entries[i]); free(d->entries); free(d); return 0; }
/* * Given two files containing keytab data, second keytab, merge the keys into * the new file. Currently, this doesn't do any cleanup of old kvnos and * doesn't handle duplicate kvnos correctly. Dies on any error. */ static void merge_keytab(krb5_context ctx, const char *newfile, const char *file) { char *oldfile; krb5_keytab old = NULL, temp = NULL; krb5_kt_cursor cursor; krb5_keytab_entry entry; krb5_error_code status; memset(&entry, 0, sizeof(entry)); xasprintf(&oldfile, "WRFILE:%s", file); status = krb5_kt_resolve(ctx, oldfile, &old); if (status != 0) die_krb5(ctx, status, "cannot open keytab %s", file); free(oldfile); status = krb5_kt_resolve(ctx, newfile, &temp); if (status != 0) die_krb5(ctx, status, "cannot open temporary keytab %s", newfile); status = krb5_kt_start_seq_get(ctx, temp, &cursor); if (status != 0) die_krb5(ctx, status, "cannot read temporary keytab %s", newfile); while ((status = krb5_kt_next_entry(ctx, temp, &entry, &cursor)) == 0) { status = krb5_kt_add_entry(ctx, old, &entry); if (status != 0) die_krb5(ctx, status, "cannot write to keytab %s", file); krb5_kt_free_entry(ctx, &entry); } if (status != KRB5_KT_END) die_krb5(ctx, status, "error reading temporary keytab %s", newfile); krb5_kt_end_seq_get(ctx, temp, &cursor); if (old != NULL) krb5_kt_close(ctx, old); if (temp != NULL) krb5_kt_close(ctx, temp); }
static krb5_error_code mkt_remove_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { struct mkt_data *d = id->data; krb5_keytab_entry *e, *end; int found = 0; if (d->num_entries == 0) { krb5_clear_error_string(context); return KRB5_KT_NOTFOUND; } /* do this backwards to minimize copying */ for(end = d->entries + d->num_entries, e = end - 1; e >= d->entries; e--) { if(krb5_kt_compare(context, e, entry->principal, entry->vno, entry->keyblock.keytype)) { krb5_kt_free_entry(context, e); memmove(e, e + 1, (end - e - 1) * sizeof(*e)); memset(end - 1, 0, sizeof(*end)); d->num_entries--; end--; found = 1; } } if (!found) { krb5_clear_error_string (context); return KRB5_KT_NOTFOUND; } e = realloc(d->entries, d->num_entries * sizeof(*d->entries)); if(e != NULL || d->num_entries == 0) d->entries = e; return 0; }
mit_krb5_error_code KRB5_CALLCONV krb5_kt_read_service_key(mit_krb5_context context, mit_krb5_pointer keyprocarg, mit_krb5_principal principal, mit_krb5_kvno vno, mit_krb5_enctype enctype, mit_krb5_keyblock **key) { mit_krb5_keytab keytab; mit_krb5_keytab_entry entry; mit_krb5_error_code ret; LOG_ENTRY(); if (keyprocarg) ret = krb5_kt_resolve (context, keyprocarg, &keytab); else ret = krb5_kt_default (context, &keytab); if (ret) return ret; ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); krb5_kt_close (context, keytab); if (ret) return ret; ret = krb5_copy_keyblock (context, &entry.key, key); krb5_kt_free_entry(context, &entry); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, krb5_principal principal, krb5_kvno vno, krb5_enctype enctype, krb5_keyblock **key) { krb5_keytab keytab; krb5_keytab_entry entry; krb5_error_code ret; if (keyprocarg) ret = krb5_kt_resolve (context, keyprocarg, &keytab); else ret = krb5_kt_default (context, &keytab); if (ret) return ret; ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); krb5_kt_close (context, keytab); if (ret) return ret; ret = krb5_copy_keyblock (context, &entry.keyblock, key); krb5_kt_free_entry(context, &entry); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_kt_have_content(krb5_context context, krb5_keytab id) { krb5_keytab_entry entry; krb5_kt_cursor cursor; krb5_error_code ret; char *name; ret = krb5_kt_start_seq_get(context, id, &cursor); if (ret) goto notfound; ret = krb5_kt_next_entry(context, id, &entry, &cursor); krb5_kt_end_seq_get(context, id, &cursor); if (ret) goto notfound; krb5_kt_free_entry(context, &entry); return 0; notfound: ret = krb5_kt_get_full_name(context, id, &name); if (ret == 0) { krb5_set_error_message(context, KRB5_KT_NOTFOUND, N_("No entry in keytab: %s", ""), name); free(name); } return KRB5_KT_NOTFOUND; }
/* * Given a context, a keytab file, and a realm, return a list of all * principals in that file. */ static struct principal_name * keytab_principals(krb5_context ctx, const char *file, char *realm) { char *princname = NULL, *princrealm = NULL; bool found; krb5_keytab keytab = NULL; krb5_kt_cursor cursor; krb5_keytab_entry entry; krb5_error_code status; struct principal_name *names = NULL, *current = NULL, *last = NULL; memset(&entry, 0, sizeof(entry)); status = krb5_kt_resolve(ctx, file, &keytab); if (status != 0) die_krb5(ctx, status, "cannot open keytab %s", file); status = krb5_kt_start_seq_get(ctx, keytab, &cursor); if (status != 0) die_krb5(ctx, status, "cannot read keytab %s", file); while ((status = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) { status = krb5_unparse_name(ctx, entry.principal, &princname); if (status != 0) die_krb5(ctx, status, "cannot unparse name for a principal"); /* Separate into principal and realm. */ princrealm = strchr(princname, '@'); if (princrealm != NULL) { *princrealm = '\0'; princrealm++; } if (princrealm == NULL || strcmp(princrealm, realm) != 0) continue; /* Check to see if the principal has already been listed. */ found = false; for (current = names; current != NULL; current = current->next) { if (strcmp(current->princ, princname) == 0) { found = true; break; } last = current; } if (found == false) { current = xmalloc(sizeof(struct principal_name)); current->princ = xstrdup(princname); current->next = NULL; if (last == NULL) names = current; else last->next = current; } krb5_kt_free_entry(ctx, &entry); free(princname); } if (status != KRB5_KT_END) die_krb5(ctx, status, "error reading keytab %s", file); krb5_kt_end_seq_get(ctx, keytab, &cursor); krb5_kt_close(ctx, keytab); return names; }
static krb5_error_code update_keytab_entry(krb5_context context, kcm_ccache ccache, krb5_enctype etype, char *cpn, char *spn, char *newpw, krb5_salt salt, unsigned kvno) { krb5_error_code ret; krb5_keytab_entry entry; krb5_data pw; memset(&entry, 0, sizeof(entry)); pw.data = (char *)newpw; pw.length = strlen(newpw); ret = krb5_string_to_key_data_salt(context, etype, pw, salt, &entry.keyblock); if (ret) { kcm_log(0, "String to key conversion failed for principal %s " "and etype %d: %s", cpn, etype, krb5_get_err_text(context, ret)); return ret; } if (spn == NULL) { ret = krb5_copy_principal(context, ccache->client, &entry.principal); if (ret) { kcm_log(0, "Failed to copy principal name %s: %s", cpn, krb5_get_err_text(context, ret)); return ret; } } else { ret = krb5_parse_name(context, spn, &entry.principal); if (ret) { kcm_log(0, "Failed to parse SPN alias %s: %s", spn, krb5_get_err_text(context, ret)); return ret; } } entry.vno = kvno; entry.timestamp = time(NULL); ret = krb5_kt_add_entry(context, ccache->key.keytab, &entry); if (ret) { kcm_log(0, "Failed to update keytab for principal %s " "and etype %d: %s", cpn, etype, krb5_get_err_text(context, ret)); } krb5_kt_free_entry(context, &entry); return ret; }
mit_krb5_error_code KRB5_CALLCONV krb5_kt_get_entry(mit_krb5_context context, mit_krb5_keytab id, mit_krb5_const_principal principal, mit_krb5_kvno kvno, mit_krb5_enctype enctype, mit_krb5_keytab_entry *entry) { mit_krb5_keytab_entry tmp; mit_krb5_error_code ret; mit_krb5_kt_cursor cursor; LOG_ENTRY(); memset(entry, 0, sizeof(*entry)); ret = krb5_kt_start_seq_get (context, id, &cursor); if (ret) return KRB5_KT_NOTFOUND; entry->vno = 0; while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { /* the file keytab might only store the lower 8 bits of the kvno, so only compare those bits */ if (kvno == tmp.vno || (tmp.vno < 256 && kvno % 256 == tmp.vno)) { krb5_kt_copy_entry_contents (context, &tmp, entry); krb5_kt_free_entry (context, &tmp); krb5_kt_end_seq_get(context, id, &cursor); return 0; } else if (kvno == 0 && tmp.vno > entry->vno) { if (entry->vno) krb5_kt_free_entry (context, entry); krb5_kt_copy_entry_contents (context, &tmp, entry); } } krb5_kt_free_entry(context, &tmp); } krb5_kt_end_seq_get (context, id, &cursor); if (entry->vno == 0) return KRB5_KT_NOTFOUND; return 0; }
int kssl_keytab_is_available(KSSL_CTX *kssl_ctx) { krb5_context krb5context = NULL; krb5_keytab krb5keytab = NULL; krb5_keytab_entry entry; krb5_principal princ = NULL; krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; int rc = 0; if ((krb5rc = krb5_init_context(&krb5context))) return (0); /* kssl_ctx->keytab_file == NULL ==> use Kerberos default */ if (kssl_ctx->keytab_file) { krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file, &krb5keytab); if (krb5rc) goto exit; } else { krb5rc = krb5_kt_default(krb5context, &krb5keytab); if (krb5rc) goto exit; } /* the host key we are looking for */ krb5rc = krb5_sname_to_principal(krb5context, NULL, kssl_ctx->service_name ? kssl_ctx->service_name : KRB5SVC, KRB5_NT_SRV_HST, &princ); if (krb5rc) goto exit; krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, princ, 0 /* IGNORE_VNO */, 0 /* IGNORE_ENCTYPE */, &entry); if (krb5rc == KRB5_KT_NOTFOUND) { rc = 1; goto exit; } else if (krb5rc) goto exit; krb5_kt_free_entry(krb5context, &entry); rc = 1; exit: if (krb5keytab) krb5_kt_close(krb5context, krb5keytab); if (princ) krb5_free_principal(krb5context, princ); if (krb5context) krb5_free_context(krb5context); return (rc); }
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 }
static krb5_error_code hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry) { hdb_keytab k = (hdb_keytab)db->hdb_db; krb5_error_code ret; krb5_keytab_entry ktentry; if (!(flags & HDB_F_KVNO_SPECIFIED)) { /* Preserve previous behaviour if no kvno specified */ kvno = 0; } memset(&ktentry, 0, sizeof(ktentry)); entry->entry.flags.server = 1; entry->entry.flags.forwardable = 1; entry->entry.flags.renewable = 1; /* Not recorded in the OD backend, make something up */ ret = krb5_parse_name(context, "hdb/keytab@WELL-KNOWN:KEYTAB-BACKEND", &entry->entry.created_by.principal); if (ret) goto out; /* * XXX really needs to try all enctypes and just not pick the * first one, even if that happens to be des3-cbc-sha1 (ie best * enctype) in the Apple case. A while loop over all known * enctypes should work. */ ret = krb5_kt_get_entry(context, k->keytab, principal, kvno, 0, &ktentry); if (ret) { ret = HDB_ERR_NOENTRY; goto out; } ret = krb5_copy_principal(context, principal, &entry->entry.principal); if (ret) goto out; ret = _hdb_keytab2hdb_entry(context, &ktentry, entry); out: if (ret) { free_hdb_entry(&entry->entry); memset(&entry->entry, 0, sizeof(entry->entry)); } krb5_kt_free_entry(context, &ktentry); return ret; }
static krb5_error_code get_as_key_keytab(krb5_context context, krb5_principal client, krb5_enctype etype, krb5_prompter_fct prompter, void *prompter_data, krb5_data *salt, krb5_data *params, krb5_keyblock *as_key, void *gak_data, k5_response_items *ritems) { krb5_keytab keytab = (krb5_keytab) gak_data; krb5_error_code ret; krb5_keytab_entry kt_ent; krb5_keyblock *kt_key; /* We don't need the password from the responder to create the AS key. */ if (as_key == NULL) return 0; /* if there's already a key of the correct etype, we're done. if the etype is wrong, free the existing key, and make a new one. */ if (as_key->length) { if (as_key->enctype == etype) return(0); krb5_free_keyblock_contents(context, as_key); as_key->length = 0; } if (!krb5_c_valid_enctype(etype)) return(KRB5_PROG_ETYPE_NOSUPP); if ((ret = krb5_kt_get_entry(context, keytab, client, 0, /* don't have vno available */ etype, &kt_ent))) return(ret); ret = krb5_copy_keyblock(context, &kt_ent.key, &kt_key); /* again, krb5's memory management is lame... */ *as_key = *kt_key; free(kt_key); (void) krb5_kt_free_entry(context, &kt_ent); return(ret); }
static krb5_error_code copy_keytab(krb5_context context, krb5_keytab from, krb5_keytab to) { krb5_keytab_entry entry; krb5_kt_cursor cursor; krb5_error_code ret; ret = krb5_kt_start_seq_get(context, from, &cursor); if (ret) return ret; while((ret = krb5_kt_next_entry(context, from, &entry, &cursor)) == 0){ krb5_kt_add_entry(context, to, &entry); krb5_kt_free_entry(context, &entry); } return krb5_kt_end_seq_get(context, from, &cursor); }
static OM_uint32 acquire_acceptor_cred (OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec ) { OM_uint32 ret; krb5_error_code kret; kret = 0; ret = GSS_S_FAILURE; kret = get_keytab(&handle->keytab); if (kret) goto end; /* check that the requested principal exists in the keytab */ if (handle->principal) { krb5_keytab_entry entry; kret = krb5_kt_get_entry(gssapi_krb5_context, handle->keytab, handle->principal, 0, 0, &entry); if (kret) goto end; krb5_kt_free_entry(gssapi_krb5_context, &entry); } ret = GSS_S_COMPLETE; end: if (ret != GSS_S_COMPLETE) { if (handle->keytab != NULL) krb5_kt_close(gssapi_krb5_context, handle->keytab); if (kret != 0) { *minor_status = kret; gssapi_krb5_set_error_string (); } } return (ret); }
static krb5_error_code krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, krb5_keytab keytab) { krb5_error_code retval; krb5_enctype enctype; krb5_keytab_entry ktent; enctype = req->ticket->enc_part.enctype; if ((retval = krb5_kt_get_entry(context, keytab, req->ticket->server, req->ticket->enc_part.kvno, enctype, &ktent))) return retval; retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket); /* Upon error, Free keytab entry first, then return */ (void) krb5_kt_free_entry(context, &ktent); return retval; }
static krb5_error_code KRB5_CALLCONV fkt_remove_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { krb5_keytab_entry e; krb5_kt_cursor cursor; off_t pos_start, pos_end; int found = 0; krb5_error_code ret; ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor); if(ret != 0) goto out; /* return other error here? */ while(fkt_next_entry_int(context, id, &e, &cursor, &pos_start, &pos_end) == 0) { if(krb5_kt_compare(context, &e, entry->principal, entry->vno, entry->keyblock.keytype)) { int32_t len; unsigned char buf[128]; found = 1; krb5_storage_seek(cursor.sp, pos_start, SEEK_SET); len = pos_end - pos_start - 4; krb5_store_int32(cursor.sp, -len); memset(buf, 0, sizeof(buf)); while(len > 0) { krb5_storage_write(cursor.sp, buf, min((size_t)len, sizeof(buf))); len -= min((size_t)len, sizeof(buf)); } } krb5_kt_free_entry(context, &e); } krb5_kt_end_seq_get(context, id, &cursor); out: if (!found) { krb5_clear_error_message (context); return KRB5_KT_NOTFOUND; } return 0; }
/* * In a couple of places we need to get a principal name from a keytab: when * verifying credentials against a keytab, and when querying the name of a * default GSS acceptor cred. Keytabs do not have the concept of a default * principal like ccaches do, so for now we just return the first principal * listed in the keytab, or an error if it's not iterable. In the future we * could consider elevating this to a public API and giving keytab types an * operation to return a default principal, and maybe extending the file format * and tools to support it. Returns KRB5_KT_NOTFOUND if the keytab is empty * or non-iterable. */ krb5_error_code k5_kt_get_principal(krb5_context context, krb5_keytab keytab, krb5_principal *princ_out) { krb5_error_code ret; krb5_kt_cursor cursor; krb5_keytab_entry kte; *princ_out = NULL; if (keytab->ops->start_seq_get == NULL) return KRB5_KT_NOTFOUND; ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) return ret; ret = krb5_kt_next_entry(context, keytab, &kte, &cursor); (void)krb5_kt_end_seq_get(context, keytab, &cursor); if (ret) return (ret == KRB5_KT_END) ? KRB5_KT_NOTFOUND : ret; ret = krb5_copy_principal(context, kte.principal, princ_out); krb5_kt_free_entry(context, &kte); return ret; }
static krb5_error_code get_key_from_keytab(krb5_context context, krb5_auth_context *auth_context, krb5_ap_req *ap_req, krb5_const_principal server, krb5_keytab keytab, krb5_keyblock **out_key) { krb5_keytab_entry entry; krb5_error_code ret; int kvno; krb5_keytab real_keytab; if(keytab == NULL) krb5_kt_default(context, &real_keytab); else real_keytab = keytab; if (ap_req->ticket.enc_part.kvno) kvno = *ap_req->ticket.enc_part.kvno; else kvno = 0; ret = krb5_kt_get_entry (context, real_keytab, server, kvno, ap_req->ticket.enc_part.etype, &entry); if(ret) goto out; ret = krb5_copy_keyblock(context, &entry.keyblock, out_key); krb5_kt_free_entry (context, &entry); out: if(keytab == NULL) krb5_kt_close(context, real_keytab); return ret; }
krb5_error_code KRB5_CALLCONV krb5_server_decrypt_ticket_keytab(krb5_context context, const krb5_keytab kt, krb5_ticket *ticket) { krb5_error_code retval; krb5_enctype enctype; krb5_keytab_entry ktent; enctype = ticket->enc_part.enctype; if ((retval = krb5_kt_get_entry(context, kt, ticket->server, ticket->enc_part.kvno, enctype, &ktent))) return retval; retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket); /* Upon error, Free keytab entry first, then return */ (void) krb5_kt_free_entry(context, &ktent); return retval; }
krb5_error_code KRB5_CALLCONV krb5_mkt_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { krb5_mkt_cursor *pcursor, next; krb5_error_code err = 0; err = KTLOCK(id); if (err) return err; if ( KTLINK(id) == NULL ) { err = KRB5_KT_NOTFOUND; goto done; } for ( pcursor = &KTLINK(id); *pcursor; pcursor = &(*pcursor)->next ) { if ( (*pcursor)->entry->vno == entry->vno && (*pcursor)->entry->key.enctype == entry->key.enctype && krb5_principal_compare(context, (*pcursor)->entry->principal, entry->principal)) break; } if (!*pcursor) { err = KRB5_KT_NOTFOUND; goto done; } krb5_kt_free_entry(context, (*pcursor)->entry); free((*pcursor)->entry); next = (*pcursor)->next; free(*pcursor); (*pcursor) = next; done: KTUNLOCK(id); return err; }
/* * effects: If keyprocarg is not NULL, it is taken to be the name of a * keytab. Otherwise, the default keytab will be used. This * routine opens the keytab and finds the principal associated with * principal, vno, and enctype and returns the resulting key in *key * or returning an error code if it is not found. * returns: Either KSUCCESS or error code. * errors: error code if not found or keyprocarg is invalid. */ krb5_error_code KRB5_CALLCONV krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, krb5_principal principal, krb5_kvno vno, krb5_enctype enctype, krb5_keyblock **key) { krb5_error_code kerror = KSUCCESS; char keytabname[MAX_KEYTAB_NAME_LEN + 1]; /* + 1 for NULL termination */ krb5_keytab id; krb5_keytab_entry entry; /* * Get the name of the file that we should use. */ if (!keyprocarg) { if ((kerror = krb5_kt_default_name(context, (char *)keytabname, sizeof(keytabname) - 1))!= KSUCCESS) return (kerror); } else { memset(keytabname, 0, sizeof(keytabname)); (void) strncpy(keytabname, (char *)keyprocarg, sizeof(keytabname) - 1); } if ((kerror = krb5_kt_resolve(context, (char *)keytabname, &id))) return (kerror); kerror = krb5_kt_get_entry(context, id, principal, vno, enctype, &entry); krb5_kt_close(context, id); if (kerror) return(kerror); krb5_copy_keyblock(context, &entry.key, key); krb5_kt_free_entry(context, &entry); return (KSUCCESS); }
static int check_keytab(krb5_context context, gsskrb5_cred handle, const char *service, int require_lkdc) { krb5_keytab_entry tmp; krb5_error_code ret; krb5_kt_cursor c; int found = 0; ret = krb5_kt_start_seq_get (context, handle->keytab, &c); if (ret) return 0; while (!found && krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) { krb5_principal principal = tmp.principal; if (service) { if (principal->name.name_string.len < 1 || strcmp(principal->name.name_string.val[0], service) != 0) goto next; } if (require_lkdc) { if (krb5_principal_is_lkdc(context, principal)) found = 1; if (krb5_principal_is_pku2u(context, principal)) found = 1; } else found = 1; next: krb5_kt_free_entry(context, &tmp); } krb5_kt_end_seq_get (context, handle->keytab, &c); return found; }
krb5_error_code KRB5_LIB_FUNCTION krb5_kt_copy_entry_contents(krb5_context context, const krb5_keytab_entry *in, krb5_keytab_entry *out) { krb5_error_code ret; memset(out, 0, sizeof(*out)); out->vno = in->vno; ret = krb5_copy_principal (context, in->principal, &out->principal); if (ret) goto fail; ret = krb5_copy_keyblock_contents (context, &in->keyblock, &out->keyblock); if (ret) goto fail; out->timestamp = in->timestamp; return 0; fail: krb5_kt_free_entry (context, out); return ret; }