]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2021-20251 s4-rpc_server: Use user privileges for SAMR password change
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Tue, 2 Aug 2022 02:39:06 +0000 (14:39 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 12 Sep 2022 23:07:38 +0000 (23:07 +0000)
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 <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/rpc_server/samr/dcesrv_samr.c
source4/rpc_server/samr/samr_password.c

index f9a6f16e33f0036e59cee8c09a3321b4dcf895f8..b1342cbfe845bf3d71c7aaec045d74f47d7c9b23 100644 (file)
@@ -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;
index 904e5fba6c54669b945fd3aa6b07fa80c4493b48..c6cca985d8e8fffc6c157cd8b2a79f6fd5ffe442 100644 (file)
@@ -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);