From: Stefan Metzmacher Date: Tue, 31 May 2016 14:39:06 +0000 (+0200) Subject: s4:dsdb/password_hash: add the UF_SMARTCARD_REQUIRED password reset magic X-Git-Tag: tdb-1.3.10~169 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=acb208625b43191db44e3969b67d80d32436e79e;p=thirdparty%2Fsamba.git s4:dsdb/password_hash: add the UF_SMARTCARD_REQUIRED password reset magic When UF_SMARTCARD_REQUIRED is set to an account we need to remove the current password and add random NT and LM hashes (without updating the pwdLastSet field. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11441 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index db95b7f19be..a6131e2880b 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -109,6 +109,7 @@ struct ph_context { bool update_lastset; bool pwd_last_set_bypass; bool pwd_last_set_default; + bool smartcard_reset; }; @@ -1990,6 +1991,12 @@ static int setup_last_set_field(struct setup_password_fields_io *io) ldb_set_errstring(ldb, "'pwdLastSet' deletion is not allowed!"); return LDB_ERR_UNWILLING_TO_PERFORM; + } else if (io->ac->smartcard_reset) { + /* + * adding UF_SMARTCARD_REQUIRED doesn't update + * pwdLastSet implicitly. + */ + io->ac->update_lastset = false; } /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */ @@ -2205,6 +2212,85 @@ static int setup_password_fields(struct setup_password_fields_io *io) return LDB_SUCCESS; } +static int setup_smartcard_reset(struct setup_password_fields_io *io) +{ + struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module); + struct loadparm_context *lp_ctx = + lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), + struct loadparm_context); + struct supplementalCredentialsBlob scb = { .__ndr_size = 0 }; + enum ndr_err_code ndr_err; + + if (!io->ac->smartcard_reset) { + return LDB_SUCCESS; + } + + io->g.nt_hash = talloc(io->ac, struct samr_Password); + if (io->g.nt_hash == NULL) { + return ldb_module_oom(io->ac->module); + } + generate_secret_buffer(io->g.nt_hash->hash, + sizeof(io->g.nt_hash->hash)); + io->g.nt_history_len = 0; + + if (lpcfg_lanman_auth(lp_ctx)) { + io->g.lm_hash = talloc(io->ac, struct samr_Password); + if (io->g.lm_hash == NULL) { + return ldb_module_oom(io->ac->module); + } + generate_secret_buffer(io->g.lm_hash->hash, + sizeof(io->g.lm_hash->hash)); + } else { + io->g.lm_hash = NULL; + } + io->g.lm_history_len = 0; + + /* + * We take the "old" value and store it + * with num_packages = 0. + * + * On "add" we have scb.sub.signature == 0, which + * results in: + * + * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 + * + * On modify it's likely to be scb.sub.signature == + * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in + * something like: + * + * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00 + * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 + * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 + * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 + * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 + * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 + * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00 + * + * See https://bugzilla.samba.org/show_bug.cgi?id=11441 + * and ndr_{push,pull}_supplementalCredentialsSubBlob(). + */ + scb = io->o.scb; + scb.sub.num_packages = 0; + + /* + * setup 'supplementalCredentials' value without packages + */ + ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac, + &scb, + (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + ldb_asprintf_errstring(ldb, + "setup_smartcard_reset: " + "failed to push supplementalCredentialsBlob: %s", + nt_errstr(status)); + return LDB_ERR_OPERATIONS_ERROR; + } + + io->ac->update_password = true; + return LDB_SUCCESS; +} + static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io) { struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module); @@ -3233,6 +3319,26 @@ static void ph_apply_controls(struct ph_context *ac) /* Mark the "bypass pwdLastSet" control as uncritical (done) */ ctrl->critical = false; } + + ac->smartcard_reset = false; + ctrl = ldb_request_get_control(ac->req, + DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID); + if (ctrl != NULL) { + struct dsdb_control_password_user_account_control *uac = NULL; + uint32_t added_flags = 0; + + uac = talloc_get_type_abort(ctrl->data, + struct dsdb_control_password_user_account_control); + + added_flags = uac->new_flags & ~uac->old_flags; + + if (added_flags & UF_SMARTCARD_REQUIRED) { + ac->smartcard_reset = true; + } + + /* Mark the "smartcard required" control as uncritical (done) */ + ctrl->critical = false; + } } static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares) @@ -3461,6 +3567,7 @@ static int password_hash_needed(struct ldb_module *module, const char **a = NULL; unsigned int attr_cnt = 0; struct ldb_control *bypass = NULL; + struct ldb_control *uac_ctrl = NULL; bool userPassword = dsdb_user_password_support(module, req, req); bool update_password = false; bool processing_needed = false; @@ -3539,6 +3646,22 @@ static int password_hash_needed(struct ldb_module *module, processing_needed = true; } + uac_ctrl = ldb_request_get_control(req, + DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID); + if (uac_ctrl != NULL) { + struct dsdb_control_password_user_account_control *uac = NULL; + uint32_t added_flags = 0; + + uac = talloc_get_type_abort(uac_ctrl->data, + struct dsdb_control_password_user_account_control); + + added_flags = uac->new_flags & ~uac->old_flags; + + if (added_flags & UF_SMARTCARD_REQUIRED) { + processing_needed = true; + } + } + if (!processing_needed) { return ldb_next_request(module, req); } @@ -3642,6 +3765,11 @@ static int password_hash_add_do_add(struct ph_context *ac) return ret; } + ret = setup_smartcard_reset(&io); + if (ret != LDB_SUCCESS) { + return ret; + } + ret = update_final_msg(&io); if (ret != LDB_SUCCESS) { return ret; @@ -3974,6 +4102,11 @@ static int password_hash_mod_do_mod(struct ph_context *ac) return ret; } + ret = setup_smartcard_reset(&io); + if (ret != LDB_SUCCESS) { + return ret; + } + ret = update_final_msg(&io); if (ret != LDB_SUCCESS) { return ret;