From dfb25941d81ff7d355e3229ca92a6700d1d77c01 Mon Sep 17 00:00:00 2001 From: Chris Provenzano Date: Mon, 7 Aug 1995 15:50:51 +0000 Subject: [PATCH] New routines for changing passwords of new kdb entries git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6431 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/kdb/ChangeLog | 30 ++- src/lib/kdb/Makefile.in | 2 + src/lib/kdb/kdb_cpw.c | 398 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 396 insertions(+), 34 deletions(-) diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog index 9b4889afa..ff19ad3b3 100644 --- a/src/lib/kdb/ChangeLog +++ b/src/lib/kdb/ChangeLog @@ -1,23 +1,17 @@ -Fri Aug 4 23:26:22 1995 Tom Yu - - * setup_mkey.c (krb5_db_setup_mkey_name): Add parens to shut up - gcc -Wall - - * fetch_mkey.c (krb5_db_fetch_mkey): Add parens to shut up gcc - -Wall - - * verify_mky.c (krb5_db_verify_master_key): Add parens to shut up - gcc -Wall - * kdb_xdr.c: Add parens to shut up gcc -Wall +Mon Aug 07 11:27:37 1995 Chris Provenzano (proven@mit.edu) - * kdb_dbm.c: Add parens to shut up gcc -Wall + * kdb_cpw.c: New routines for changing passwords of db_entried. - * decrypt_key.c (krb5_dbekd_decrypt_key_data): Add parens to shut - up gcc -Wall +Fri Aug 4 23:26:22 1995 Tom Yu - * encrypt_key.c (krb5_dbekd_encrypt_key_data): Add parens to shut - up gcc -Wall + * setup_mkey.c (krb5_db_setup_mkey_name), + * fetch_mkey.c (krb5_db_fetch_mkey), + * verify_mky.c (krb5_db_verify_master_key), + * decrypt_key.c (krb5_dbekd_decrypt_key_data), + * encrypt_key.c (krb5_dbekd_encrypt_key_data), + * kdb_xdr.c, kdb_dbm.c, + Add parens to shut up gcc -Wall Fri Aug 4 16:22:46 EDT 1995 Paul Park (pjpark@mit.edu) * kdb_xdr,{de,en}crypt_key.c - Use encode/decode macros to [de]serialize @@ -40,14 +34,12 @@ Mon Jul 31 15:55:46 EDT 1995 Paul Park (pjpark@mit.edu) Thu Jul 27 15:28:41 EDT 1995 Paul Park (pjpark@mit.edu) * kdbint.h - Obsolete. - -Thu Jul 27 02:59:05 1995 Chris Provenzano (proven@mit.edu) +Thu Jul 27 02:59:05 1995 Chris Provenzano (proven@mit.edu) * decrypt_key.c, encrypt_key.c, kdb_dbm.c, kdb_xdr.c: Rewritten for new kdb format. * kdb_cpw.c : New password changing routines for new kdb format. * verify_mky.c, t_kdb.c : Use new kdb format. - Tue Jul 25 14:06:50 1995 Tom Yu * kdb_dbm.c, t_kdb.c: Add prototype for dbm_error and dbm_clearerr diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in index fad482eec..48b7213e9 100644 --- a/src/lib/kdb/Makefile.in +++ b/src/lib/kdb/Makefile.in @@ -7,6 +7,7 @@ all:: $(OBJS) all-$(WHAT) SRCS= \ $(srcdir)/encrypt_key.c \ $(srcdir)/decrypt_key.c \ + $(srcdir)/kdb_cpw.c \ $(srcdir)/kdb_dbm.c \ $(srcdir)/kdb_xdr.c \ $(srcdir)/verify_mky.c \ @@ -17,6 +18,7 @@ SRCS= \ OBJS= \ encrypt_key.o \ decrypt_key.o \ + kdb_cpw.o \ kdb_dbm.o \ kdb_xdr.o \ verify_mky.o \ diff --git a/src/lib/kdb/kdb_cpw.c b/src/lib/kdb/kdb_cpw.c index 7376c22c4..8324976cc 100644 --- a/src/lib/kdb/kdb_cpw.c +++ b/src/lib/kdb/kdb_cpw.c @@ -23,46 +23,414 @@ */ #include "k5-int.h" +#include "krb5/adm.h" #include #include +static int +get_key_data_kvno(context, count, data) + krb5_context context; + int count; + krb5_key_data * data; +{ + int i, kvno; + /* Find last key version number */ + for (kvno = i = 0; i < count; i++) { + if (kvno < data[i].key_data_kvno) { + kvno = data[i].key_data_kvno; + } + } + return(kvno); +} + +static void +cleanup_key_data(context, count, data) + krb5_context context; + int count; + krb5_key_data * data; +{ + int i, j; + + for (i = 0; i < count; i++) { + for (j = 0; j < data[i].key_data_ver; j++) { + if (data[i].key_data_length[j]) { + free(data[i].key_data_contents[j]); + } + } + } +} + +/* + * Currently we can only generate random keys for preinitialized + * krb5_encrypt_block with a seed. This is bogus but currently + * necessary to insure that we don't generate two keys with the + * same data. + */ +static krb5_error_code +add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno) + krb5_context context; + krb5_encrypt_block * master_eblock; + krb5_key_salt_tuple * ks_tuple; + int ks_tuple_count; + krb5_db_entry * db_entry; + int kvno; +{ + krb5_data krbtgt_princ_entries[] = { + { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }, + { 0, 0, 0 }, + }; + krb5_principal_data krbtgt_princ = { + 0, /* magic number */ + {0, 0, 0}, /* krb5_data realm */ + krbtgt_princ_entries, /* krb5_data *data */ + 2, /* int length */ + KRB5_NT_SRV_INST /* int type */ + }; + krb5_keyblock krbtgt_keyblock, * key; + krb5_pointer krbtgt_seed; + krb5_encrypt_block krbtgt_eblock; + krb5_db_entry krbtgt_entry; + krb5_boolean more; + int max_kvno, one, i, j; + krb5_error_code retval; + + krb5_princ_set_realm_length(context, &krbtgt_princ, + db_entry->princ->realm.length); + krb5_princ_set_realm_data(context, &krbtgt_princ, + db_entry->princ->realm.data); + krb5_princ_component(context, &krbtgt_princ, 1)->length = + db_entry->princ->realm.length; + krb5_princ_component(context, &krbtgt_princ, 1)->data = + db_entry->princ->realm.data; + + /* Get tgt from database */ + if (retval = krb5_db_get_principal(context, &krbtgt_princ, &krbtgt_entry, + &one, &more)) + return(retval); + if ((one > 1) || (more)) { + krb5_db_free_principal(context, &krbtgt_entry, one); + return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; + } + if (!one) + return KRB5_KDB_NOENTRY; + + /* Get max kvno */ + for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) { + if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) { + max_kvno = krbtgt_entry.key_data[j].key_data_kvno; + } + } + + for (i = 0; i < ks_tuple_count; i++) { + if (retval = krb5_dbe_create_key_data(context, db_entry)) + goto add_key_rnd_err; + + for (j = 0; j < krbtgt_entry.n_key_data; j++) { + if ((krbtgt_entry.key_data[j].key_data_kvno == max_kvno) && + (krbtgt_entry.key_data[j].key_data_type[0] == + ks_tuple[i].ks_keytype)) { + break; + } + } + + if (j == krbtgt_entry.n_key_data) { + retval = KRB5_KDB_BAD_KEYTYPE; + goto add_key_rnd_err; + } + + /* Decrypt key */ + if (retval = krb5_dbekd_decrypt_key_data(context, master_eblock, + &krbtgt_entry.key_data[j], + &krbtgt_keyblock, NULL)) { + goto add_key_rnd_err; + } + + /* Init key */ + krb5_use_keytype(context, &krbtgt_eblock, ks_tuple[i].ks_keytype); + if (retval = krb5_process_key(context,&krbtgt_eblock,&krbtgt_keyblock)){ + goto add_key_rnd_err; + } + + /* Init random generator */ + if (retval = krb5_init_random_key(context, &krbtgt_eblock, + &krbtgt_keyblock, &krbtgt_seed)) { + krb5_finish_key(context, &krbtgt_eblock); + goto add_key_rnd_err; + } + + if (retval = krb5_random_key(context,&krbtgt_eblock,krbtgt_seed,&key)) { + krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed); + krb5_finish_key(context, &krbtgt_eblock); + goto add_key_rnd_err; + } + + krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed); + krb5_finish_key(context, &krbtgt_eblock); + + if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, + key, NULL, kvno + 1, + db_entry->key_data)) { + krb5_free_keyblock(context, key); + goto add_key_rnd_err; + } + + /* Finish random key */ + krb5_free_keyblock(context, key); + } + +add_key_rnd_err:; + krb5_db_free_principal(context, &krbtgt_entry, one); + return(retval); +} + +/* + * Change random key for a krb5_db_entry + * Assumes the max kvno + * + * As a side effect all old keys are nuked. + */ +krb5_error_code +krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry) + krb5_context context; + krb5_encrypt_block * master_eblock; + krb5_key_salt_tuple * ks_tuple; + int ks_tuple_count; + krb5_db_entry * db_entry; +{ + int key_data_count; + krb5_key_data * key_data; + krb5_error_code retval; + int kvno; + + /* First save the old keydata */ + kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); + key_data_count = db_entry->n_key_data; + key_data = db_entry->key_data; + db_entry->key_data = NULL; + db_entry->n_key_data = 0; + + if (retval = add_key_rnd(context, master_eblock, ks_tuple, + ks_tuple_count, db_entry, kvno)) { + cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); + db_entry->n_key_data = key_data_count; + db_entry->key_data = key_data; + } else { + cleanup_key_data(context, key_data_count, key_data); + } + return(retval); +} + /* - * Change password for a krb5_db_entry for a specific key version number + * Add random key for a krb5_db_entry + * Assumes the max kvno + * + * As a side effect all old keys older than the max kvno are nuked. */ krb5_error_code -krb5_kdb_cpw_dbe_for_kvno(context, db_entry, password, kvno) +krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry) + krb5_context context; + krb5_encrypt_block * master_eblock; + krb5_key_salt_tuple * ks_tuple; + int ks_tuple_count; + krb5_db_entry * db_entry; +{ + int key_data_count; + krb5_key_data * key_data; + krb5_error_code retval; + int kvno; + int i; + + /* First save the old keydata */ + kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); + key_data_count = db_entry->n_key_data; + key_data = db_entry->key_data; + db_entry->key_data = NULL; + db_entry->n_key_data = 0; + + if (retval = add_key_rnd(context, master_eblock, ks_tuple, + ks_tuple_count, db_entry, kvno)) { + cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); + db_entry->n_key_data = key_data_count; + db_entry->key_data = key_data; + } else { + /* Copy keys with key_data_kvno = kvno */ + for (i = 0; i < key_data_count; i++) { + if (key_data[i].key_data_kvno = kvno) { + if (retval = krb5_dbe_create_key_data(context, db_entry)) { + cleanup_key_data(context, db_entry->n_key_data, + db_entry->key_data); + break; + } + /* We should decrypt/re-encrypt the data to use the same mkvno*/ + db_entry->key_data[db_entry->n_key_data - 1] = key_data[i]; + memset(&key_data[i], 0, sizeof(krb5_key_data)); + } + } + cleanup_key_data(context, key_data_count, key_data); + } + return(retval); +} + +/* + * Add key_data for a krb5_db_entry + * If passwd is NULL the assumes that the caller wants a random password. + */ +static krb5_error_code +add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd, + db_entry, kvno) krb5_context context; + krb5_encrypt_block * master_eblock; + krb5_key_salt_tuple * ks_tuple; + int ks_tuple_count; + char * passwd; krb5_db_entry * db_entry; - char * password; int kvno; { - krb5_error_code retval; - int key; + krb5_error_code retval; + krb5_encrypt_block key_eblock; + krb5_keysalt key_salt; + krb5_keyblock key; + krb5_data pwd; + int i; + + for (i = 0; i < ks_tuple_count; i++) { + krb5_use_keytype(context, &key_eblock, ks_tuple[i].ks_keytype); + if (retval = krb5_dbe_create_key_data(context, db_entry)) + return(retval); + + /* Convert password string to key using appropriate salt */ + switch (key_salt.type = ks_tuple[i].ks_salttype) { + case KRB5_KDB_SALTTYPE_ONLYREALM: { + krb5_data * saltdata; + if (retval = krb5_copy_data(context, krb5_princ_realm(context, + db_entry->princ), &saltdata)) + return(retval); + + key_salt.data = *saltdata; + krb5_xfree(saltdata); + } + case KRB5_KDB_SALTTYPE_NOREALM: + if (retval=krb5_principal2salt_norealm(context, db_entry->princ, + &key_salt.data)) + return(retval); + break; + case KRB5_KDB_SALTTYPE_NORMAL: + if (retval = krb5_principal2salt(context, db_entry->princ, + &key_salt.data)) + return(retval); + break; + case KRB5_KDB_SALTTYPE_V4: + key_salt.data.length = 0; + key_salt.data.data = 0; + break; + default: + return(KRB5_KDB_BAD_SALTTYPE); + } + + pwd.data = passwd; + pwd.length = strlen(passwd); + if (retval = krb5_string_to_key(context, &key_eblock, + ks_tuple[i].ks_keytype, &key, + &pwd, &key_salt.data)) + return(retval); - for (key = 0; key < db_entry.n_key_data; key++) { - if (db_entry.key_data[key] == kvno) { + if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key, + key_salt.type ? (const krb5_keysalt *)&key_salt : NULL, + kvno + 1, &db_entry->key_data[i])) { + krb5_xfree(key.contents); + return(retval); } + krb5_xfree(key.contents); } - return retval; + return(retval); } /* * Change password for a krb5_db_entry * Assumes the max kvno + * + * As a side effect all old keys are nuked. */ krb5_error_code -krb5_kdb_cpw_dbe_for_kvno(context, db_entry, password) +krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry) krb5_context context; + krb5_encrypt_block * master_eblock; + krb5_key_salt_tuple * ks_tuple; + int ks_tuple_count; + char * passwd; krb5_db_entry * db_entry; - char * password; +{ + int key_data_count; + krb5_key_data * key_data; + krb5_error_code retval; int kvno; + + /* First save the old keydata */ + kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); + key_data_count = db_entry->n_key_data; + key_data = db_entry->key_data; + db_entry->key_data = NULL; + db_entry->n_key_data = 0; + + if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, + passwd, db_entry, kvno)) { + cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); + db_entry->n_key_data = key_data_count; + db_entry->key_data = key_data; + } else { + cleanup_key_data(context, key_data_count, key_data); + } + return(retval); +} + +/* + * Add password for a krb5_db_entry + * Assumes the max kvno + * + * As a side effect all old keys older than the max kvno are nuked. + */ +krb5_error_code +krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry) + krb5_context context; + krb5_encrypt_block * master_eblock; + krb5_key_salt_tuple * ks_tuple; + int ks_tuple_count; + char * passwd; + krb5_db_entry * db_entry; { - int key, kvno; + int key_data_count; + krb5_key_data * key_data; + krb5_error_code retval; + int kvno; + int i; + + /* First save the old keydata */ + kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); + key_data_count = db_entry->n_key_data; + key_data = db_entry->key_data; + db_entry->key_data = NULL; + db_entry->n_key_data = 0; - for (kvno = key = 0; key < db_entry.n_key_data; key++) { - if (kvno < db_entry.key_data[key].key_data_kvno) { - kvno = db_entry.key_data[key].key_data_kvno; + if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, + passwd, db_entry, kvno)) { + cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); + db_entry->n_key_data = key_data_count; + db_entry->key_data = key_data; + } else { + /* Copy keys with key_data_kvno = kvno */ + for (i = 0; i < key_data_count; i++) { + if (key_data[i].key_data_kvno = kvno) { + if (retval = krb5_dbe_create_key_data(context, db_entry)) { + cleanup_key_data(context, db_entry->n_key_data, + db_entry->key_data); + break; + } + /* We should decrypt/re-encrypt the data to use the same mkvno*/ + db_entry->key_data[db_entry->n_key_data - 1] = key_data[i]; + memset(&key_data[i], 0, sizeof(krb5_key_data)); + } } + cleanup_key_data(context, key_data_count, key_data); } - return(krb5_kdb_cpw_dbe_for_kvno(context, db_entry, password, kvno)); + return(retval); } -- 2.26.2