aboutsummaryrefslogtreecommitdiff
path: root/src/kdc/kdc_preauth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kdc/kdc_preauth.c')
-rw-r--r--src/kdc/kdc_preauth.c282
1 files changed, 240 insertions, 42 deletions
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index 4747f27..342f050 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -59,6 +59,8 @@
#include "adm_proto.h"
#include <syslog.h>
+#include <assert.h>
+
/* XXX This is ugly and should be in a header file somewhere */
#ifndef KRB5INT_DES_TYPES_DEFINED
#define KRB5INT_DES_TYPES_DEFINED
@@ -104,6 +106,18 @@ static krb5_error_code get_etype_info
(krb5_context, krb5_kdc_req *request,
krb5_db_entry *client, krb5_db_entry *server,
krb5_pa_data *data);
+static krb5_error_code
+get_etype_info2(krb5_context context, krb5_kdc_req *request,
+ krb5_db_entry *client, krb5_db_entry *server,
+ krb5_pa_data *pa_data);
+static krb5_error_code
+return_etype_info2(krb5_context, krb5_pa_data * padata,
+ krb5_db_entry *client,
+ krb5_kdc_req *request, krb5_kdc_rep *reply,
+ krb5_key_data *client_key,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **send_pa);
+
static krb5_error_code return_pw_salt
(krb5_context, krb5_pa_data * padata,
krb5_db_entry *client,
@@ -156,6 +170,14 @@ static krb5_preauth_systems preauth_systems[] = {
0
},
{
+ "etype-info2",
+ KRB5_PADATA_ETYPE_INFO2,
+ 0,
+ get_etype_info2,
+ 0,
+ return_etype_info2
+ },
+ {
"pw-salt",
KRB5_PADATA_PW_SALT,
PA_PSEUDO, /* Don't include this in the error list */
@@ -362,6 +384,7 @@ check_padata (krb5_context context, krb5_db_entry *client,
* to return some preauth system errors back to the client.
*/
switch(retval) {
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
case KRB5KRB_AP_ERR_SKEW:
return retval;
default:
@@ -432,6 +455,26 @@ cleanup:
}
static krb5_boolean
+enctype_requires_etype_info_2(krb5_enctype enctype)
+{
+ switch(enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES3_CBC_SHA1:
+ case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP :
+ case ENCTYPE_LOCAL_DES3_HMAC_SHA1:
+ return 0;
+ default:
+ if (krb5_c_valid_enctype(enctype))
+ return 1;
+ else return 0;
+ }
+}
+
+static krb5_boolean
request_contains_enctype (krb5_context context, const krb5_kdc_req *request,
krb5_enctype enctype)
{
@@ -457,7 +500,8 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
krb5_key_data * client_key;
krb5_int32 start;
krb5_timestamp timenow;
-
+ krb5_error_code decrypt_err;
+
scratch.data = pa->contents;
scratch.length = pa->length;
@@ -471,6 +515,7 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
goto cleanup;
start = 0;
+ decrypt_err = 0;
while (1) {
if ((retval = krb5_dbe_search_enctype(context, client,
&start, enc_data->enctype,
@@ -488,6 +533,8 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
krb5_free_keyblock_contents(context, &key);
if (retval == 0)
break;
+ else
+ decrypt_err = retval;
}
if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0)
@@ -513,29 +560,98 @@ cleanup:
krb5_free_data_contents(context, &enc_ts_data);
if (pa_enc)
free(pa_enc);
+ /*
+ * If we get NO_MATCHING_KEY and decryption previously failed, and
+ * we failed to find any other keys of the correct enctype after
+ * that failed decryption, it probably means that the password was
+ * incorrect.
+ */
+ if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0)
+ retval = decrypt_err;
return retval;
}
+static krb5_error_code
+_make_etype_info_entry(krb5_context context,
+ krb5_kdc_req *request, krb5_key_data *client_key,
+ krb5_enctype etype, krb5_etype_info_entry **entry,
+ int etype_info2)
+{
+ krb5_data salt;
+ krb5_etype_info_entry * tmp_entry;
+ krb5_error_code retval;
+
+ if ((tmp_entry = malloc(sizeof(krb5_etype_info_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, request->client,
+ client_key, &salt);
+ if (retval)
+ goto fail;
+ if (etype_info2 && client_key->key_data_ver > 1 &&
+ client_key->key_data_type[1] == 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;
+ 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;
+
+fail:
+ if (tmp_entry) {
+ if (tmp_entry->s2kparams.data)
+ free(tmp_entry->s2kparams.data);
+ free(tmp_entry);
+ }
+ if (salt.data)
+ free(salt.data);
+ return retval;
+}
/*
* This function returns the etype information for a particular
* client, to be passed back in the preauth list in the KRB_ERROR
- * message.
+ * message. It supports generating both etype_info and etype_info2
+ * as most of the work is the same.
*/
static krb5_error_code
-get_etype_info(krb5_context context, krb5_kdc_req *request,
+etype_info_helper(krb5_context context, krb5_kdc_req *request,
krb5_db_entry *client, krb5_db_entry *server,
- krb5_pa_data *pa_data)
+ krb5_pa_data *pa_data, int etype_info2)
{
krb5_etype_info_entry ** entry = 0;
krb5_key_data *client_key;
krb5_error_code retval;
- krb5_data salt;
krb5_data * scratch;
krb5_enctype db_etype;
int i = 0;
int start = 0;
-
- salt.data = 0;
+ int seen_des = 0;
entry = malloc((client->n_key_data * 2 + 1) * sizeof(krb5_etype_info_entry *));
if (entry == NULL)
@@ -550,51 +666,55 @@ get_etype_info(krb5_context context, krb5_kdc_req *request,
if (retval)
goto cleanup;
db_etype = client_key->key_data_type[0];
- if (db_etype == ENCTYPE_DES_CBC_MD4 || db_etype == ENCTYPE_DES_CBC_MD5)
- db_etype = ENCTYPE_DES_CBC_CRC;
+ if (db_etype == ENCTYPE_DES_CBC_MD4)
+ db_etype = ENCTYPE_DES_CBC_MD5;
- while (1) {
- if (!request_contains_enctype(context,
- request, db_etype)) {
- if (db_etype == ENCTYPE_DES_CBC_CRC)
- continue;
- else break;
- }
-
- if ((entry[i] = malloc(sizeof(krb5_etype_info_entry))) == NULL) {
- retval = ENOMEM;
+ if (request_contains_enctype(context, request, db_etype)) {
+ assert(etype_info2 ||
+ !enctype_requires_etype_info_2(db_etype));
+ if ((retval = _make_etype_info_entry(context, request, client_key,
+ db_etype, &entry[i], etype_info2)) != 0) {
goto cleanup;
}
entry[i+1] = 0;
- entry[i]->magic = KV5M_ETYPE_INFO_ENTRY;
- entry[i]->etype = db_etype;
- entry[i]->length = KRB5_ETYPE_NO_SALT;
- entry[i]->salt = 0;
- retval = get_salt_from_key(context, request->client,
- client_key, &salt);
- if (retval)
- goto cleanup;
- if (salt.length >= 0 && salt.length != SALT_TYPE_NO_LENGTH) {
- entry[i]->length = salt.length;
- entry[i]->salt = salt.data;
- salt.data = 0;
- }
i++;
- /*
- * If we have a DES_CRC key, it can also be used as a
- * DES_MD5 key.
- */
- if (db_etype == ENCTYPE_DES_CBC_CRC)
+ }
+
+ /*
+ * If there is a des key in the kdb, try the "similar" enctypes,
+ * avoid duplicate entries.
+ */
+ if (!seen_des) {
+ switch (db_etype) {
+ case ENCTYPE_DES_CBC_MD5:
+ db_etype = ENCTYPE_DES_CBC_CRC;
+ break;
+ case ENCTYPE_DES_CBC_CRC:
db_etype = ENCTYPE_DES_CBC_MD5;
- else
break;
+ default:
+ continue;
+
+ }
+ if (request_contains_enctype(context, request, db_etype)) {
+ if ((retval = _make_etype_info_entry(context, request,
+ client_key, db_etype, &entry[i], etype_info2)) != 0) {
+ goto cleanup;
+ }
+ entry[i+1] = 0;
+ i++;
+ }
+ seen_des++;
}
}
- retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry,
+ if (etype_info2)
+ retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry,
+ &scratch);
+ else retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry,
&scratch);
if (retval)
goto cleanup;
- pa_data->contents = scratch->data;
+ pa_data->contents = (unsigned char *)scratch->data;
pa_data->length = scratch->length;
free(scratch);
@@ -603,12 +723,85 @@ get_etype_info(krb5_context context, krb5_kdc_req *request,
cleanup:
if (entry)
krb5_free_etype_info(context, entry);
- if (salt.data)
- free(salt.data);
return retval;
}
static krb5_error_code
+get_etype_info(krb5_context context, krb5_kdc_req *request,
+ krb5_db_entry *client, krb5_db_entry *server,
+ krb5_pa_data *pa_data)
+{
+ int i;
+ for (i=0; i < request->nktypes; i++) {
+ if (enctype_requires_etype_info_2(request->ktype[i]))
+ return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will
+ * skip this
+ * type*/
+ }
+ return etype_info_helper(context, request, client, server, pa_data, 0);
+}
+
+static krb5_error_code
+get_etype_info2(krb5_context context, krb5_kdc_req *request,
+ krb5_db_entry *client, krb5_db_entry *server,
+ krb5_pa_data *pa_data)
+{
+ return etype_info_helper( context, request, client, server, pa_data, 1);
+}
+
+static krb5_error_code
+return_etype_info2(krb5_context context, krb5_pa_data * padata,
+ krb5_db_entry *client,
+ krb5_kdc_req *request, krb5_kdc_rep *reply,
+ krb5_key_data *client_key,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **send_pa)
+{
+ krb5_error_code retval;
+ krb5_pa_data *tmp_padata;
+ krb5_etype_info_entry **entry = NULL;
+ krb5_data *scratch = NULL;
+ tmp_padata = malloc( sizeof(krb5_pa_data));
+ if (tmp_padata == NULL)
+ return ENOMEM;
+ tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2;
+ entry = malloc(2 * sizeof(krb5_etype_info_entry *));
+ if (entry == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ entry[0] = NULL;
+ entry[1] = NULL;
+ retval = _make_etype_info_entry(context, request, client_key, client_key->key_data_type[0],
+ entry, 1);
+ if (retval)
+ goto cleanup;
+ retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, &scratch);
+ if (retval)
+ goto cleanup;
+ tmp_padata->contents = scratch->data;
+ tmp_padata->length = scratch->length;
+ *send_pa = tmp_padata;
+
+ /* For cleanup - we no longer own the contents of the krb5_data
+ * only to pointer to the krb5_data
+ */
+ scratch->data = 0;
+
+ cleanup:
+ if (entry)
+ krb5_free_etype_info(context, entry);
+ if (retval) {
+ if (tmp_padata)
+ free(tmp_padata);
+ }
+ if (scratch)
+ krb5_free_data(context, scratch);
+ return retval;
+}
+
+
+static krb5_error_code
return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
krb5_db_entry *client, krb5_kdc_req *request,
krb5_kdc_rep *reply, krb5_key_data *client_key,
@@ -618,7 +811,12 @@ return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
krb5_pa_data * padata;
krb5_data * scratch;
krb5_data salt_data;
+ int i;
+ for (i = 0; i < request->nktypes; i++) {
+ 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)
return 0;