Refactor salt computation into libkdb5
authorGreg Hudson <ghudson@mit.edu>
Mon, 24 Oct 2011 15:09:32 +0000 (15:09 +0000)
committerGreg Hudson <ghudson@mit.edu>
Mon, 24 Oct 2011 15:09:32 +0000 (15:09 +0000)
Add a new API krb5_dbe_compute_salt() to determine the salt for a key
data entry, and use it in the three places we currently compute salts.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25410 dc483132-0cff-0310-8789-dd5450dbe970

src/include/kdb.h
src/kdc/kdc_preauth.c
src/kdc/kdc_util.c
src/kdc/kdc_util.h
src/lib/kadm5/srv/svr_principal.c
src/lib/kdb/kdb5.c
src/lib/kdb/libkdb5.exports

index 78f786f3b99a52c10797ddbaf3343d6327d7f083..0f50a83c16cb5da73d77a34453062c6c70d4360c 100644 (file)
@@ -576,6 +576,12 @@ krb5_dbe_update_tl_data( krb5_context          context,
                          krb5_db_entry       * entry,
                          krb5_tl_data        * new_tl_data);
 
+/* Compute the salt for a key data entry given the corresponding principal. */
+krb5_error_code
+krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key,
+                      krb5_const_principal princ, krb5_int16 *salttype_out,
+                      krb5_data **salt_out);
+
 krb5_error_code
 krb5_dbe_cpw( krb5_context        kcontext,
               krb5_keyblock       * master_key,
index 272980db5a855519102dcfa400604a14ef57221c..fc7e43bcad7ce9a80558060ae42a9ef89584c599 100644 (file)
@@ -1315,62 +1315,54 @@ request_contains_enctype(krb5_context context,  const krb5_kdc_req *request,
 static krb5_error_code
 _make_etype_info_entry(krb5_context context,
                        krb5_principal client_princ, krb5_key_data *client_key,
-                       krb5_enctype etype, krb5_etype_info_entry **entry,
+                       krb5_enctype etype, krb5_etype_info_entry **entry_out,
                        int etype_info2)
 {
-    krb5_data                   salt;
-    krb5_etype_info_entry *     tmp_entry;
-    krb5_error_code             retval;
+    krb5_error_code retval;
+    krb5_int16 salttype;
+    krb5_data *salt = NULL;
+    krb5_etype_info_entry *entry = NULL;
 
-    if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL)
+    *entry_out = NULL;
+    entry = malloc(sizeof(*entry));
+    if (entry == NULL)
         return ENOMEM;
 
-    salt.data = 0;
-
-    tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY;
-    tmp_entry->etype = etype;
-    tmp_entry->length = KRB5_ETYPE_NO_SALT;
-    tmp_entry->salt = 0;
-    tmp_entry->s2kparams.data = NULL;
-    tmp_entry->s2kparams.length = 0;
-    retval = get_salt_from_key(context, client_princ, client_key, &salt);
+    entry->magic = KV5M_ETYPE_INFO_ENTRY;
+    entry->etype = etype;
+    entry->length = KRB5_ETYPE_NO_SALT;
+    entry->salt = NULL;
+    entry->s2kparams = empty_data();
+    retval = krb5_dbe_compute_salt(context, client_key, client_princ,
+                                   &salttype, &salt);
     if (retval)
-        goto fail;
-    if (etype_info2 && client_key->key_data_ver > 1 &&
-        client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) {
+        goto cleanup;
+    if (etype_info2 && salttype == KRB5_KDB_SALTTYPE_AFS3) {
         switch (etype) {
         case ENCTYPE_DES_CBC_CRC:
         case ENCTYPE_DES_CBC_MD4:
         case ENCTYPE_DES_CBC_MD5:
-            tmp_entry->s2kparams.data = malloc(1);
-            if (tmp_entry->s2kparams.data == NULL) {
-                retval = ENOMEM;
-                goto fail;
-            }
-            tmp_entry->s2kparams.length = 1;
-            tmp_entry->s2kparams.data[0] = 1;
+            retval = alloc_data(&entry->s2kparams, 1);
+            if (retval)
+                goto cleanup;
+            entry->s2kparams.data[0] = 1;
             break;
         default:
             break;
         }
     }
 
-    if (salt.length >= 0) {
-        tmp_entry->length = salt.length;
-        tmp_entry->salt = (unsigned char *) salt.data;
-        salt.data = 0;
-    }
-    *entry = tmp_entry;
-    return 0;
+    entry->length = salt->length;
+    entry->salt = (unsigned char *)salt->data;
+    salt->data = NULL;
+    *entry_out = entry;
+    entry = NULL;
 
-fail:
-    if (tmp_entry) {
-        if (tmp_entry->s2kparams.data)
-            free(tmp_entry->s2kparams.data);
-        free(tmp_entry);
-    }
-    if (salt.data)
-        free(salt.data);
+cleanup:
+    if (entry != NULL)
+        krb5_free_data_contents(context, &entry->s2kparams);
+    free(entry);
+    krb5_free_data(context, salt);
     return retval;
 }
 
@@ -1606,8 +1598,8 @@ return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
 {
     krb5_error_code     retval;
     krb5_pa_data *      padata;
-    krb5_data *         scratch;
-    krb5_data           salt_data;
+    krb5_data *         salt = NULL;
+    krb5_int16          salttype;
     krb5_key_data *     client_key = rock->client_key;
     int i;
 
@@ -1615,74 +1607,37 @@ return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
         if (enctype_requires_etype_info_2(request->ktype[i]))
             return 0;
     }
-    if (client_key->key_data_ver == 1 ||
-        client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)
+    retval = krb5_dbe_compute_salt(context, client_key, request->client,
+                                   &salttype, &salt);
+    if (retval)
         return 0;
 
-    if ((padata = malloc(sizeof(krb5_pa_data))) == NULL)
-        return ENOMEM;
+    padata = k5alloc(sizeof(*padata), &retval);
+    if (padata == NULL)
+        goto cleanup;
     padata->magic = KV5M_PA_DATA;
-    padata->pa_type = KRB5_PADATA_PW_SALT;
 
-    switch (client_key->key_data_type[1]) {
-    case KRB5_KDB_SALTTYPE_V4:
-        /* send an empty (V4) salt */
-        padata->contents = 0;
-        padata->length = 0;
-        break;
-    case KRB5_KDB_SALTTYPE_NOREALM:
-        if ((retval = krb5_principal2salt_norealm(kdc_context,
-                                                  request->client,
-                                                  &salt_data)))
+    if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
+        padata->contents = k5alloc(salt->length + 1, &retval);
+        if (padata->contents == NULL)
             goto cleanup;
-        padata->contents = (krb5_octet *)salt_data.data;
-        padata->length = salt_data.length;
-        break;
-    case KRB5_KDB_SALTTYPE_AFS3:
-        /* send an AFS style realm-based salt */
-        /* for now, just pass the realm back and let the client
-           do the work. In the future, add a kdc configuration
-           variable that specifies the old cell name. */
+        memcpy(padata->contents, salt->data, salt->length);
         padata->pa_type = KRB5_PADATA_AFS3_SALT;
-        /* it would be just like ONLYREALM, but we need to pass the 0 */
-        scratch = krb5_princ_realm(kdc_context, request->client);
-        if ((padata->contents = malloc(scratch->length+1)) == NULL) {
-            retval = ENOMEM;
-            goto cleanup;
-        }
-        memcpy(padata->contents, scratch->data, scratch->length);
-        padata->length = scratch->length+1;
-        padata->contents[scratch->length] = 0;
-        break;
-    case KRB5_KDB_SALTTYPE_ONLYREALM:
-        scratch = krb5_princ_realm(kdc_context, request->client);
-        if ((padata->contents = malloc(scratch->length)) == NULL) {
-            retval = ENOMEM;
-            goto cleanup;
-        }
-        memcpy(padata->contents, scratch->data, scratch->length);
-        padata->length = scratch->length;
-        break;
-    case KRB5_KDB_SALTTYPE_SPECIAL:
-        if ((padata->contents = malloc(client_key->key_data_length[1]))
-            == NULL) {
-            retval = ENOMEM;
-            goto cleanup;
-        }
-        memcpy(padata->contents, client_key->key_data_contents[1],
-               client_key->key_data_length[1]);
-        padata->length = client_key->key_data_length[1];
-        break;
-    default:
-        free(padata);
-        return 0;
+        padata->contents[salt->length] = '\0';
+        padata->length = salt->length + 1;
+    } else {
+        padata->pa_type = KRB5_PADATA_PW_SALT;
+        padata->length = salt->length;
+        padata->contents = (krb5_octet *)salt->data;
+        salt->data = NULL;
     }
 
     *send_pa = padata;
-    return 0;
+    padata = NULL;
 
 cleanup:
     free(padata);
+    krb5_free_data(context, salt);
     return retval;
 }
 
index e03cb27cb0529d410b774f6dbc4f5ce5bab366a4..e5c554f1b500aca486719c33ad03a9b6e12db1b8 100644 (file)
@@ -1501,62 +1501,6 @@ select_session_keytype(krb5_context context, krb5_db_entry *server,
     return 0;
 }
 
-/*
- * This function returns salt information for a particular client_key
- */
-krb5_error_code
-get_salt_from_key(krb5_context context, krb5_principal client,
-                  krb5_key_data *client_key, krb5_data *salt)
-{
-    krb5_error_code             retval;
-    krb5_data *                 realm;
-
-    salt->data = 0;
-    salt->length = SALT_TYPE_NO_LENGTH;
-
-    if (client_key->key_data_ver == 1)
-        return 0;
-
-    switch (client_key->key_data_type[1]) {
-    case KRB5_KDB_SALTTYPE_NORMAL:
-        /*
-         * The client could infer the salt from the principal, but
-         * might use the wrong principal name if this is an alias.  So
-         * it's more reliable to send an explicit salt.
-         */
-        if ((retval = krb5_principal2salt(context, client, salt)))
-            return retval;
-        break;
-    case KRB5_KDB_SALTTYPE_V4:
-        /* send an empty (V4) salt */
-        salt->data = 0;
-        salt->length = 0;
-        break;
-    case KRB5_KDB_SALTTYPE_NOREALM:
-        if ((retval = krb5_principal2salt_norealm(context, client, salt)))
-            return retval;
-        break;
-    case KRB5_KDB_SALTTYPE_AFS3:
-        /* send the same salt as with onlyrealm - but with no type info,
-           we just hope they figure it out on the other end. */
-        /* fall through to onlyrealm: */
-    case KRB5_KDB_SALTTYPE_ONLYREALM:
-        realm = krb5_princ_realm(context, client);
-        salt->length = realm->length;
-        if ((salt->data = malloc(realm->length)) == NULL)
-            return ENOMEM;
-        memcpy(salt->data, realm->data, realm->length);
-        break;
-    case KRB5_KDB_SALTTYPE_SPECIAL:
-        salt->length = client_key->key_data_length[1];
-        if ((salt->data = malloc(salt->length)) == NULL)
-            return ENOMEM;
-        memcpy(salt->data, client_key->key_data_contents[1], salt->length);
-        break;
-    }
-    return 0;
-}
-
 /*
  * Limit strings to a "reasonable" length to prevent crowding out of
  * other useful information in the log entry
index bdeaa5f7db4b77bdf9b4b7b589489aacf46e431d..f4773ae4c4cc533fdd77c3de02f80e9cfcbf2ae9 100644 (file)
@@ -105,10 +105,6 @@ select_session_keytype (krb5_context context,
                         int nktypes,
                         krb5_enctype *ktypes);
 
-krb5_error_code
-get_salt_from_key (krb5_context, krb5_principal,
-                   krb5_key_data *, krb5_data *);
-
 void limit_string (char *name);
 
 void
index a9d0cdb88b7a39e97d464986f71d4fc0ac2a15ce..d50007c52b9905da960cfeb61d483ff5ba2350af 100644 (file)
@@ -725,10 +725,10 @@ kadm5_rename_principal(void *server_handle,
 {
     krb5_db_entry *kdb;
     osa_princ_ent_rec adb;
-    int ret, i;
+    krb5_error_code ret;
     kadm5_server_handle_t handle = server_handle;
-    krb5_int32 stype;
-    krb5_data sdata;
+    krb5_int16 stype, i;
+    krb5_data *salt = NULL;
 
     CHECK_HANDLE(server_handle);
 
@@ -747,52 +747,19 @@ kadm5_rename_principal(void *server_handle,
 
     /* Transform salts as necessary. */
     for (i = 0; i < kdb->n_key_data; i++) {
-        sdata = empty_data();
-        if (kdb->key_data[i].key_data_ver > 1)
-            stype = kdb->key_data[i].key_data_type[1];
-        else
-            stype = KRB5_KDB_SALTTYPE_NORMAL;
-
-        /* For salt types which compute a salt from the principal name, compute
-         * the salt based on the old principal name into sdata. */
-        switch (stype) {
-        case KRB5_KDB_SALTTYPE_NORMAL:
-            ret = krb5_principal2salt(handle->context, kdb->princ, &sdata);
-            if (ret)
-                goto done;
-            break;
-        case KRB5_KDB_SALTTYPE_NOREALM:
-            ret = krb5_principal2salt_norealm(handle->context, kdb->princ,
-                                              &sdata);
-            if (ret)
-                goto done;
-            break;
-        case KRB5_KDB_SALTTYPE_ONLYREALM:
-            ret = alloc_data(&sdata, kdb->princ->realm.length);
-            if (ret)
-                goto done;
-            memcpy(sdata.data, kdb->princ->realm.data,
-                   kdb->princ->realm.length);
-            break;
-        case KRB5_KDB_SALTTYPE_SPECIAL:
-        case KRB5_KDB_SALTTYPE_V4:
-        case KRB5_KDB_SALTTYPE_AFS3:
-            /* Don't compute a new salt.  Assume the realm doesn't change for
-             * V4 and AFS3. */
-            break;
-        default:
-            /* We don't recognize this salt type.  Be conservative. */
+        ret = krb5_dbe_compute_salt(handle->context, &kdb->key_data[i],
+                                    kdb->princ, &stype, &salt);
+        if (ret == KRB5_KDB_BAD_SALTTYPE)
             ret = KADM5_NO_RENAME_SALT;
+        if (ret)
             goto done;
-        }
-        /* If we computed a salt, store it as an explicit salt. */
-        if (sdata.data != NULL) {
-            kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
-            free(kdb->key_data[i].key_data_contents[1]);
-            kdb->key_data[i].key_data_contents[1] = (krb5_octet *)sdata.data;
-            kdb->key_data[i].key_data_length[1] = sdata.length;
-            kdb->key_data[i].key_data_ver = 2;
-        }
+        kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
+        free(kdb->key_data[i].key_data_contents[1]);
+        kdb->key_data[i].key_data_contents[1] = (krb5_octet *)salt->data;
+        kdb->key_data[i].key_data_length[1] = salt->length;
+        kdb->key_data[i].key_data_ver = 2;
+        free(salt);
+        salt = NULL;
     }
 
     kadm5_free_principal(handle->context, kdb->princ);
@@ -808,6 +775,7 @@ kadm5_rename_principal(void *server_handle,
     ret = kdb_delete_entry(handle, source);
 
 done:
+    krb5_free_data(handle->context, salt);
     kdb_free_entry(handle, kdb, &adb);
     return ret;
 }
index 011c83bf380c28ab81887d67be7641f03764e182..380c3d69dfecff1f6fb59372bd604fd28e394431 100644 (file)
@@ -2234,6 +2234,56 @@ krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry,
     return (0);
 }
 
+krb5_error_code
+krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key,
+                      krb5_const_principal princ, krb5_int16 *salttype_out,
+                      krb5_data **salt_out)
+{
+    krb5_error_code retval;
+    krb5_int16 stype;
+    krb5_data *salt, sdata;
+
+    stype = (key->key_data_ver < 2) ? KRB5_KDB_SALTTYPE_NORMAL :
+        key->key_data_type[1];
+    *salttype_out = stype;
+    *salt_out = NULL;
+
+    /* Place computed salt into sdata, or directly into salt_out and return. */
+    switch (stype) {
+    case KRB5_KDB_SALTTYPE_NORMAL:
+        retval = krb5_principal2salt(context, princ, &sdata);
+        if (retval)
+            return retval;
+        break;
+    case KRB5_KDB_SALTTYPE_V4:
+        sdata = empty_data();
+        break;
+    case KRB5_KDB_SALTTYPE_NOREALM:
+        retval = krb5_principal2salt_norealm(context, princ, &sdata);
+        if (retval)
+            return retval;
+        break;
+    case KRB5_KDB_SALTTYPE_AFS3:
+    case KRB5_KDB_SALTTYPE_ONLYREALM:
+        return krb5_copy_data(context, &princ->realm, salt_out);
+    case KRB5_KDB_SALTTYPE_SPECIAL:
+        sdata = make_data(key->key_data_contents[1], key->key_data_length[1]);
+        return krb5_copy_data(context, &sdata, salt_out);
+    default:
+        return KRB5_KDB_BAD_SALTTYPE;
+    }
+
+    /* Make a container for sdata. */
+    salt = malloc(sizeof(*salt));
+    if (salt == NULL) {
+        free(sdata.data);
+        return ENOMEM;
+    }
+    *salt = sdata;
+    *salt_out = salt;
+    return 0;
+}
+
 /* change password functions */
 krb5_error_code
 krb5_dbe_cpw(krb5_context kcontext, krb5_keyblock *master_key,
index 3ea179a46f98d204e3a87b85ab24a6f4fc748d15..e32b7a1d2cfa78d84d3e5ae96e797d728762c122 100644 (file)
@@ -48,6 +48,7 @@ krb5_dbe_free_strings
 krb5_dbe_get_mkvno
 krb5_dbe_get_string
 krb5_dbe_get_strings
+krb5_dbe_compute_salt
 krb5_dbe_lookup_last_admin_unlock
 krb5_dbe_lookup_last_pwd_change
 krb5_dbe_lookup_actkvno