static krb5_error_code KRB5_CALLCONV any_remove_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { struct any_data *a = id->data; krb5_error_code ret; int found = 0; while(a != NULL) { ret = krb5_kt_remove_entry(context, a->kt, entry); if(ret == 0) found++; else { if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { krb5_set_error_message(context, ret, N_("Failed to remove keytab " "entry from %s", "keytab name"), a->name); return ret; } } a = a->next; } if(!found) return KRB5_KT_NOTFOUND; return 0; }
static krb5_error_code any_remove_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { struct any_data *a = id->data; krb5_error_code ret; int found = 0; while(a != NULL) { ret = krb5_kt_remove_entry(context, a->kt, entry); if(ret == 0) found++; else { if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { krb5_set_error_string(context, "failed to remove entry from %s", a->name); return ret; } } a = a->next; } if(!found) return KRB5_KT_NOTFOUND; return 0; }
int kt_remove(struct remove_options *opt, int argc, char **argv) { krb5_error_code ret = 0; krb5_keytab_entry entry; krb5_keytab keytab; krb5_principal principal = NULL; krb5_enctype enctype = 0; if(opt->principal_string) { ret = krb5_parse_name(context, opt->principal_string, &principal); if(ret) { krb5_warn(context, ret, "%s", opt->principal_string); return 1; } } if(opt->enctype_string) { ret = krb5_string_to_enctype(context, opt->enctype_string, &enctype); if(ret) { int t; if(sscanf(opt->enctype_string, "%d", &t) == 1) enctype = t; else { krb5_warn(context, ret, "%s", opt->enctype_string); if(principal) krb5_free_principal(context, principal); return 1; } } } if (!principal && !enctype && !opt->kvno_integer) { krb5_warnx(context, "You must give at least one of " "principal, enctype or kvno."); ret = EINVAL; goto out; } if((keytab = ktutil_open_keytab()) == NULL) { ret = 1; goto out; } entry.principal = principal; entry.keyblock.keytype = enctype; entry.vno = opt->kvno_integer; ret = krb5_kt_remove_entry(context, keytab, &entry); krb5_kt_close(context, keytab); if(ret) krb5_warn(context, ret, "remove"); out: if(principal) krb5_free_principal(context, principal); return ret != 0; }
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; }
void KRB5Keytab::removeEntry(KRB5Principal &princ, krb5_kvno kvno, krb5_enctype enctype) { krb5_keytab_entry entry; entry.principal = princ.get(); entry.vno = kvno; #ifdef HEIMDAL entry.keyblock.keytype = enctype; #else entry.key.enctype = enctype; #endif krb5_error_code ret = krb5_kt_remove_entry(g_context.get(), m_keytab, &entry); if (ret) { throw KRB5Exception("krb5_kt_remove_entry", ret); } }
static void test_empty_keytab(krb5_context context, const char *keytab) { krb5_error_code ret; krb5_keytab id; krb5_keytab_entry entry; ret = krb5_kt_resolve(context, keytab, &id); if (ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); memset(&entry, 0, sizeof(entry)); krb5_kt_remove_entry(context, id, &entry); ret = krb5_kt_close(context, id); if (ret) krb5_err(context, 1, ret, "krb5_kt_close"); }
static void remove_principal(char *keytab_str, krb5_keytab keytab, char *princ_str, char *kvno_str) { krb5_principal princ; krb5_keytab_entry entry; krb5_kt_cursor cursor; enum { UNDEF, SPEC, HIGH, ALL, OLD } mode; int code, did_something; krb5_kvno kvno; code = krb5_parse_name(context, princ_str, &princ); if (code != 0) { com_err(whoami, code, "while parsing principal name %s", princ_str); return; } mode = UNDEF; if (kvno_str == NULL) { mode = HIGH; kvno = 0; } else if (strcmp(kvno_str, "all") == 0) { mode = ALL; kvno = 0; } else if (strcmp(kvno_str, "old") == 0) { mode = OLD; kvno = 0; } else { mode = SPEC; kvno = atoi(kvno_str); } /* kvno is set to specified value for SPEC, 0 otherwise */ code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry); if (code != 0) { if (code == ENOENT) { fprintf(stderr, "%s: Keytab %s does not exist.\n", whoami, keytab_str); } else if (code == KRB5_KT_NOTFOUND) { if (mode != SPEC) { fprintf(stderr, "%s: No entry for principal " "%s exists in keytab %s\n", whoami, princ_str, keytab_str); } else { fprintf(stderr, "%s: No entry for principal " "%s with kvno %d exists in keytab " "%s.\n", whoami, princ_str, kvno, keytab_str); } } else com_err(whoami, code, "while retrieving highest kvno from keytab"); return; } /* set kvno to spec'ed value for SPEC, highest kvno otherwise */ kvno = entry.vno; krb5_kt_free_entry(context, &entry); code = krb5_kt_start_seq_get(context, keytab, &cursor); if (code != 0) { com_err(whoami, code, "while starting keytab scan"); return; } did_something = 0; while ((code = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) { if (krb5_principal_compare(context, princ, entry.principal) && ((mode == ALL) || (mode == SPEC && entry.vno == kvno) || (mode == OLD && entry.vno != kvno) || (mode == HIGH && entry.vno == kvno))) { /* * Ack! What a kludge... the scanning functions lock * the keytab so entries cannot be removed while they * are operating. */ code = krb5_kt_end_seq_get(context, keytab, &cursor); if (code != 0) { com_err(whoami, code, "while temporarily ending keytab scan"); return; } code = krb5_kt_remove_entry(context, keytab, &entry); if (code != 0) { com_err(whoami, code, "while deleting entry from keytab"); return; } code = krb5_kt_start_seq_get(context, keytab, &cursor); if (code != 0) { com_err(whoami, code, "while restarting keytab scan"); return; } did_something++; if (!quiet) printf("Entry for principal %s with kvno %d " "removed from keytab %s.\n", princ_str, entry.vno, keytab_str); } krb5_kt_free_entry(context, &entry); } if (code && code != KRB5_KT_END) { com_err(whoami, code, "while scanning keytab"); return; } code = krb5_kt_end_seq_get(context, keytab, &cursor); if (code) { com_err(whoami, code, "while ending keytab scan"); return; } /* * If !did_someting then mode must be OLD or we would have * already returned with an error. But check it anyway just to * prevent unexpected error messages... */ if (!did_something && mode == OLD) { fprintf(stderr, "%s: There is only one entry for principal " "%s in keytab %s\n", whoami, princ_str, keytab_str); } }
/* * Walk the keytab, looking for entries of this principal name, * with KVNO other than current kvno -1. * * These entries are now stale, * we only keep the current and previous entries around. * * Inspired by the code in Samba3 for 'use kerberos keytab'. */ krb5_error_code smb_krb5_remove_obsolete_keytab_entries(TALLOC_CTX *mem_ctx, krb5_context context, krb5_keytab keytab, uint32_t num_principals, krb5_principal *principals, krb5_kvno kvno, bool *found_previous, const char **error_string) { TALLOC_CTX *tmp_ctx; krb5_error_code code; krb5_kt_cursor cursor; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { *error_string = "Cannot allocate tmp_ctx"; return ENOMEM; } *found_previous = true; code = krb5_kt_start_seq_get(context, keytab, &cursor); switch (code) { case 0: break; #ifdef HEIM_ERR_OPNOTSUPP case HEIM_ERR_OPNOTSUPP: #endif case ENOENT: case KRB5_KT_END: /* no point enumerating if there isn't anything here */ code = 0; goto done; default: *error_string = talloc_asprintf(mem_ctx, "failed to open keytab for read of old entries: %s\n", smb_get_krb5_error_message(context, code, mem_ctx)); goto done; } do { krb5_kvno old_kvno = kvno - 1; krb5_keytab_entry entry; bool matched = false; uint32_t i; code = krb5_kt_next_entry(context, keytab, &entry, &cursor); if (code) { break; } for (i = 0; i < num_principals; i++) { krb5_boolean ok; ok = smb_krb5_kt_compare(context, &entry, principals[i], 0, 0); if (ok) { matched = true; break; } } if (!matched) { /* * Free the entry, it wasn't the one we were looking * for anyway */ krb5_kt_free_entry(context, &entry); /* Make sure we do not double free */ ZERO_STRUCT(entry); continue; } /* * Delete it, if it is not kvno - 1. * * Some keytab files store the kvno only in 8bits. Limit the * compare to 8bits, so that we don't miss old keys and delete * them. */ if ((entry.vno & 0xff) != (old_kvno & 0xff)) { krb5_error_code rc; /* Release the enumeration. We are going to * have to start this from the top again, * because deletes during enumeration may not * always be consistent. * * Also, the enumeration locks a FILE: keytab */ krb5_kt_end_seq_get(context, keytab, &cursor); code = krb5_kt_remove_entry(context, keytab, &entry); krb5_kt_free_entry(context, &entry); /* Make sure we do not double free */ ZERO_STRUCT(entry); /* Deleted: Restart from the top */ rc = krb5_kt_start_seq_get(context, keytab, &cursor); if (rc != 0) { krb5_kt_free_entry(context, &entry); /* Make sure we do not double free */ ZERO_STRUCT(entry); DEBUG(1, ("failed to restart enumeration of keytab: %s\n", smb_get_krb5_error_message(context, code, tmp_ctx))); talloc_free(tmp_ctx); return rc; } if (code != 0) { break; } } else { *found_previous = true; } /* Free the entry, we don't need it any more */ krb5_kt_free_entry(context, &entry); /* Make sure we do not double free */ ZERO_STRUCT(entry); } while (code != 0); krb5_kt_end_seq_get(context, keytab, &cursor); switch (code) { case 0: break; case ENOENT: case KRB5_KT_END: code = 0; break; default: *error_string = talloc_asprintf(mem_ctx, "failed in deleting old entries for principal: %s\n", smb_get_krb5_error_message(context, code, mem_ctx)); } code = 0; done: talloc_free(tmp_ctx); return code; }
/** * 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; }
int kt_purge(struct purge_options *opt, int argc, char **argv) { krb5_error_code ret = 0; krb5_kt_cursor cursor; krb5_keytab keytab; krb5_keytab_entry entry; int age; struct e *head = NULL; time_t judgement_day; age = parse_time(opt->age_string, "s"); if(age < 0) { krb5_warnx(context, "unparasable time `%s'", opt->age_string); return 1; } if((keytab = ktutil_open_keytab()) == NULL) return 1; ret = krb5_kt_start_seq_get(context, keytab, &cursor); if(ret){ krb5_warn(context, ret, "%s", keytab_string); goto out; } while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { add_entry (entry.principal, entry.vno, entry.timestamp, &head); krb5_kt_free_entry(context, &entry); } krb5_kt_end_seq_get(context, keytab, &cursor); judgement_day = time (NULL); ret = krb5_kt_start_seq_get(context, keytab, &cursor); if(ret){ krb5_warn(context, ret, "%s", keytab_string); goto out; } while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { struct e *e = get_entry (entry.principal, head); if (e == NULL) { krb5_warnx (context, "ignoring extra entry"); continue; } if (entry.vno < e->max_vno && judgement_day - e->timestamp > age) { if (verbose_flag) { char *name_str; krb5_unparse_name (context, entry.principal, &name_str); printf ("removing %s vno %d\n", name_str, entry.vno); free (name_str); } ret = krb5_kt_remove_entry (context, keytab, &entry); if (ret) krb5_warn (context, ret, "remove"); } krb5_kt_free_entry(context, &entry); } ret = krb5_kt_end_seq_get(context, keytab, &cursor); delete_list (head); out: krb5_kt_close (context, keytab); return ret != 0; }
int kt_rename(struct rename_options *opt, int argc, char **argv) { krb5_error_code ret = 0; krb5_keytab_entry entry; krb5_keytab keytab; krb5_kt_cursor cursor; krb5_principal from_princ, to_princ; ret = krb5_parse_name(context, argv[0], &from_princ); if(ret != 0) { krb5_warn(context, ret, "%s", argv[0]); return 1; } ret = krb5_parse_name(context, argv[1], &to_princ); if(ret != 0) { krb5_free_principal(context, from_princ); krb5_warn(context, ret, "%s", argv[1]); return 1; } if((keytab = ktutil_open_keytab()) == NULL) { krb5_free_principal(context, from_princ); krb5_free_principal(context, to_princ); return 1; } ret = krb5_kt_start_seq_get(context, keytab, &cursor); if(ret) { krb5_kt_close(context, keytab); krb5_free_principal(context, from_princ); krb5_free_principal(context, to_princ); return 1; } while(1) { ret = krb5_kt_next_entry(context, keytab, &entry, &cursor); if(ret != 0) { if(ret != KRB5_CC_END && ret != KRB5_KT_END) krb5_warn(context, ret, "getting entry from keytab"); else ret = 0; break; } if(krb5_principal_compare(context, entry.principal, from_princ)) { krb5_free_principal(context, entry.principal); entry.principal = to_princ; ret = krb5_kt_add_entry(context, keytab, &entry); if(ret) { entry.principal = NULL; krb5_kt_free_entry(context, &entry); krb5_warn(context, ret, "adding entry"); break; } if (opt->delete_flag) { entry.principal = from_princ; ret = krb5_kt_remove_entry(context, keytab, &entry); if(ret) { entry.principal = NULL; krb5_kt_free_entry(context, &entry); krb5_warn(context, ret, "removing entry"); break; } } entry.principal = NULL; } krb5_kt_free_entry(context, &entry); } krb5_kt_end_seq_get(context, keytab, &cursor); krb5_free_principal(context, from_princ); krb5_free_principal(context, to_princ); return ret != 0; }
static void test_memory_keytab(krb5_context context, const char *keytab, const char *keytab2) { krb5_error_code ret; krb5_keytab id, id2, id3; krb5_keytab_entry entry, entry2, entry3; ret = krb5_kt_resolve(context, keytab, &id); if (ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); memset(&entry, 0, sizeof(entry)); ret = krb5_parse_name(context, "*****@*****.**", &entry.principal); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); entry.vno = 1; ret = krb5_generate_random_keyblock(context, ETYPE_AES256_CTS_HMAC_SHA1_96, &entry.keyblock); if (ret) krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); krb5_kt_add_entry(context, id, &entry); ret = krb5_kt_resolve(context, keytab, &id2); if (ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); ret = krb5_kt_get_entry(context, id, entry.principal, 0, ETYPE_AES256_CTS_HMAC_SHA1_96, &entry2); if (ret) krb5_err(context, 1, ret, "krb5_kt_get_entry"); krb5_kt_free_entry(context, &entry2); ret = krb5_kt_close(context, id); if (ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_kt_get_entry(context, id2, entry.principal, 0, ETYPE_AES256_CTS_HMAC_SHA1_96, &entry2); if (ret) krb5_err(context, 1, ret, "krb5_kt_get_entry"); krb5_kt_free_entry(context, &entry2); ret = krb5_kt_close(context, id2); if (ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_kt_resolve(context, keytab2, &id3); if (ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); memset(&entry3, 0, sizeof(entry3)); ret = krb5_parse_name(context, "*****@*****.**", &entry3.principal); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); entry3.vno = 1; ret = krb5_generate_random_keyblock(context, ETYPE_AES256_CTS_HMAC_SHA1_96, &entry3.keyblock); if (ret) krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); krb5_kt_add_entry(context, id3, &entry3); ret = krb5_kt_resolve(context, keytab, &id); if (ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); ret = krb5_kt_get_entry(context, id, entry.principal, 0, ETYPE_AES256_CTS_HMAC_SHA1_96, &entry2); if (ret == 0) krb5_errx(context, 1, "krb5_kt_get_entry when if should fail"); krb5_kt_remove_entry(context, id, &entry); ret = krb5_kt_close(context, id); if (ret) krb5_err(context, 1, ret, "krb5_kt_close"); krb5_kt_free_entry(context, &entry); krb5_kt_remove_entry(context, id3, &entry3); ret = krb5_kt_close(context, id3); if (ret) krb5_err(context, 1, ret, "krb5_kt_close"); krb5_free_principal(context, entry3.principal); krb5_free_keyblock_contents(context, &entry3.keyblock); }
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"); }
static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx, int kvno, krb5_principal *principals, bool delete_all_kvno, krb5_context context, krb5_keytab keytab, bool *found_previous, const char **error_string) { krb5_error_code ret, ret2; krb5_kt_cursor cursor; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } *found_previous = false; /* for each entry in the keytab */ ret = krb5_kt_start_seq_get(context, keytab, &cursor); switch (ret) { case 0: break; #ifdef HEIM_ERR_OPNOTSUPP case HEIM_ERR_OPNOTSUPP: #endif case ENOENT: case KRB5_KT_END: /* no point enumerating if there isn't anything here */ talloc_free(mem_ctx); return 0; default: *error_string = talloc_asprintf(parent_ctx, "failed to open keytab for read of old entries: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx)); talloc_free(mem_ctx); return ret; } while (!ret) { unsigned int i; bool matched = false; krb5_keytab_entry entry; ret = krb5_kt_next_entry(context, keytab, &entry, &cursor); if (ret) { break; } for (i = 0; principals[i]; i++) { /* if it matches our principal */ if (smb_krb5_kt_compare(context, &entry, principals[i], 0, 0)) { matched = true; break; } } if (!matched) { /* Free the entry, * it wasn't the one we were looking for anyway */ krb5_kt_free_entry(context, &entry); continue; } /* delete it, if it is not kvno -1 */ if (entry.vno != (kvno - 1 )) { /* Release the enumeration. We are going to * have to start this from the top again, * because deletes during enumeration may not * always be consistent. * * Also, the enumeration locks a FILE: keytab */ krb5_kt_end_seq_get(context, keytab, &cursor); ret = krb5_kt_remove_entry(context, keytab, &entry); krb5_kt_free_entry(context, &entry); /* Deleted: Restart from the top */ ret2 = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret2) { krb5_kt_free_entry(context, &entry); DEBUG(1, ("failed to restart enumeration of keytab: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); talloc_free(mem_ctx); return ret2; } if (ret) { break; } } else { *found_previous = true; } /* Free the entry, we don't need it any more */ krb5_kt_free_entry(context, &entry); } krb5_kt_end_seq_get(context, keytab, &cursor); switch (ret) { case 0: break; case ENOENT: case KRB5_KT_END: ret = 0; break; default: *error_string = talloc_asprintf(parent_ctx, "failed in deleting old entries for principal: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx)); } talloc_free(mem_ctx); return ret; }
int main(int argc, char **argv) { krb5_context context; krb5_keytab kt; krb5_keytab_entry ktent; krb5_encrypt_block eblock; krb5_creds my_creds; krb5_get_init_creds_opt *opt; kadm5_principal_ent_rec princ_ent; krb5_principal princ, server; char pw[16]; char *whoami, *principal, *authprinc, *authpwd; krb5_data pwdata; void *handle; int ret, test, encnum; unsigned int i; whoami = argv[0]; if (argc < 2 || argc > 4) { fprintf(stderr, "Usage: %s principal [authuser] [authpwd]\n", whoami); exit(1); } principal = argv[1]; authprinc = (argc > 2) ? argv[2] : argv[0]; authpwd = (argc > 3) ? argv[3] : NULL; /* * Setup. Initialize data structures, open keytab, open connection * to kadm5 server. */ memset(&context, 0, sizeof(context)); kadm5_init_krb5_context(&context); ret = krb5_parse_name(context, principal, &princ); if (ret) { com_err(whoami, ret, "while parsing principal name %s", principal); exit(1); } if((ret = krb5_build_principal_ext(context, &server, krb5_princ_realm(kcontext, princ)->length, krb5_princ_realm(kcontext, princ)->data, tgtname.length, tgtname.data, krb5_princ_realm(kcontext, princ)->length, krb5_princ_realm(kcontext, princ)->data, 0))) { com_err(whoami, ret, "while building server name"); exit(1); } ret = krb5_kt_default(context, &kt); if (ret) { com_err(whoami, ret, "while opening keytab"); exit(1); } ret = kadm5_init(context, authprinc, authpwd, KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, NULL, &handle); if (ret) { com_err(whoami, ret, "while initializing connection"); exit(1); } /* these pw's don't need to be secure, just different every time */ SRAND((RAND_TYPE)time((void *) NULL)); pwdata.data = pw; pwdata.length = sizeof(pw); /* * For each test: * * For each enctype in the test, construct a random password/key. * Assign all keys to principal with kadm5_setkey_principal. Add * each key to the keytab, and acquire an initial ticket with the * keytab (XXX can I specify the kvno explicitly?). If * krb5_get_init_creds_keytab succeeds, then the keys were set * successfully. */ for (test = 0; tests[test] != NULL; test++) { krb5_keyblock *testp = tests[test]; kadm5_key_data *extracted; int n_extracted, match; printf("+ Test %d:\n", test); for (encnum = 0; testp[encnum].magic != -1; encnum++) { for (i = 0; i < sizeof(pw); i++) pw[i] = (RAND() % 26) + '0'; /* XXX */ krb5_use_enctype(context, &eblock, testp[encnum].enctype); ret = krb5_string_to_key(context, &eblock, &testp[encnum], &pwdata, NULL); if (ret) { com_err(whoami, ret, "while converting string to key"); exit(1); } } /* now, encnum == # of keyblocks in testp */ ret = kadm5_setkey_principal(handle, princ, testp, encnum); if (ret) { com_err(whoami, ret, "while setting keys"); exit(1); } ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO); if (ret) { com_err(whoami, ret, "while retrieving principal"); exit(1); } ret = kadm5_get_principal_keys(handle, princ, 0, &extracted, &n_extracted); if (ret) { com_err(whoami, ret, "while extracting keys"); exit(1); } for (encnum = 0; testp[encnum].magic != -1; encnum++) { printf("+ enctype %d\n", testp[encnum].enctype); for (match = 0; match < n_extracted; match++) { if (extracted[match].key.enctype == testp[encnum].enctype) break; } if (match >= n_extracted) { com_err(whoami, KRB5_WRONG_ETYPE, "while matching enctypes"); exit(1); } if (extracted[match].key.length != testp[encnum].length || memcmp(extracted[match].key.contents, testp[encnum].contents, testp[encnum].length) != 0) { com_err(whoami, KRB5_KDB_NO_MATCHING_KEY, "verifying keys"); exit(1); } memset(&ktent, 0, sizeof(ktent)); ktent.principal = princ; ktent.key = testp[encnum]; ktent.vno = princ_ent.kvno; ret = krb5_kt_add_entry(context, kt, &ktent); if (ret) { com_err(whoami, ret, "while adding keytab entry"); exit(1); } memset(&my_creds, 0, sizeof(my_creds)); my_creds.client = princ; my_creds.server = server; ktypes[0] = testp[encnum].enctype; ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { com_err(whoami, ret, "while allocating gic opts"); exit(1); } krb5_get_init_creds_opt_set_etype_list(opt, ktypes, 1); ret = krb5_get_init_creds_keytab(context, &my_creds, princ, kt, 0, NULL /* in_tkt_service */, opt); krb5_get_init_creds_opt_free(context, opt); if (ret) { com_err(whoami, ret, "while acquiring initial ticket"); exit(1); } krb5_free_cred_contents(context, &my_creds); /* since I can't specify enctype explicitly ... */ ret = krb5_kt_remove_entry(context, kt, &ktent); if (ret) { com_err(whoami, ret, "while removing keytab entry"); exit(1); } } (void)kadm5_free_kadm5_key_data(context, n_extracted, extracted); } ret = krb5_kt_close(context, kt); if (ret) { com_err(whoami, ret, "while closing keytab"); exit(1); } ret = kadm5_destroy(handle); if (ret) { com_err(whoami, ret, "while closing kadmin connection"); exit(1); } krb5_free_principal(context, princ); krb5_free_principal(context, server); krb5_free_context(context); return 0; }
static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, krb5_keytab keytab, BOOL *found_previous) { krb5_error_code ret, ret2; krb5_kt_cursor cursor; krb5_principal princ; int kvno; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); const char *princ_string; if (!mem_ctx) { return ENOMEM; } *found_previous = False; princ_string = cli_credentials_get_principal(machine_account, mem_ctx); /* Get the principal we will store the new keytab entries under */ ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ); if (ret) { DEBUG(1,("update_keytab: makeing krb5 principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } kvno = cli_credentials_get_kvno(machine_account); /* for each entry in the keytab */ ret = krb5_kt_start_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); switch (ret) { case 0: break; case HEIM_ERR_OPNOTSUPP: case ENOENT: case KRB5_KT_END: /* no point enumerating if there isn't anything here */ talloc_free(mem_ctx); return 0; default: DEBUG(1,("failed to open keytab for read of old entries: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } while (!ret) { krb5_keytab_entry entry; ret = krb5_kt_next_entry(smb_krb5_context->krb5_context, keytab, &entry, &cursor); if (ret) { break; } /* if it matches our principal */ if (!krb5_kt_compare(smb_krb5_context->krb5_context, &entry, princ, 0, 0)) { /* Free the entry, it wasn't the one we were looking for anyway */ krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); continue; } /* delete it, if it is not kvno -1 */ if (entry.vno != (kvno - 1 )) { /* Release the enumeration. We are going to * have to start this from the top again, * because deletes during enumeration may not * always be consistant. * * Also, the enumeration locks a FILE: keytab */ krb5_kt_end_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); ret = krb5_kt_remove_entry(smb_krb5_context->krb5_context, keytab, &entry); krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); /* Deleted: Restart from the top */ ret2 = krb5_kt_start_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); if (ret2) { krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); DEBUG(1,("failed to restart enumeration of keytab: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret2; } if (ret) { break; } } else { *found_previous = True; } /* Free the entry, we don't need it any more */ krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); } krb5_kt_end_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); switch (ret) { case 0: break; case ENOENT: case KRB5_KT_END: ret = 0; break; default: DEBUG(1,("failed in deleting old entries for principal: %s: %s\n", princ_string, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } talloc_free(mem_ctx); return ret; }