From 09ae48b415b2b50dbf4600e9c7f9cb4ec65a6263 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 20 May 2024 13:51:23 +1200 Subject: [PATCH] dsdb: Prepare to handle smartcard password rollover We do this by allowing the password change control to indicate that the password is to be randomised, bypassing the quality checks (as true random passwords often fail these) and re-randomising with the same code as is used for the KDC. Signed-off-by: Andrew Bartlett Reviewed-by: Jo Sutton --- source4/dsdb/common/util.c | 10 ++++++ .../dsdb/samdb/ldb_modules/password_hash.c | 33 ++++++++++++++++--- source4/dsdb/samdb/samdb.h | 15 ++++++++- source4/libcli/ldap/ldap_controls.c | 1 + source4/setup/schema_samba4.ldif | 2 +- 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 38cd30c47dc..689fbd22a38 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2540,6 +2540,16 @@ static NTSTATUS samdb_set_password_request(struct ldb_context *ldb, TALLOC_CTX * talloc_free(req); return NT_STATUS_NO_MEMORY; } + + /* a KDC-triggered smart card password rollover (ResetSmartCardAccountPassword) */ + } else if (old_password_checked == DSDB_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD) { + ret = ldb_request_add_control(req, + DSDB_CONTROL_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD, + true, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(req); + return NT_STATUS_NO_MEMORY; + } } if (hash_values) { ret = ldb_request_add_control(req, diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index bcdf68a2214..1d1267624e2 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -135,6 +135,7 @@ struct ph_context { bool pwd_last_set_bypass; bool pwd_last_set_default; bool smartcard_reset; + bool kdc_reset_smartcard_account_password; const char **userPassword_schemes; }; @@ -2622,6 +2623,8 @@ static int setup_given_passwords(struct setup_password_fields_io *io, static int setup_password_fields(struct setup_password_fields_io *io) { struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module); + bool prepare_random; + int ret; ret = setup_last_set_field(io); @@ -2649,12 +2652,16 @@ static int setup_password_fields(struct setup_password_fields_io *io) } } + prepare_random = io->u.is_krbtgt || io->ac->smartcard_reset || + io->ac->kdc_reset_smartcard_account_password; + /* - * Both krbtgt and smartcard reset (on addition of - * UF_SMARTCARD_REQUIRED) need random passwords for all - * supported keys + * krbtgt, smartcard reset (on addition of + * UF_SMARTCARD_REQUIRED) and KDC-triggered rollover (for + * ResetSmartCardAccountPassword) need random passwords for + * all supported keys */ - if (io->u.is_krbtgt || io->ac->smartcard_reset) { + if (prepare_random) { size_t min = 196; size_t max = 255; size_t diff = max - min; @@ -2749,7 +2756,7 @@ static int setup_smartcard_reset(struct setup_password_fields_io *io) * to declare this a password update so that the change is * made (this ensures that the other rules about updates are * skipped in case, which is the setting of - * UF_SMARTCARD_REQUIRED on an account + * UF_SMARTCARD_REQUIRED on an account) */ io->ac->update_password = true; @@ -2927,6 +2934,11 @@ static int check_password_restrictions(struct setup_password_fields_io *io, WERR return ret; } + /* Do not apply restrictions on a KDC-issued rollover (eg ResetSmartCardAccountPassword) */ + if (io->ac->kdc_reset_smartcard_account_password) { + return LDB_SUCCESS; + } + /* * First check the old password is correct, for password * changes when this hasn't already been checked by a @@ -4189,6 +4201,17 @@ static void ph_apply_controls(struct ph_context *ac) /* Mark the "smartcard required" control as uncritical (done) */ ctrl->critical = false; } + + ac->kdc_reset_smartcard_account_password = false; + ctrl = ldb_request_get_control(ac->req, + DSDB_CONTROL_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD); + if (ctrl != NULL) { + ac->kdc_reset_smartcard_account_password = true; + + /* Mark KDC running ResetSmartCardAccountPassword control as uncritical (done) */ + ctrl->critical = false; + } + } static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares) diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 64135ef704f..3b62b60c52f 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -39,7 +39,15 @@ struct KeyEnvelope; enum dsdb_password_checked { DSDB_PASSWORD_NOT_CHECKED = 0, /* unused */ DSDB_PASSWORD_RESET, - DSDB_PASSWORD_CHECKED_AND_CORRECT + DSDB_PASSWORD_CHECKED_AND_CORRECT, + /* + * This disables the password rules for this new random + * password for ResetSmartCardAccountPassword handling. This + * produces a + * DSDB_CONTROL_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD + * control. + */ + DSDB_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD }; #include "lib/util/data_blob.h" @@ -263,6 +271,11 @@ struct dsdb_control_calculated_default_sd { #define DSDB_CONTROL_GMSA_UPDATE_OID "1.3.6.1.4.1.7165.4.3.38" /* struct gmsa_update */ +/* + * KDC is running ResetSmartCardAccountPassword behaviour, the password needs to be made random + */ +#define DSDB_CONTROL_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD "1.3.6.1.4.1.7165.4.3.39" + #define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1" struct dsdb_extended_replicated_object { struct ldb_message *msg; diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c index ec0094f6bc0..8d3a40f602e 100644 --- a/source4/libcli/ldap/ldap_controls.c +++ b/source4/libcli/ldap/ldap_controls.c @@ -1296,6 +1296,7 @@ static const struct ldap_control_handler ldap_known_controls[] = { { DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID, NULL, NULL }, { DSDB_CONTROL_ACL_READ_OID, NULL, NULL }, { DSDB_CONTROL_GMSA_UPDATE_OID, NULL, NULL }, + { DSDB_CONTROL_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD, NULL, NULL }, { DSDB_EXTENDED_SCHEMA_UPGRADE_IN_PROGRESS_OID, NULL, NULL }, { DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID, NULL, NULL}, { DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID, NULL, NULL }, diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif index 86907fac1ec..ed775af59a8 100644 --- a/source4/setup/schema_samba4.ldif +++ b/source4/setup/schema_samba4.ldif @@ -236,7 +236,7 @@ #Allocated: DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID 1.3.6.1.4.1.7165.4.3.36 #Allocated: DSDB_CONTROL_ACL_READ_OID 1.3.6.1.4.1.7165.4.3.37 #Allocated: DSDB_CONTROL_GMSA_UPDATE_OID 1.3.6.1.4.1.7165.4.3.38 - +#Allocated: DSDB_CONTROL_PASSWORD_KDC_RESET_SMARTCARD_ACCOUNT_PASSWORD 1.3.6.1.4.1.7165.4.3.39 # Extended 1.3.6.1.4.1.7165.4.4.x #Allocated: DSDB_EXTENDED_REPLICATED_OBJECTS_OID 1.3.6.1.4.1.7165.4.4.1 -- 2.47.3