summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/hdb/mkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/hdb/mkey.c')
-rw-r--r--source4/heimdal/lib/hdb/mkey.c150
1 files changed, 146 insertions, 4 deletions
diff --git a/source4/heimdal/lib/hdb/mkey.c b/source4/heimdal/lib/hdb/mkey.c
index 9a13d55a51..6dcfc02942 100644
--- a/source4/heimdal/lib/hdb/mkey.c
+++ b/source4/heimdal/lib/hdb/mkey.c
@@ -228,7 +228,7 @@ read_master_encryptionkey(krb5_context context, const char *filename,
should cover all cases, but will break if someone has hacked
this code to really use des-cbc-md5 -- but then that's not my
problem. */
- if(key.keytype == KEYTYPE_DES || key.keytype == ETYPE_DES_CBC_MD5)
+ if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5)
key.keytype = ETYPE_DES_CFB64_NONE;
ret = hdb_process_master_key(context, 0, &key, 0, mkey);
@@ -480,6 +480,131 @@ hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
}
krb5_error_code
+hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno,
+ unsigned flags, hdb_entry *ent)
+{
+ krb5_error_code ret = HDB_ERR_NOENTRY;
+ HDB_extension *ext;
+ HDB_Ext_KeySet *hist_keys;
+ Key *tmp_val;
+ time_t tmp_set_time;
+ unsigned int tmp_len;
+ unsigned int kvno_diff = 0;
+ krb5_kvno tmp_kvno;
+ size_t i, k;
+ int exclude_dead = 0;
+ KerberosTime now = 0;
+ time_t *set_time;
+
+ if (kvno == 0)
+ ret = 0;
+
+ if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) {
+ exclude_dead = 1;
+ now = time(NULL);
+ if (HDB_F_LIVE_CLNT_KVNOS)
+ kvno_diff = hdb_entry_get_kvno_diff_clnt(ent);
+ else
+ kvno_diff = hdb_entry_get_kvno_diff_svc(ent);
+ }
+
+ ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
+ if (ext == NULL)
+ return ret;
+
+ /* For swapping; see below */
+ tmp_len = ent->keys.len;
+ tmp_val = ent->keys.val;
+ tmp_kvno = ent->kvno;
+ (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time);
+
+ hist_keys = &ext->data.u.hist_keys;
+
+ for (i = 0; i < hist_keys->len; i++) {
+ if (kvno != 0 && hist_keys->val[i].kvno != kvno)
+ continue;
+
+ if (exclude_dead &&
+ ((ent->max_life != NULL &&
+ hist_keys->val[i].set_time != NULL &&
+ (*hist_keys->val[i].set_time) < (now - (*ent->max_life))) ||
+ (hist_keys->val[i].kvno < kvno &&
+ (kvno - hist_keys->val[i].kvno) > kvno_diff)))
+ /*
+ * The KDC may want to to check for this keyset's set_time
+ * is within the TGS principal's max_life, say. But we stop
+ * here.
+ */
+ continue;
+
+ /* Either the keys we want, or all the keys */
+ for (k = 0; k < hist_keys->val[i].keys.len; k++) {
+ ret = hdb_unseal_key_mkey(context,
+ &hist_keys->val[i].keys.val[k],
+ db->hdb_master_key);
+ /*
+ * If kvno == 0 we might not want to bail here! E.g., if we
+ * no longer have the right master key, so just ignore this.
+ *
+ * We could filter out keys that we can't decrypt here
+ * because of HDB_ERR_NO_MKEY. However, it seems safest to
+ * filter them out only where necessary, say, in kadm5.
+ */
+ if (ret && kvno != 0)
+ return ret;
+ if (ret && ret != HDB_ERR_NO_MKEY)
+ return (ret);
+ }
+
+ if (kvno == 0)
+ continue;
+
+ /*
+ * What follows is a bit of a hack.
+ *
+ * This is the keyset we're being asked for, but it's not the
+ * current keyset. So we add the current keyset to the history,
+ * leave the one we were asked for in the history, and pretend
+ * the one we were asked for is also the current keyset.
+ *
+ * This is a bit of a defensive hack in case an entry fetched
+ * this way ever gets modified then stored: if the keyset is not
+ * changed we can detect this and put things back, else we won't
+ * drop any keysets from history by accident.
+ *
+ * Note too that we only ever get called with a non-zero kvno
+ * either in the KDC or in cases where we aren't changing the
+ * HDB entry anyways, which is why this is just a defensive
+ * hack. We also don't fetch specific kvnos in the dump case,
+ * so there's no danger that we'll dump this entry and load it
+ * again, repeatedly causing the history to grow boundelessly.
+ */
+ set_time = malloc(sizeof (*set_time));
+ if (set_time == NULL)
+ return ENOMEM;
+
+ /* Swap key sets */
+ ent->kvno = hist_keys->val[i].kvno;
+ ent->keys.val = hist_keys->val[i].keys.val;
+ ent->keys.len = hist_keys->val[i].keys.len;
+ if (hist_keys->val[i].set_time != NULL)
+ /* Sloppy, but the callers we expect won't care */
+ (void) hdb_entry_set_pw_change_time(context, ent,
+ *hist_keys->val[i].set_time);
+ hist_keys->val[i].kvno = tmp_kvno;
+ hist_keys->val[i].keys.val = tmp_val;
+ hist_keys->val[i].keys.len = tmp_len;
+ if (hist_keys->val[i].set_time != NULL)
+ /* Sloppy, but the callers we expect won't care */
+ *hist_keys->val[i].set_time = tmp_set_time;
+
+ return 0;
+ }
+
+ return (ret);
+}
+
+krb5_error_code
hdb_unseal_key(krb5_context context, HDB *db, Key *k)
{
if (db->hdb_master_key_set == 0)
@@ -526,14 +651,31 @@ hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
krb5_error_code
hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
{
- size_t i;
- for(i = 0; i < ent->keys.len; i++){
- krb5_error_code ret;
+ HDB_extension *ext;
+ HDB_Ext_KeySet *hist_keys;
+ size_t i, k;
+ krb5_error_code ret;
+ for(i = 0; i < ent->keys.len; i++){
ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
if (ret)
return ret;
}
+
+ ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
+ if (ext == NULL)
+ return 0;
+ hist_keys = &ext->data.u.hist_keys;
+
+ for (i = 0; i < hist_keys->len; i++) {
+ for (k = 0; k < hist_keys->val[i].keys.len; k++) {
+ ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k],
+ mkey);
+ if (ret)
+ return ret;
+ }
+ }
+
return 0;
}