diff options
author | Stefan Metzmacher <metze@samba.org> | 2008-07-23 09:35:19 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2008-07-23 14:46:11 +0200 |
commit | 34b10077f9ca742b72ad37c86357d0f16ed68ee7 (patch) | |
tree | a3602669d29dca81dd578e1c33fea7c99bd4a9c4 | |
parent | 0842eb25a196ae9551fd93c25cbd3901df3ec537 (diff) | |
download | samba-34b10077f9ca742b72ad37c86357d0f16ed68ee7.tar.gz samba-34b10077f9ca742b72ad37c86357d0f16ed68ee7.tar.bz2 samba-34b10077f9ca742b72ad37c86357d0f16ed68ee7.zip |
password_hash: add generation of the Primary:Kerberos-Newer-Keys blob
But it's still of by default until we now what triggers this generation.
It could be that the value is always generated but the KDC only
uses it when in a specific funtional level, but it could also
be that it's only generated in a specific functional level.
metze
(This used to be commit 08618bbd508ede0bb9e1922fae562cffdca41cbd)
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/password_hash.c | 219 |
1 files changed, 216 insertions, 3 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 8d63aed0f5..413ec12479 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -141,6 +141,8 @@ struct setup_password_fields_io { uint32_t lm_history_len; struct samr_Password *lm_history; const char *salt; + DATA_BLOB aes_256; + DATA_BLOB aes_128; DATA_BLOB des_md5; DATA_BLOB des_crc; struct ldb_val supplemental; @@ -316,6 +318,56 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io) salt.saltvalue.length = strlen(io->g.salt); /* + * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of + * the salt and the cleartext password + */ + krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context, + ENCTYPE_AES256_CTS_HMAC_SHA1_96, + io->n.cleartext, + salt, + &key); + if (krb5_ret) { + ldb_asprintf_errstring(io->ac->module->ldb, + "setup_kerberos_keys: " + "generation of a aes256-cts-hmac-sha1-96 key failed: %s", + smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac)); + return LDB_ERR_OPERATIONS_ERROR; + } + io->g.aes_256 = data_blob_talloc(io->ac, + key.keyvalue.data, + key.keyvalue.length); + krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); + if (!io->g.aes_256.data) { + ldb_oom(io->ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* + * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of + * the salt and the cleartext password + */ + krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, + io->n.cleartext, + salt, + &key); + if (krb5_ret) { + ldb_asprintf_errstring(io->ac->module->ldb, + "setup_kerberos_keys: " + "generation of a aes128-cts-hmac-sha1-96 key failed: %s", + smb_get_krb5_error_message(io->smb_krb5_context->krb5_context, krb5_ret, io->ac)); + return LDB_ERR_OPERATIONS_ERROR; + } + io->g.aes_128 = data_blob_talloc(io->ac, + key.keyvalue.data, + key.keyvalue.length); + krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key); + if (!io->g.aes_128.data) { + ldb_oom(io->ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* * create ENCTYPE_DES_CBC_MD5 key out of * the salt and the cleartext password */ @@ -467,6 +519,117 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io, return LDB_SUCCESS; } +static int setup_primary_kerberos_newer(struct setup_password_fields_io *io, + const struct supplementalCredentialsBlob *old_scb, + struct package_PrimaryKerberosNewerBlob *pkb) +{ + struct package_PrimaryKerberosNewerCtr4 *pkb4 = &pkb->ctr.ctr4; + struct supplementalCredentialsPackage *old_scp = NULL; + struct package_PrimaryKerberosNewerBlob _old_pkb; + struct package_PrimaryKerberosNewerCtr4 *old_pkb4 = NULL; + uint32_t i; + enum ndr_err_code ndr_err; + + /* + * prepare generation of keys + * + * ENCTYPE_AES256_CTS_HMAC_SHA1_96 + * ENCTYPE_AES128_CTS_HMAC_SHA1_96 + * ENCTYPE_DES_CBC_MD5 + * ENCTYPE_DES_CBC_CRC + */ + pkb4->salt.string = io->g.salt; + pkb4->num_keys = 4; + pkb4->keys = talloc_array(io->ac, + struct package_PrimaryKerberosNewerKey, + pkb4->num_keys); + if (!pkb4->keys) { + ldb_oom(io->ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96; + pkb4->keys[0].value = &io->g.aes_256; + pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96; + pkb4->keys[1].value = &io->g.aes_128; + pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5; + pkb4->keys[2].value = &io->g.des_md5; + pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC; + pkb4->keys[3].value = &io->g.des_crc; + + /* initialize the old keys to zero */ + pkb4->num_old_keys1 = 0; + pkb4->old_keys1 = NULL; + pkb4->num_old_keys2 = 0; + pkb4->old_keys2 = NULL; + + /* if there're no old keys, then we're done */ + if (!old_scb) { + return LDB_SUCCESS; + } + + for (i=0; i < old_scb->sub.num_packages; i++) { + if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) { + continue; + } + + if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) { + continue; + } + + old_scp = &old_scb->sub.packages[i]; + break; + } + /* Primary:Kerberos element of supplementalCredentials */ + if (old_scp) { + DATA_BLOB blob; + + blob = strhex_to_data_blob(old_scp->data); + if (!blob.data) { + ldb_oom(io->ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + talloc_steal(io->ac, blob.data); + + /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */ + ndr_err = ndr_pull_struct_blob(&blob, io->ac, + lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), + &_old_pkb, + (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosNewerBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + ldb_asprintf_errstring(io->ac->module->ldb, + "setup_primary_kerberos_newer: " + "failed to pull old package_PrimaryKerberosNewerBlob: %s", + nt_errstr(status)); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (_old_pkb.version != 4) { + ldb_asprintf_errstring(io->ac->module->ldb, + "setup_primary_kerberos: " + "package_PrimaryKerberosNewerBlob version[%u] expected[4]", + _old_pkb.version); + return LDB_ERR_OPERATIONS_ERROR; + } + + old_pkb4 = &_old_pkb.ctr.ctr4; + } + + /* if we didn't found the old keys we're done */ + if (!old_pkb4) { + return LDB_SUCCESS; + } + + /* fill in the old keys */ + pkb4->num_old_keys1 = old_pkb4->num_keys; + pkb4->old_keys1 = old_pkb4->keys; + pkb4->num_old_keys2 = old_pkb4->num_old_keys1; + pkb4->old_keys2 = old_pkb4->old_keys1; + + return LDB_SUCCESS; +} + static int setup_primary_wdigest(struct setup_password_fields_io *io, const struct supplementalCredentialsBlob *old_scb, struct package_PrimaryWDigestBlob *pdb) @@ -804,16 +967,22 @@ static int setup_supplemental_field(struct setup_password_fields_io *io) struct supplementalCredentialsBlob scb; struct supplementalCredentialsBlob _old_scb; struct supplementalCredentialsBlob *old_scb = NULL; - /* Packages + (Kerberos, WDigest and CLEARTEXT) */ + /* Packages + (Kerberos-Newer-Keys, Kerberos, WDigest and CLEARTEXT) */ uint32_t num_names = 0; - const char *names[1+3]; + const char *names[1+4]; uint32_t num_packages = 0; - struct supplementalCredentialsPackage packages[1+3]; + struct supplementalCredentialsPackage packages[1+4]; /* Packages */ struct supplementalCredentialsPackage *pp = NULL; struct package_PackagesBlob pb; DATA_BLOB pb_blob; char *pb_hexstr; + /* Primary:Kerberos-Newer-Keys */ + const char **nkn = NULL; + struct supplementalCredentialsPackage *pkn = NULL; + struct package_PrimaryKerberosNewerBlob pknb; + DATA_BLOB pknb_blob; + char *pknb_hexstr; /* Primary:Kerberos */ const char **nk = NULL; struct supplementalCredentialsPackage *pk = NULL; @@ -835,6 +1004,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io) int ret; enum ndr_err_code ndr_err; uint8_t zero16[16]; + bool do_newer_keys = false; bool do_cleartext = false; ZERO_STRUCT(zero16); @@ -873,6 +1043,10 @@ static int setup_supplemental_field(struct setup_password_fields_io *io) } } + /* TODO: do the correct check for this, it maybe depends on the functional level? */ + do_newer_keys = lp_parm_bool(ldb_get_opaque(io->ac->module->ldb, "loadparm"), + NULL, "password_hash", "create_aes_key", false); + if (io->domain->store_cleartext && (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) { do_cleartext = true; @@ -881,6 +1055,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io) /* * The ordering is this * + * Primary:Kerberos-Newer-Keys (optional) * Primary:Kerberos * Primary:WDigest * Primary:CLEARTEXT (optional) @@ -888,6 +1063,11 @@ static int setup_supplemental_field(struct setup_password_fields_io *io) * And the 'Packages' package is insert before the last * other package. */ + if (do_newer_keys) { + /* Primary:Kerberos-Newer-Keys */ + nkn = &names[num_names++]; + pkn = &packages[num_packages++]; + } /* Primary:Kerberos */ nk = &names[num_names++]; @@ -911,6 +1091,39 @@ static int setup_supplemental_field(struct setup_password_fields_io *io) pc = &packages[num_packages++]; } + if (pkn) { + /* + * setup 'Primary:Kerberos-Newer-Keys' element + */ + *nkn = "Kerberos-Newer-Keys"; + + ret = setup_primary_kerberos_newer(io, old_scb, &pknb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ndr_err = ndr_push_struct_blob(&pknb_blob, io->ac, + lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), + &pknb, + (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosNewerBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + ldb_asprintf_errstring(io->ac->module->ldb, + "setup_supplemental_field: " + "failed to push package_PrimaryKerberosNeverBlob: %s", + nt_errstr(status)); + return LDB_ERR_OPERATIONS_ERROR; + } + pknb_hexstr = data_blob_hex_string(io->ac, &pknb_blob); + if (!pknb_hexstr) { + ldb_oom(io->ac->module->ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + pkn->name = "Primary:Kerberos-Newer-Keys"; + pkn->reserved = 1; + pkn->data = pknb_hexstr; + } + /* * setup 'Primary:Kerberos' element */ |