mirror of
https://github.com/samba-team/samba.git
synced 2025-03-12 20:58:37 +03:00
s4:kdc: split out samba_kdc_fill_trust_keys() helper
This simplifies the logic in samba_kdc_trust_message2entry(), is very similar to our samba_kdc_fill_user_keys() helper and will make it trivial to provide the previous keys in entry->old_keys in the next commit. Review with: git show -p --patience Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
f5c8c212dc
commit
6ecc607ede
@ -1811,6 +1811,257 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct samba_kdc_trust_keys {
|
||||
struct sdb_keys *skeys;
|
||||
uint32_t kvno;
|
||||
uint32_t *returned_kvno;
|
||||
uint32_t supported_enctypes;
|
||||
uint32_t *available_enctypes;
|
||||
krb5_const_principal salt_principal;
|
||||
const struct AuthenticationInformationArray *auth_array;
|
||||
};
|
||||
|
||||
static krb5_error_code samba_kdc_fill_trust_keys(krb5_context context,
|
||||
struct samba_kdc_trust_keys *p)
|
||||
{
|
||||
/*
|
||||
* Make sure we'll never reveal DES keys
|
||||
*/
|
||||
uint32_t supported_enctypes = p->supported_enctypes &= ~(ENC_CRC32 | ENC_RSA_MD5);
|
||||
uint32_t _available_enctypes = 0;
|
||||
uint32_t *available_enctypes = p->available_enctypes;
|
||||
uint32_t _returned_kvno = 0;
|
||||
uint32_t *returned_kvno = p->returned_kvno;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
const struct AuthenticationInformationArray *aa = p->auth_array;
|
||||
DATA_BLOB password_utf16 = { .length = 0, };
|
||||
DATA_BLOB password_utf8 = { .length = 0, };
|
||||
struct samr_Password _password_hash = { .hash = { 0,}, };
|
||||
const struct samr_Password *password_hash = NULL;
|
||||
uint32_t allocated_keys = 0;
|
||||
uint32_t i;
|
||||
int ret;
|
||||
|
||||
if (available_enctypes == NULL) {
|
||||
available_enctypes = &_available_enctypes;
|
||||
}
|
||||
|
||||
*available_enctypes = 0;
|
||||
|
||||
if (returned_kvno == NULL) {
|
||||
returned_kvno = &_returned_kvno;
|
||||
}
|
||||
|
||||
*returned_kvno = p->kvno;
|
||||
|
||||
for (i=0; i < aa->count; i++) {
|
||||
if (aa->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
|
||||
const struct AuthInfoClear *clear =
|
||||
&aa->array[i].AuthInfo.clear;
|
||||
bool ok;
|
||||
|
||||
password_utf16 = data_blob_const(clear->password,
|
||||
clear->size);
|
||||
if (password_utf16.length == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_RC4_HMAC_MD5) {
|
||||
mdfour(_password_hash.hash,
|
||||
password_utf16.data,
|
||||
password_utf16.length);
|
||||
if (password_hash == NULL) {
|
||||
allocated_keys += 1;
|
||||
}
|
||||
password_hash = &_password_hash;
|
||||
}
|
||||
|
||||
if (!(supported_enctypes & (ENC_HMAC_SHA1_96_AES128|ENC_HMAC_SHA1_96_AES256))) {
|
||||
break;
|
||||
}
|
||||
|
||||
ok = convert_string_talloc(frame,
|
||||
CH_UTF16MUNGED, CH_UTF8,
|
||||
password_utf16.data,
|
||||
password_utf16.length,
|
||||
&password_utf8.data,
|
||||
&password_utf8.length);
|
||||
if (!ok) {
|
||||
krb5_clear_error_message(context);
|
||||
ret = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
|
||||
allocated_keys += 1;
|
||||
}
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
|
||||
allocated_keys += 1;
|
||||
}
|
||||
break;
|
||||
} else if (aa->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
|
||||
const struct AuthInfoNT4Owf *nt4owf =
|
||||
&aa->array[i].AuthInfo.nt4owf;
|
||||
|
||||
if (supported_enctypes & ENC_RC4_HMAC_MD5) {
|
||||
password_hash = &nt4owf->password;
|
||||
allocated_keys += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allocated_keys = MAX(1, allocated_keys);
|
||||
|
||||
/* allocate space to decode into */
|
||||
p->skeys->len = 0;
|
||||
p->skeys->val = calloc(allocated_keys, sizeof(struct sdb_key));
|
||||
if (p->skeys->val == NULL) {
|
||||
krb5_clear_error_message(context);
|
||||
ret = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (password_utf8.length != 0) {
|
||||
struct sdb_key key = {};
|
||||
krb5_data salt;
|
||||
krb5_data cleartext_data;
|
||||
|
||||
cleartext_data.data = discard_const_p(char, password_utf8.data);
|
||||
cleartext_data.length = password_utf8.length;
|
||||
|
||||
ret = smb_krb5_get_pw_salt(context,
|
||||
p->salt_principal,
|
||||
&salt);
|
||||
if (ret != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
|
||||
key.salt = calloc(1, sizeof(*key.salt));
|
||||
if (key.salt == NULL) {
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
ret = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key.salt->type = KRB5_PW_SALT;
|
||||
|
||||
ret = smb_krb5_copy_data_contents(&key.salt->salt,
|
||||
salt.data,
|
||||
salt.length);
|
||||
if (ret) {
|
||||
*key.salt = (struct sdb_salt) {};
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = smb_krb5_create_key_from_string(context,
|
||||
p->salt_principal,
|
||||
&salt,
|
||||
&cleartext_data,
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
&key.key);
|
||||
if (ret == 0) {
|
||||
p->skeys->val[p->skeys->len++] = key;
|
||||
*available_enctypes |= ENC_HMAC_SHA1_96_AES256;
|
||||
} else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
|
||||
DBG_NOTICE("Unsupported keytype ignored - type %u\n",
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96);
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
|
||||
key.salt = calloc(1, sizeof(*key.salt));
|
||||
if (key.salt == NULL) {
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
ret = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key.salt->type = KRB5_PW_SALT;
|
||||
|
||||
ret = smb_krb5_copy_data_contents(&key.salt->salt,
|
||||
salt.data,
|
||||
salt.length);
|
||||
if (ret) {
|
||||
*key.salt = (struct sdb_salt) {};
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = smb_krb5_create_key_from_string(context,
|
||||
p->salt_principal,
|
||||
&salt,
|
||||
&cleartext_data,
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
&key.key);
|
||||
if (ret == 0) {
|
||||
p->skeys->val[p->skeys->len++] = key;
|
||||
*available_enctypes |= ENC_HMAC_SHA1_96_AES128;
|
||||
} else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
|
||||
DBG_NOTICE("Unsupported keytype ignored - type %u\n",
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96);
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
}
|
||||
|
||||
if (password_hash != NULL) {
|
||||
struct sdb_key key = {};
|
||||
|
||||
ret = smb_krb5_keyblock_init_contents(context,
|
||||
ENCTYPE_ARCFOUR_HMAC,
|
||||
password_hash->hash,
|
||||
sizeof(password_hash->hash),
|
||||
&key.key);
|
||||
if (ret == 0) {
|
||||
p->skeys->val[p->skeys->len++] = key;
|
||||
|
||||
*available_enctypes |= ENC_RC4_HMAC_MD5;
|
||||
} else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
|
||||
DEBUG(2,("Unsupported keytype ignored - type %u\n",
|
||||
ENCTYPE_ARCFOUR_HMAC));
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
samba_kdc_sort_keys(p->skeys);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
sdb_keys_free(p->skeys);
|
||||
TALLOC_FREE(frame);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct an hdb_entry from a directory entry.
|
||||
* The kvno is what the remote client asked for
|
||||
@ -1831,24 +2082,19 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
|
||||
char *partner_realm = NULL;
|
||||
const char *realm = NULL;
|
||||
const char *krbtgt_realm = NULL;
|
||||
DATA_BLOB password_utf16 = data_blob_null;
|
||||
DATA_BLOB password_utf8 = data_blob_null;
|
||||
struct samr_Password _password_hash;
|
||||
const struct samr_Password *password_hash = NULL;
|
||||
const struct ldb_val *password_val;
|
||||
struct trustAuthInOutBlob password_blob;
|
||||
struct samba_kdc_entry *p;
|
||||
bool use_previous = false;
|
||||
uint32_t current_kvno;
|
||||
uint32_t previous_kvno;
|
||||
uint32_t num_keys = 0;
|
||||
struct samba_kdc_trust_keys current_keys = {};
|
||||
struct samba_kdc_trust_keys previous_keys = {};
|
||||
enum ndr_err_code ndr_err;
|
||||
int ret;
|
||||
unsigned int i;
|
||||
struct AuthenticationInformationArray *auth_array;
|
||||
struct timeval tv;
|
||||
NTTIME an_hour_ago;
|
||||
uint32_t *auth_kvno;
|
||||
bool prefer_current = false;
|
||||
bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
|
||||
uint32_t supported_enctypes = ENC_RC4_HMAC_MD5;
|
||||
@ -2085,217 +2331,65 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
|
||||
use_previous = false;
|
||||
}
|
||||
|
||||
current_keys = (struct samba_kdc_trust_keys) {
|
||||
.kvno = current_kvno,
|
||||
.supported_enctypes = supported_enctypes,
|
||||
.salt_principal = entry->principal,
|
||||
.auth_array = &password_blob.current,
|
||||
};
|
||||
|
||||
previous_keys = (struct samba_kdc_trust_keys) {
|
||||
.kvno = previous_kvno,
|
||||
.supported_enctypes = supported_enctypes,
|
||||
.salt_principal = entry->principal,
|
||||
.auth_array = &password_blob.previous,
|
||||
};
|
||||
|
||||
if (use_previous) {
|
||||
auth_array = &password_blob.previous;
|
||||
auth_kvno = &previous_kvno;
|
||||
/*
|
||||
* return the old keys as default keys
|
||||
* with the requested kvno.
|
||||
*/
|
||||
previous_keys.skeys = &entry->keys;
|
||||
previous_keys.available_enctypes = &available_enctypes;
|
||||
previous_keys.returned_kvno = &returned_kvno;
|
||||
} else {
|
||||
auth_array = &password_blob.current;
|
||||
auth_kvno = ¤t_kvno;
|
||||
/*
|
||||
* return the current keys as default keys
|
||||
* with the requested kvno.
|
||||
*/
|
||||
current_keys.skeys = &entry->keys;
|
||||
current_keys.available_enctypes = &available_enctypes;
|
||||
current_keys.returned_kvno = &returned_kvno;
|
||||
}
|
||||
|
||||
if (current_keys.skeys != NULL) {
|
||||
ret = samba_kdc_fill_trust_keys(context, ¤t_keys);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous_keys.skeys != NULL) {
|
||||
ret = samba_kdc_fill_trust_keys(context, &previous_keys);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* use the kvno the client specified, if available */
|
||||
if (flags & SDB_F_KVNO_SPECIFIED) {
|
||||
returned_kvno = kvno;
|
||||
} else {
|
||||
returned_kvno = *auth_kvno;
|
||||
}
|
||||
|
||||
for (i=0; i < auth_array->count; i++) {
|
||||
if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
|
||||
bool ok;
|
||||
|
||||
password_utf16 = data_blob_const(auth_array->array[i].AuthInfo.clear.password,
|
||||
auth_array->array[i].AuthInfo.clear.size);
|
||||
if (password_utf16.length == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_RC4_HMAC_MD5) {
|
||||
mdfour(_password_hash.hash, password_utf16.data, password_utf16.length);
|
||||
if (password_hash == NULL) {
|
||||
num_keys += 1;
|
||||
}
|
||||
password_hash = &_password_hash;
|
||||
}
|
||||
|
||||
if (!(supported_enctypes & (ENC_HMAC_SHA1_96_AES128|ENC_HMAC_SHA1_96_AES256))) {
|
||||
break;
|
||||
}
|
||||
|
||||
ok = convert_string_talloc(tmp_ctx,
|
||||
CH_UTF16MUNGED, CH_UTF8,
|
||||
password_utf16.data,
|
||||
password_utf16.length,
|
||||
&password_utf8.data,
|
||||
&password_utf8.length);
|
||||
if (!ok) {
|
||||
krb5_clear_error_message(context);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
|
||||
num_keys += 1;
|
||||
}
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
|
||||
num_keys += 1;
|
||||
}
|
||||
break;
|
||||
} else if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
|
||||
if (supported_enctypes & ENC_RC4_HMAC_MD5) {
|
||||
password_hash = &auth_array->array[i].AuthInfo.nt4owf.password;
|
||||
num_keys += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Must have found a cleartext or MD4 password */
|
||||
if (num_keys == 0) {
|
||||
if (entry->keys.len == 0) {
|
||||
DBG_WARNING("no usable key found\n");
|
||||
krb5_clear_error_message(context);
|
||||
ret = SDB_ERR_NOENTRY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry->keys.val = calloc(num_keys, sizeof(struct sdb_key));
|
||||
if (entry->keys.val == NULL) {
|
||||
krb5_clear_error_message(context);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (password_utf8.length != 0) {
|
||||
struct sdb_key key = {};
|
||||
krb5_const_principal salt_principal = entry->principal;
|
||||
krb5_data salt;
|
||||
krb5_data cleartext_data;
|
||||
|
||||
cleartext_data.data = discard_const_p(char, password_utf8.data);
|
||||
cleartext_data.length = password_utf8.length;
|
||||
|
||||
ret = smb_krb5_get_pw_salt(context,
|
||||
salt_principal,
|
||||
&salt);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
|
||||
key.salt = calloc(1, sizeof(*key.salt));
|
||||
if (key.salt == NULL) {
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
key.salt->type = KRB5_PW_SALT;
|
||||
|
||||
ret = smb_krb5_copy_data_contents(&key.salt->salt,
|
||||
salt.data,
|
||||
salt.length);
|
||||
if (ret) {
|
||||
*key.salt = (struct sdb_salt) {};
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = smb_krb5_create_key_from_string(context,
|
||||
salt_principal,
|
||||
&salt,
|
||||
&cleartext_data,
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
&key.key);
|
||||
if (ret == 0) {
|
||||
entry->keys.val[entry->keys.len++] = key;
|
||||
available_enctypes |= ENC_HMAC_SHA1_96_AES256;
|
||||
} else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
|
||||
DBG_NOTICE("Unsupported keytype ignored - type %u\n",
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96);
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
|
||||
key.salt = calloc(1, sizeof(*key.salt));
|
||||
if (key.salt == NULL) {
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
key.salt->type = KRB5_PW_SALT;
|
||||
|
||||
ret = smb_krb5_copy_data_contents(&key.salt->salt,
|
||||
salt.data,
|
||||
salt.length);
|
||||
if (ret) {
|
||||
*key.salt = (struct sdb_salt) {};
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = smb_krb5_create_key_from_string(context,
|
||||
salt_principal,
|
||||
&salt,
|
||||
&cleartext_data,
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
&key.key);
|
||||
if (ret == 0) {
|
||||
entry->keys.val[entry->keys.len++] = key;
|
||||
available_enctypes |= ENC_HMAC_SHA1_96_AES128;
|
||||
} else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
|
||||
DBG_NOTICE("Unsupported keytype ignored - type %u\n",
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96);
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
smb_krb5_free_data_contents(context, &salt);
|
||||
}
|
||||
|
||||
if (password_hash != NULL) {
|
||||
struct sdb_key key = {};
|
||||
|
||||
ret = smb_krb5_keyblock_init_contents(context,
|
||||
ENCTYPE_ARCFOUR_HMAC,
|
||||
password_hash->hash,
|
||||
sizeof(password_hash->hash),
|
||||
&key.key);
|
||||
if (ret == 0) {
|
||||
entry->keys.val[entry->keys.len++] = key;
|
||||
available_enctypes |= ENC_RC4_HMAC_MD5;
|
||||
} else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
|
||||
DBG_NOTICE("Unsupported keytype ignored - type %u\n",
|
||||
ENCTYPE_ARCFOUR_HMAC);
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ZERO_STRUCT(key.key);
|
||||
sdb_key_free(&key);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
entry->flags = (struct SDBFlags) {};
|
||||
entry->flags.immutable = 1;
|
||||
entry->flags.invalid = 0;
|
||||
@ -2311,8 +2405,6 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
|
||||
/* Match Windows behavior and allow forwardable flag in cross-realm. */
|
||||
entry->flags.forwardable = 1;
|
||||
|
||||
samba_kdc_sort_keys(&entry->keys);
|
||||
|
||||
entry->kvno = returned_kvno;
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user