From: Joseph Sutton Date: Tue, 2 Aug 2022 02:39:06 +0000 (+1200) Subject: CVE-2021-20251 s4-rpc_server: Use user privileges for SAMR password change X-Git-Tag: talloc-2.4.0~1061 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f74f92aea164af40d9177b332778a76d7ecabcbd;p=thirdparty%2Fsamba.git CVE-2021-20251 s4-rpc_server: Use user privileges for SAMR password change We don't (and shouldn't) need system prvileges to perform the password change, so drop to the privileges of the user by setting DSDB_SESSION_INFO. We need to reuse the same sam_ctx: creating a new one with only user privileges would not work, because any database modifications would be blocked by the transaction taken out on the original context. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14611 Signed-off-by: Joseph Sutton Reviewed-by: Andreas Schneider Reviewed-by: Andrew Bartlett --- diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index f9a6f16e33f..b1342cbfe84 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -4091,7 +4091,8 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - &r->in.info->info31.password); + &r->in.info->info31.password, + DSDB_PASSWORD_RESET); if (!NT_STATUS_IS_OK(status)) { goto done; } @@ -4244,7 +4245,8 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - &r->in.info->info32.password); + &r->in.info->info32.password, + DSDB_PASSWORD_RESET); } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) { @@ -4255,7 +4257,8 @@ static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALL a_state->sam_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - &r->in.info->info32.password); + &r->in.info->info32.password, + DSDB_PASSWORD_RESET); } if (!NT_STATUS_IS_OK(status)) { goto done; diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c index 904e5fba6c5..c6cca985d8e 100644 --- a/source4/rpc_server/samr/samr_password.c +++ b/source4/rpc_server/samr/samr_password.c @@ -134,6 +134,8 @@ NTSTATUS dcesrv_samr_ChangePasswordUser4(struct dcesrv_call_state *dce_call, .data = cdk_data, .length = sizeof(cdk_data), }; + struct auth_session_info *call_session_info = NULL; + struct auth_session_info *old_session_info = NULL; NTSTATUS status = NT_STATUS_WRONG_PASSWORD; int rc; @@ -219,14 +221,33 @@ NTSTATUS dcesrv_samr_ChangePasswordUser4(struct dcesrv_call_state *dce_call, goto done; } + /* Drop to user privileges for the password change */ + + old_session_info = ldb_get_opaque(sam_ctx, DSDB_SESSION_INFO); + call_session_info = dcesrv_call_session_info(dce_call); + + rc = ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, call_session_info); + if (rc != LDB_SUCCESS) { + ldb_transaction_cancel(sam_ctx); + status = NT_STATUS_INVALID_SYSTEM_SERVICE; + goto done; + } + status = samr_set_password_aes(dce_call, mem_ctx, &cdk, sam_ctx, dn, NULL, - r->in.password); + r->in.password, + DSDB_PASSWORD_CHECKED_AND_CORRECT); BURN_DATA(cdk_data); + + /* Restore our privileges to system level */ + if (old_session_info != NULL) { + ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info); + } + if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); status = NT_STATUS_WRONG_PASSWORD; @@ -741,7 +762,8 @@ NTSTATUS samr_set_password_aes(struct dcesrv_call_state *dce_call, struct ldb_context *sam_ctx, struct ldb_dn *account_dn, struct ldb_dn *domain_dn, - struct samr_EncryptedPasswordAES *pwbuf) + struct samr_EncryptedPasswordAES *pwbuf, + enum dsdb_password_checked old_password_checked) { DATA_BLOB pw_data = data_blob_null; DATA_BLOB new_password = data_blob_null; @@ -779,7 +801,7 @@ NTSTATUS samr_set_password_aes(struct dcesrv_call_state *dce_call, domain_dn, &new_password, NULL, - DSDB_PASSWORD_RESET, + old_password_checked, NULL, NULL); TALLOC_FREE(new_password.data);