New routines for changing passwords of new kdb entries
authorChris Provenzano <proven@mit.edu>
Mon, 7 Aug 1995 15:50:51 +0000 (15:50 +0000)
committerChris Provenzano <proven@mit.edu>
Mon, 7 Aug 1995 15:50:51 +0000 (15:50 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6431 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/kdb/ChangeLog
src/lib/kdb/Makefile.in
src/lib/kdb/kdb_cpw.c

index 9b4889afab8aaff378efa3a1df42bb51e410c688..ff19ad3b3b51d1caa60039e4874d7f61dc4618c6 100644 (file)
@@ -1,23 +1,17 @@
-Fri Aug  4 23:26:22 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
-
-       * 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  <tlyu@dragons-lair.MIT.EDU>
 
-       * 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  <tlyu@lothlorien.MIT.EDU>
 
        * kdb_dbm.c, t_kdb.c: Add prototype for dbm_error and dbm_clearerr
index fad482eecbfc17608588cbb460b7a9d58f215217..48b7213e9a522960469f32484f7537bb147049d1 100644 (file)
@@ -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 \
index 7376c22c4d1eb888779e865a7541dac4ab5ccde1..8324976ccf0014375d0df50d9b509009337a8441 100644 (file)
  */
 
 #include "k5-int.h"
+#include "krb5/adm.h"
 #include <stdio.h>
 #include <errno.h>
 
+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);
 }