Initial patch for dealing with AD x-realm key rollover
AD issues x-realm TGTs with kvno 0. On key x-realm trust key change we need to be able to try current and previous keys for trust, else we will have some failures.
This commit is contained in:
@@ -118,7 +118,7 @@ ntlm_service(void *ctx, const heim_idata *req,
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = hdb_enctype2key(context, &user->entry,
|
||||
ret = hdb_enctype2key(context, &user->entry, NULL,
|
||||
ETYPE_ARCFOUR_HMAC_MD5, &key);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret, "NTLM missing arcfour key");
|
||||
|
@@ -883,7 +883,7 @@ _kdc_do_digest(krb5_context context,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(context, &user->entry,
|
||||
ret = hdb_enctype2key(context, &user->entry, NULL,
|
||||
ETYPE_ARCFOUR_HMAC_MD5, &key);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret,
|
||||
@@ -1209,7 +1209,7 @@ _kdc_do_digest(krb5_context context,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(context, &user->entry,
|
||||
ret = hdb_enctype2key(context, &user->entry, NULL,
|
||||
ETYPE_ARCFOUR_HMAC_MD5, &key);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret, "NTLM missing arcfour key");
|
||||
|
@@ -61,7 +61,7 @@ get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto)
|
||||
ret = _kdc_get_preferred_key(r->context, r->config, fast_user,
|
||||
"fast-cookie", &enctype, &cookie_key);
|
||||
else
|
||||
ret = hdb_enctype2key(r->context, &fast_user->entry,
|
||||
ret = hdb_enctype2key(r->context, &fast_user->entry, NULL,
|
||||
enctype, &cookie_key);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -438,7 +438,7 @@ _kdc_fast_unwrap_request(kdc_request_t r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(r->context, &armor_user->entry,
|
||||
ret = hdb_enctype2key(r->context, &armor_user->entry, NULL,
|
||||
ap_req.ticket.enc_part.etype,
|
||||
&armor_key);
|
||||
if (ret) {
|
||||
|
@@ -173,7 +173,7 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key,
|
||||
if (clientbest == (krb5_enctype)ETYPE_NULL)
|
||||
clientbest = p[i];
|
||||
/* check target princ support */
|
||||
ret = hdb_enctype2key(context, &princ->entry, p[i], &key);
|
||||
ret = hdb_enctype2key(context, &princ->entry, NULL, p[i], &key);
|
||||
if (ret)
|
||||
continue;
|
||||
if (is_preauth && !is_default_salt_p(&def_salt, key))
|
||||
@@ -206,7 +206,8 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key,
|
||||
!_kdc_is_weak_exception(princ->entry.principal, etypes[i]))
|
||||
continue;
|
||||
|
||||
while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) {
|
||||
while (hdb_next_enctype2key(context, &princ->entry, NULL,
|
||||
etypes[i], &key) == 0) {
|
||||
if (key->key.keyvalue.length == 0) {
|
||||
ret = KRB5KDC_ERR_NULL_KEY;
|
||||
continue;
|
||||
@@ -552,7 +553,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(r->context, &r->client->entry,
|
||||
ret = hdb_enctype2key(r->context, &r->client->entry, NULL,
|
||||
enc_data.etype, &pa_key);
|
||||
if(ret){
|
||||
char *estr;
|
||||
@@ -608,7 +609,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa)
|
||||
krb5_free_error_message(r->context, msg);
|
||||
free(str);
|
||||
|
||||
if(hdb_next_enctype2key(r->context, &r->client->entry,
|
||||
if(hdb_next_enctype2key(r->context, &r->client->entry, NULL,
|
||||
enc_data.etype, &pa_key) == 0)
|
||||
goto try_next_key;
|
||||
|
||||
|
@@ -139,7 +139,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
|
||||
|
||||
{
|
||||
Key *key;
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
|
||||
if (ret == 0)
|
||||
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
|
||||
if (ret) {
|
||||
@@ -226,7 +226,8 @@ check_KRB5SignedPath(krb5_context context,
|
||||
|
||||
{
|
||||
Key *key;
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
|
||||
sp.etype, &key);
|
||||
if (ret == 0)
|
||||
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
|
||||
if (ret) {
|
||||
@@ -1156,6 +1157,10 @@ tgs_parse_request(krb5_context context,
|
||||
krb5_flags ap_req_options;
|
||||
krb5_flags verify_ap_req_flags;
|
||||
krb5_crypto crypto;
|
||||
krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
|
||||
krb5uint32 krbtgt_kvno_try;
|
||||
int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
|
||||
const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
|
||||
Key *tkey;
|
||||
krb5_keyblock *subkey = NULL;
|
||||
unsigned usage;
|
||||
@@ -1186,20 +1191,52 @@ tgs_parse_request(krb5_context context,
|
||||
ap_req.ticket.sname,
|
||||
ap_req.ticket.realm);
|
||||
|
||||
ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
|
||||
krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
|
||||
krbtgt_kvno_try = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
|
||||
ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
|
||||
&krbtgt_kvno, NULL, krbtgt);
|
||||
|
||||
if(ret == HDB_ERR_NOT_FOUND_HERE) {
|
||||
if (ret == HDB_ERR_NOT_FOUND_HERE) {
|
||||
/* XXX Factor out this unparsing of the same princ all over */
|
||||
char *p;
|
||||
ret = krb5_unparse_name(context, princ, &p);
|
||||
if (ret != 0)
|
||||
p = failed;
|
||||
krb5_free_principal(context, princ);
|
||||
kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
|
||||
kdc_log(context, config, 5,
|
||||
"Ticket-granting ticket account %s does not have secrets at "
|
||||
"this KDC, need to proxy", p);
|
||||
if (ret == 0)
|
||||
free(p);
|
||||
ret = HDB_ERR_NOT_FOUND_HERE;
|
||||
goto out;
|
||||
} else if(ret){
|
||||
} else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
|
||||
char *p;
|
||||
ret = krb5_unparse_name(context, princ, &p);
|
||||
if (ret != 0)
|
||||
p = failed;
|
||||
krb5_free_principal(context, princ);
|
||||
kdc_log(context, config, 5,
|
||||
"Ticket-granting ticket account %s does not have keys for "
|
||||
"kvno %d at this KDC", p, krbtgt_kvno);
|
||||
if (ret == 0)
|
||||
free(p);
|
||||
ret = HDB_ERR_KVNO_NOT_FOUND;
|
||||
goto out;
|
||||
} else if (ret == HDB_ERR_NO_MKEY) {
|
||||
char *p;
|
||||
ret = krb5_unparse_name(context, princ, &p);
|
||||
if (ret != 0)
|
||||
p = failed;
|
||||
krb5_free_principal(context, princ);
|
||||
kdc_log(context, config, 5,
|
||||
"Missing master key for decrypting keys for ticket-granting "
|
||||
"ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
|
||||
if (ret == 0)
|
||||
free(p);
|
||||
ret = HDB_ERR_KVNO_NOT_FOUND;
|
||||
goto out;
|
||||
} else if (ret) {
|
||||
const char *msg = krb5_get_error_message(context, ret);
|
||||
char *p;
|
||||
ret = krb5_unparse_name(context, princ, &p);
|
||||
@@ -1215,30 +1252,17 @@ tgs_parse_request(krb5_context context,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(ap_req.ticket.enc_part.kvno &&
|
||||
*ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
|
||||
char *p;
|
||||
|
||||
ret = krb5_unparse_name (context, princ, &p);
|
||||
krb5_free_principal(context, princ);
|
||||
if (ret != 0)
|
||||
p = failed;
|
||||
kdc_log(context, config, 0,
|
||||
"Ticket kvno = %d, DB kvno = %d (%s)",
|
||||
*ap_req.ticket.enc_part.kvno,
|
||||
(*krbtgt)->entry.kvno,
|
||||
p);
|
||||
if (ret == 0)
|
||||
free (p);
|
||||
ret = KRB5KRB_AP_ERR_BADKEYVER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*krbtgt_etype = ap_req.ticket.enc_part.etype;
|
||||
|
||||
ret = hdb_enctype2key(context, &(*krbtgt)->entry,
|
||||
next_kvno:
|
||||
krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
|
||||
ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
|
||||
ap_req.ticket.enc_part.etype, &tkey);
|
||||
if(ret){
|
||||
if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
|
||||
kvno_search_tries--;
|
||||
krbtgt_kvno_try--;
|
||||
goto next_kvno;
|
||||
} else if (ret) {
|
||||
char *str = NULL, *p = NULL;
|
||||
|
||||
krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
|
||||
@@ -1267,6 +1291,11 @@ tgs_parse_request(krb5_context context,
|
||||
&ap_req_options,
|
||||
ticket,
|
||||
KRB5_KU_TGS_REQ_AUTH);
|
||||
if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
|
||||
kvno_search_tries--;
|
||||
krbtgt_kvno_try--;
|
||||
goto next_kvno;
|
||||
}
|
||||
|
||||
krb5_free_principal(context, princ);
|
||||
if(ret) {
|
||||
@@ -1554,7 +1583,7 @@ tgs_build_reply(krb5_context context,
|
||||
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
|
||||
goto out;
|
||||
}
|
||||
ret = hdb_enctype2key(context, &uu->entry,
|
||||
ret = hdb_enctype2key(context, &uu->entry, NULL,
|
||||
t->enc_part.etype, &uukey);
|
||||
if(ret){
|
||||
_kdc_free_ent(context, uu);
|
||||
@@ -1734,7 +1763,7 @@ server_lookup:
|
||||
* Validate authoriation data
|
||||
*/
|
||||
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry,
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
|
||||
krbtgt_etype, &tkey_check);
|
||||
if(ret) {
|
||||
kdc_log(context, config, 0,
|
||||
@@ -1814,7 +1843,7 @@ server_lookup:
|
||||
"Failed to find key for krbtgt PAC signature");
|
||||
goto out;
|
||||
}
|
||||
ret = hdb_enctype2key(context, &krbtgt_out->entry,
|
||||
ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
|
||||
tkey_sign->key.keytype, &tkey_sign);
|
||||
if(ret) {
|
||||
kdc_log(context, config, 0,
|
||||
@@ -2065,6 +2094,8 @@ server_lookup:
|
||||
t = &b->additional_tickets->val[0];
|
||||
|
||||
ret = hdb_enctype2key(context, &client->entry,
|
||||
hdb_kvno2keys(context, &client->entry,
|
||||
t->enc_part.kvno ? * t->enc_part.kvno : 0),
|
||||
t->enc_part.etype, &clientkey);
|
||||
if(ret){
|
||||
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
|
||||
|
@@ -143,7 +143,7 @@ _kdc_get_preferred_key(krb5_context context,
|
||||
for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) {
|
||||
if (krb5_enctype_valid(context, p[i]) != 0)
|
||||
continue;
|
||||
ret = hdb_enctype2key(context, &h->entry, p[i], key);
|
||||
ret = hdb_enctype2key(context, &h->entry, NULL, p[i], key);
|
||||
if (ret != 0)
|
||||
continue;
|
||||
if (enctype != NULL)
|
||||
@@ -157,8 +157,8 @@ _kdc_get_preferred_key(krb5_context context,
|
||||
if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype)
|
||||
!= 0)
|
||||
continue;
|
||||
ret = hdb_enctype2key(context, &h->entry,
|
||||
h->entry.keys.val[i].key.keytype, key);
|
||||
ret = hdb_enctype2key(context, &h->entry, NULL,
|
||||
h->entry.keys.val[i].key.keytype, key);
|
||||
if (ret != 0)
|
||||
continue;
|
||||
if (enctype != NULL)
|
||||
|
@@ -92,19 +92,42 @@ static struct hdb_method dbmetod =
|
||||
{ HDB_INTERFACE_VERSION, "", hdb_ndbm_create };
|
||||
#endif
|
||||
|
||||
const Keys *
|
||||
hdb_kvno2keys(krb5_context context,
|
||||
const hdb_entry *e,
|
||||
krb5_kvno kvno)
|
||||
{
|
||||
HDB_Ext_KeySet *hist_keys;
|
||||
HDB_extension *extp;
|
||||
size_t i;
|
||||
|
||||
if (kvno == 0)
|
||||
return &e->keys;
|
||||
|
||||
extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys);
|
||||
if (extp == NULL)
|
||||
return 0;
|
||||
|
||||
hist_keys = &extp->data.u.hist_keys;
|
||||
for (i = 0; i < hist_keys->len; i++) {
|
||||
if (hist_keys->val[i].kvno == kvno)
|
||||
return &hist_keys->val[i].keys;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_next_enctype2key(krb5_context context,
|
||||
const hdb_entry *e,
|
||||
const Keys *keyset,
|
||||
krb5_enctype enctype,
|
||||
Key **key)
|
||||
{
|
||||
const Keys *keys = keyset ? keyset : &e->keys;
|
||||
Key *k;
|
||||
|
||||
for (k = *key ? (*key) + 1 : e->keys.val;
|
||||
k < e->keys.val + e->keys.len;
|
||||
k++)
|
||||
{
|
||||
for (k = *key ? (*key) + 1 : keys->val; k < keys->val + keys->len; k++) {
|
||||
if(k->key.keytype == enctype){
|
||||
*key = k;
|
||||
return 0;
|
||||
@@ -119,11 +142,12 @@ hdb_next_enctype2key(krb5_context context,
|
||||
krb5_error_code
|
||||
hdb_enctype2key(krb5_context context,
|
||||
hdb_entry *e,
|
||||
const Keys *keyset,
|
||||
krb5_enctype enctype,
|
||||
Key **key)
|
||||
{
|
||||
*key = NULL;
|
||||
return hdb_next_enctype2key(context, e, enctype, key);
|
||||
return hdb_next_enctype2key(context, e, keyset, enctype, key);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -45,6 +45,7 @@ EXPORTS
|
||||
hdb_init_db
|
||||
hdb_interface_version DATA
|
||||
hdb_key2principal
|
||||
hdb_kvno2keys
|
||||
hdb_list_builtin
|
||||
hdb_lock
|
||||
hdb_next_enctype2key
|
||||
|
@@ -47,6 +47,7 @@ HEIMDAL_HDB_1.0 {
|
||||
hdb_get_dbinfo;
|
||||
hdb_init_db;
|
||||
hdb_key2principal;
|
||||
hdb_kvno2keys;
|
||||
hdb_list_builtin;
|
||||
hdb_lock;
|
||||
hdb_next_enctype2key;
|
||||
|
Reference in New Issue
Block a user