Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / src / lib / kdb / kdb_cpw.c
index abaae4f..03efc28 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /* lib/kdb/kdb_cpw.c */
 /*
- * Copyright 1995, 2009 by the Massachusetts Institute of Technology.
+ * Copyright 1995, 2009, 2014 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -54,6 +54,8 @@
 #include <stdio.h>
 #include <errno.h>
 
+enum save { DISCARD_ALL, KEEP_LAST_KVNO, KEEP_ALL };
+
 int
 krb5_db_get_key_data_kvno(context, count, data)
     krb5_context          context;
@@ -76,19 +78,74 @@ cleanup_key_data(context, count, data)
     int                   count;
     krb5_key_data       * data;
 {
-    int i, j;
+    int i;
 
     /* If data is NULL, count is always 0 */
     if (data == NULL) return;
 
-    for (i = 0; i < count; i++) {
-        for (j = 0; j < data[i].key_data_ver; j++) {
-            if (data[i].key_data_length[j]) {
-                krb5_db_free(context, data[i].key_data_contents[j]);
-            }
-        }
+    for (i = 0; i < count; i++)
+        krb5_dbe_free_key_data_contents(context, &data[i]);
+    free(data);
+}
+
+/* Transfer key data from old_kd to new_kd, making sure that new_kd is
+ * encrypted with mkey.  May steal from old_kd and zero it out. */
+static krb5_error_code
+preserve_one_old_key(krb5_context context, krb5_keyblock *mkey,
+                     krb5_db_entry *dbent, krb5_key_data *old_kd,
+                     krb5_key_data *new_kd)
+{
+    krb5_error_code ret;
+    krb5_keyblock kb;
+    krb5_keysalt salt;
+
+    memset(new_kd, 0, sizeof(*new_kd));
+
+    ret = krb5_dbe_decrypt_key_data(context, mkey, old_kd, &kb, NULL);
+    if (ret == 0) {
+        /* old_kd is already encrypted in mkey, so just move it. */
+        *new_kd = *old_kd;
+        memset(old_kd, 0, sizeof(*old_kd));
+        krb5_free_keyblock_contents(context, &kb);
+        return 0;
+    }
+
+    /* Decrypt and re-encrypt old_kd using mkey. */
+    ret = krb5_dbe_decrypt_key_data(context, NULL, old_kd, &kb, &salt);
+    if (ret)
+        return ret;
+    ret = krb5_dbe_encrypt_key_data(context, mkey, &kb, &salt,
+                                    old_kd->key_data_kvno, new_kd);
+    krb5_free_keyblock_contents(context, &kb);
+    krb5_free_data_contents(context, &salt.data);
+    return ret;
+}
+
+/*
+ * Add key_data to dbent, making sure that each entry is encrypted in mkey.  If
+ * kvno is non-zero, preserve only keys of that kvno.  May steal some elements
+ * from key_data and zero them out.
+ */
+static krb5_error_code
+preserve_old_keys(krb5_context context, krb5_keyblock *mkey,
+                  krb5_db_entry *dbent, int kvno, int n_key_data,
+                  krb5_key_data *key_data)
+{
+    krb5_error_code ret;
+    int i;
+
+    for (i = 0; i < n_key_data; i++) {
+        if (kvno != 0 && key_data[i].key_data_kvno != kvno)
+            continue;
+        ret = krb5_dbe_create_key_data(context, dbent);
+        if (ret)
+            return ret;
+        ret = preserve_one_old_key(context, mkey, dbent, &key_data[i],
+                                   &dbent->key_data[dbent->n_key_data - 1]);
+        if (ret)
+            return ret;
     }
-    krb5_db_free(context, data);
+    return 0;
 }
 
 static krb5_error_code
@@ -100,40 +157,10 @@ add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
     krb5_db_entry       * db_entry;
     int                   kvno;
 {
-    krb5_principal        krbtgt_princ;
     krb5_keyblock         key;
-    krb5_db_entry         *krbtgt_entry;
-    int                   max_kvno, i, j, k;
+    int                   i, j;
     krb5_error_code       retval;
-    krb5_key_data         tmp_key_data;
-    krb5_key_data        *tptr;
-
-    memset( &tmp_key_data, 0, sizeof(tmp_key_data));
-
-
-    retval = krb5_build_principal_ext(context, &krbtgt_princ,
-                                      db_entry->princ->realm.length,
-                                      db_entry->princ->realm.data,
-                                      KRB5_TGS_NAME_SIZE,
-                                      KRB5_TGS_NAME,
-                                      db_entry->princ->realm.length,
-                                      db_entry->princ->realm.data,
-                                      0);
-    if (retval)
-        return retval;
-
-    /* Get tgt from database */
-    retval = krb5_db_get_principal(context, krbtgt_princ, 0, &krbtgt_entry);
-    krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
-    if (retval)
-        return(retval);
-
-    /* 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;
-        }
-    }
+    krb5_key_data        *kd_slot;
 
     for (i = 0; i < ks_tuple_count; i++) {
         krb5_boolean similar;
@@ -160,7 +187,8 @@ add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
             continue;
 
         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
-            goto add_key_rnd_err;
+            return retval;
+        kd_slot = &db_entry->key_data[db_entry->n_key_data - 1];
 
         /* there used to be code here to extract the old key, and derive
            a new key from it.  Now that there's a unified prng, that isn't
@@ -169,174 +197,17 @@ add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
         /* make new key */
         if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
                                              &key)))
-            goto add_key_rnd_err;
-
+            return retval;
 
-        /* db library will free this. Since, its a so, it could actually be using different memory management
-           function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used
-           here which will later be copied to the db_entry */
         retval = krb5_dbe_encrypt_key_data(context, master_key, &key, NULL,
-                                           kvno, &tmp_key_data);
+                                           kvno, kd_slot);
 
         krb5_free_keyblock_contents(context, &key);
         if( retval )
-            goto add_key_rnd_err;
-
-        tptr = &db_entry->key_data[db_entry->n_key_data-1];
-
-        tptr->key_data_ver = tmp_key_data.key_data_ver;
-        tptr->key_data_kvno = tmp_key_data.key_data_kvno;
-
-        for( k = 0; k < tmp_key_data.key_data_ver; k++ )
-        {
-            tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
-            tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
-            if( tmp_key_data.key_data_contents[k] )
-            {
-                tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
-                if( tptr->key_data_contents[k] == NULL )
-                {
-                    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
-                    db_entry->key_data = NULL;
-                    db_entry->n_key_data = 0;
-                    retval = ENOMEM;
-                    goto add_key_rnd_err;
-                }
-                memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
-
-                memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
-                free( tmp_key_data.key_data_contents[k] );
-                tmp_key_data.key_data_contents[k] = NULL;
-            }
-        }
-
-    }
-
-add_key_rnd_err:
-    krb5_db_free_principal(context, krbtgt_entry);
-
-    for( i = 0; i < tmp_key_data.key_data_ver; i++ )
-    {
-        if( tmp_key_data.key_data_contents[i] )
-        {
-            memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
-            free( tmp_key_data.key_data_contents[i] );
-        }
-    }
-    return(retval);
-}
-
-/*
- * Change random key for a krb5_db_entry
- * Assumes the max kvno
- *
- * As a side effect all old keys are nuked if keepold is false.
- */
-krb5_error_code
-krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
-    krb5_context          context;
-    krb5_keyblock       * master_key;
-    krb5_key_salt_tuple * ks_tuple;
-    int                   ks_tuple_count;
-    krb5_boolean          keepold;
-    krb5_db_entry       * db_entry;
-{
-    int                   key_data_count;
-    int                   n_new_key_data;
-    krb5_key_data       * key_data;
-    krb5_error_code       retval;
-    int                   kvno;
-    int                   i;
-
-    /* First save the old keydata */
-    kvno = krb5_db_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;
-
-    /* increment the kvno */
-    kvno++;
-
-    retval = add_key_rnd(context, master_key, ks_tuple,
-                         ks_tuple_count, db_entry, kvno);
-    if (retval) {
-        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 if (keepold) {
-        n_new_key_data = db_entry->n_key_data;
-        for (i = 0; i < key_data_count; i++) {
-            retval = krb5_dbe_create_key_data(context, db_entry);
-            if (retval) {
-                cleanup_key_data(context, db_entry->n_key_data,
-                                 db_entry->key_data);
-                break;
-            }
-            db_entry->key_data[i+n_new_key_data] = key_data[i];
-            memset(&key_data[i], 0, sizeof(krb5_key_data));
-        }
-        krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */
-    } else {
-        cleanup_key_data(context, key_data_count, key_data);
+            return retval;
     }
-    return(retval);
-}
 
-/*
- * 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_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
-    krb5_context          context;
-    krb5_keyblock       * master_key;
-    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 = krb5_db_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;
-
-    /* increment the kvno */
-    kvno++;
-
-    if ((retval = add_key_rnd(context, master_key, 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 - 1 ( = old kvno ) */
-        for (i = 0; i < key_data_count; i++) {
-            if (key_data[i].key_data_kvno == (kvno - 1)) {
-                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);
+    return 0;
 }
 
 /* Construct a random explicit salt. */
@@ -381,7 +252,7 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
     krb5_keyblock       * master_key;
     krb5_key_salt_tuple * ks_tuple;
     int                   ks_tuple_count;
-    char                * passwd;
+    const char          * passwd;
     krb5_db_entry       * db_entry;
     int                   kvno;
 {
@@ -389,18 +260,15 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
     krb5_keysalt          key_salt;
     krb5_keyblock         key;
     krb5_data             pwd;
-    int                   i, j, k;
-    krb5_key_data         tmp_key_data;
-    krb5_key_data        *tptr;
-
-    memset( &tmp_key_data, 0, sizeof(tmp_key_data));
-
-    retval = 0;
+    krb5_data             afs_params = string2data("\1"), *s2k_params;
+    int                   i, j;
+    krb5_key_data        *kd_slot;
 
     for (i = 0; i < ks_tuple_count; i++) {
         krb5_boolean similar;
 
         similar = 0;
+        s2k_params = NULL;
 
         /*
          * We could use krb5_keysalt_iterate to replace this loop, or use
@@ -424,6 +292,7 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
 
         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
             return(retval);
+        kd_slot = &db_entry->key_data[db_entry->n_key_data - 1];
 
         /* Convert password string to key using appropriate salt */
         switch (key_salt.type = ks_tuple[i].ks_salttype) {
@@ -452,15 +321,12 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
             key_salt.data.data = 0;
             break;
         case KRB5_KDB_SALTTYPE_AFS3:
-            /* The afs_mit_string_to_key needs to use strlen, and the
-               realm field is not (necessarily) NULL terminated.  */
-            retval = krb5int_copy_data_contents_add0(context,
-                                                     krb5_princ_realm(context,
-                                                                      db_entry->princ),
-                                                     &key_salt.data);
+            retval = krb5int_copy_data_contents(context,
+                                                &db_entry->princ->realm,
+                                                &key_salt.data);
             if (retval)
                 return retval;
-            key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
+            s2k_params = &afs_params;
             break;
         case KRB5_KDB_SALTTYPE_SPECIAL:
             retval = make_random_salt(context, &key_salt);
@@ -471,135 +337,127 @@ add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
             return(KRB5_KDB_BAD_SALTTYPE);
         }
 
-        pwd.data = passwd;
-        pwd.length = strlen(passwd);
+        pwd = string2data((char *)passwd);
 
-        /* AFS string to key will happen here */
-        if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
-                                           &pwd, &key_salt.data, &key))) {
-            if (key_salt.data.data)
-                free(key_salt.data.data);
-            return(retval);
+        retval = krb5_c_string_to_key_with_params(context,
+                                                  ks_tuple[i].ks_enctype,
+                                                  &pwd, &key_salt.data,
+                                                  s2k_params, &key);
+        if (retval) {
+            free(key_salt.data.data);
+            return retval;
         }
 
-        if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
-            key_salt.data.length =
-                krb5_princ_realm(context, db_entry->princ)->length;
-
-        /* memory allocation to be done by db. So, use temporary block and later copy
-           it to the memory allocated by db */
         retval = krb5_dbe_encrypt_key_data(context, master_key, &key,
                                            (const krb5_keysalt *)&key_salt,
-                                           kvno, &tmp_key_data);
+                                           kvno, kd_slot);
         if (key_salt.data.data)
             free(key_salt.data.data);
         free(key.contents);
 
         if( retval )
             return retval;
+    }
 
-        tptr = &db_entry->key_data[db_entry->n_key_data-1];
-
-        tptr->key_data_ver = tmp_key_data.key_data_ver;
-        tptr->key_data_kvno = tmp_key_data.key_data_kvno;
-
-        for( k = 0; k < tmp_key_data.key_data_ver; k++ )
-        {
-            tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
-            tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
-            if( tmp_key_data.key_data_contents[k] )
-            {
-                tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
-                if( tptr->key_data_contents[k] == NULL )
-                {
-                    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
-                    db_entry->key_data = NULL;
-                    db_entry->n_key_data = 0;
-                    retval = ENOMEM;
-                    goto add_key_pwd_err;
-                }
-                memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
-
-                memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
-                free( tmp_key_data.key_data_contents[k] );
-                tmp_key_data.key_data_contents[k] = NULL;
-            }
-        }
+    return 0;
+}
+
+static krb5_error_code
+rekey(krb5_context context, krb5_keyblock *mkey, krb5_key_salt_tuple *ks_tuple,
+      int ks_tuple_count, const char *password, int new_kvno,
+      enum save savekeys, krb5_db_entry *db_entry)
+{
+    krb5_error_code ret;
+    krb5_key_data *key_data;
+    int n_key_data, old_kvno, save_kvno;
+
+    /* Save aside the old key data. */
+    n_key_data = db_entry->n_key_data;
+    key_data = db_entry->key_data;
+    db_entry->n_key_data = 0;
+    db_entry->key_data = NULL;
+
+    /* Make sure the new kvno is greater than the old largest kvno. */
+    old_kvno = krb5_db_get_key_data_kvno(context, n_key_data, key_data);
+    if (new_kvno < old_kvno + 1)
+        new_kvno = old_kvno + 1;
+    /* Wrap from 65535 to 1; we can only store 16-bit kvno values in key_data,
+     * and we assign special meaning to kvno 0. */
+    if (new_kvno == (1 << 16))
+        new_kvno = 1;
+
+    /* Add new keys to the front of the list. */
+    if (password != NULL) {
+        ret = add_key_pwd(context, mkey, ks_tuple, ks_tuple_count, password,
+                          db_entry, new_kvno);
+    } else {
+        ret = add_key_rnd(context, mkey, ks_tuple, ks_tuple_count, db_entry,
+                          new_kvno);
     }
-add_key_pwd_err:
-    for( i = 0; i < tmp_key_data.key_data_ver; i++ )
-    {
-        if( tmp_key_data.key_data_contents[i] )
-        {
-            memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
-            free( tmp_key_data.key_data_contents[i] );
-        }
+    if (ret) {
+        cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+        db_entry->n_key_data = n_key_data;
+        db_entry->key_data = key_data;
+        return ret;
     }
 
-    return(retval);
+    /* Possibly add some or all of the old keys to the back of the list.  May
+     * steal from and zero out some of the old key data entries. */
+    if (savekeys != DISCARD_ALL) {
+        save_kvno = (savekeys == KEEP_LAST_KVNO) ? old_kvno : 0;
+        ret = preserve_old_keys(context, mkey, db_entry, save_kvno, n_key_data,
+                                key_data);
+    }
+
+    /* Free any old key data entries not stolen and zeroed out above. */
+    cleanup_key_data(context, n_key_data, key_data);
+    return ret;
 }
 
 /*
- * Change password for a krb5_db_entry
+ * Change random key for a krb5_db_entry
  * Assumes the max kvno
  *
  * As a side effect all old keys are nuked if keepold is false.
  */
 krb5_error_code
-krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
-                 new_kvno, keepold, db_entry)
-    krb5_context          context;
-    krb5_keyblock       * master_key;
-    krb5_key_salt_tuple * ks_tuple;
-    int                   ks_tuple_count;
-    char                * passwd;
-    int                   new_kvno;
-    krb5_boolean          keepold;
-    krb5_db_entry       * db_entry;
+krb5_dbe_crk(krb5_context context, krb5_keyblock *mkey,
+             krb5_key_salt_tuple *ks_tuple, int ks_tuple_count,
+             krb5_boolean keepold, krb5_db_entry *dbent)
 {
-    int                   key_data_count;
-    int                   n_new_key_data;
-    krb5_key_data       * key_data;
-    krb5_error_code       retval;
-    int                   old_kvno;
-    int                   i;
-
-    /* First save the old keydata */
-    old_kvno = krb5_db_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;
+    return rekey(context, mkey, ks_tuple, ks_tuple_count, NULL, 0,
+                 keepold ? KEEP_ALL : DISCARD_ALL, dbent);
+}
 
-    /* increment the kvno.  if the requested kvno is too small,
-       increment the old kvno */
-    if (new_kvno < old_kvno+1)
-        new_kvno = old_kvno+1;
+/*
+ * 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_dbe_ark(krb5_context context, krb5_keyblock *mkey,
+             krb5_key_salt_tuple *ks_tuple, int ks_tuple_count,
+             krb5_db_entry *dbent)
+{
+    return rekey(context, mkey, ks_tuple, ks_tuple_count, NULL, 0,
+                 KEEP_LAST_KVNO, dbent);
+}
 
-    retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
-                         passwd, db_entry, new_kvno);
-    if (retval) {
-        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 if (keepold) {
-        n_new_key_data = db_entry->n_key_data;
-        for (i = 0; i < key_data_count; i++) {
-            retval = krb5_dbe_create_key_data(context, db_entry);
-            if (retval) {
-                cleanup_key_data(context, db_entry->n_key_data,
-                                 db_entry->key_data);
-                break;
-            }
-            db_entry->key_data[i+n_new_key_data] = key_data[i];
-            memset(&key_data[i], 0, sizeof(krb5_key_data));
-        }
-        krb5_db_free( context, key_data );
-    } else {
-        cleanup_key_data(context, key_data_count, key_data);
-    }
-    return(retval);
+/*
+ * Change password for a krb5_db_entry
+ * Assumes the max kvno
+ *
+ * As a side effect all old keys are nuked if keepold is false.
+ */
+krb5_error_code
+krb5_dbe_def_cpw(krb5_context context, krb5_keyblock *mkey,
+                 krb5_key_salt_tuple *ks_tuple, int ks_tuple_count,
+                 char *password, int new_kvno, krb5_boolean keepold,
+                 krb5_db_entry *dbent)
+{
+    return rekey(context, mkey, ks_tuple, ks_tuple_count, password, new_kvno,
+                 keepold ? KEEP_ALL : DISCARD_ALL, dbent);
 }
 
 /*
@@ -609,51 +467,10 @@ krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
  * As a side effect all old keys older than the max kvno are nuked.
  */
 krb5_error_code
-krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
-    krb5_context          context;
-    krb5_keyblock       * master_key;
-    krb5_key_salt_tuple * ks_tuple;
-    int                   ks_tuple_count;
-    char                * passwd;
-    krb5_db_entry       * db_entry;
+krb5_dbe_apw(krb5_context context, krb5_keyblock *mkey,
+             krb5_key_salt_tuple *ks_tuple, int ks_tuple_count, char *password,
+             krb5_db_entry *dbent)
 {
-    int                   key_data_count;
-    krb5_key_data       * key_data;
-    krb5_error_code       retval;
-    int                   old_kvno, new_kvno;
-    int                   i;
-
-    /* First save the old keydata */
-    old_kvno = krb5_db_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;
-
-    /* increment the kvno */
-    new_kvno = old_kvno+1;
-
-    if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
-                              passwd, db_entry, new_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 == old_kvno */
-        for (i = 0; i < key_data_count; i++) {
-            if (key_data[i].key_data_kvno == old_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);
+    return rekey(context, mkey, ks_tuple, ks_tuple_count, password, 0,
+                 KEEP_LAST_KVNO, dbent);
 }