LCOV - code coverage report
Current view: top level - source4/rpc_server/samr - samr_password.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 277 366 75.7 %
Date: 2023-11-21 12:31:41 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    samr server password set/change handling
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2004
       7             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "rpc_server/dcerpc_server.h"
      25             : #include "rpc_server/common/common.h"
      26             : #include "rpc_server/samr/dcesrv_samr.h"
      27             : #include "system/time.h"
      28             : #include "lib/crypto/md4.h"
      29             : #include "dsdb/common/util.h"
      30             : #include "dsdb/samdb/samdb.h"
      31             : #include "auth/auth.h"
      32             : #include "libcli/auth/libcli_auth.h"
      33             : #include "../lib/util/util_ldb.h"
      34             : #include "rpc_server/samr/proto.h"
      35             : #include "auth/auth_sam.h"
      36             : #include "lib/param/loadparm.h"
      37             : #include "librpc/rpc/dcerpc_helper.h"
      38             : #include "librpc/rpc/dcerpc_samr.h"
      39             : 
      40             : #include "lib/crypto/gnutls_helpers.h"
      41             : #include <gnutls/gnutls.h>
      42             : #include <gnutls/crypto.h>
      43             : 
      44        1522 : static void log_password_change_event(struct imessaging_context *msg_ctx,
      45             :                                       struct loadparm_context *lp_ctx,
      46             :                                       const struct tsocket_address *remote_client_address,
      47             :                                       const struct tsocket_address *local_server_address,
      48             :                                       const char *auth_description,
      49             :                                       const char *password_type,
      50             :                                       const char *original_client_name,
      51             :                                       const char *account_name_from_db,
      52             :                                       NTSTATUS status,
      53             :                                       struct dom_sid *sid)
      54             : {
      55             :         /*
      56             :          * Forcing this via the NTLM auth structure is not ideal, but
      57             :          * it is the most practical option right now, and ensures the
      58             :          * logs are consistent, even if some elements are always NULL.
      59             :          */
      60        4566 :         struct auth_usersupplied_info ui = {
      61             :                 .was_mapped = true,
      62             :                 .client = {
      63             :                         .account_name = original_client_name,
      64        1522 :                         .domain_name = lpcfg_sam_name(lp_ctx),
      65             :                 },
      66             :                 .mapped = {
      67             :                         .account_name = account_name_from_db,
      68        1522 :                         .domain_name = lpcfg_sam_name(lp_ctx),
      69             :                 },
      70             :                 .remote_host = remote_client_address,
      71             :                 .local_host = local_server_address,
      72             :                 .service_description = "SAMR Password Change",
      73             :                 .auth_description = auth_description,
      74             :                 .password_type = password_type,
      75             :         };
      76             : 
      77        1522 :         log_authentication_event(msg_ctx,
      78             :                                  lp_ctx,
      79             :                                  NULL,
      80             :                                  &ui,
      81             :                                  status,
      82             :                                  ui.mapped.domain_name,
      83             :                                  ui.mapped.account_name,
      84             :                                  sid,
      85             :                                  NULL /* client_audit_info */,
      86             :                                  NULL /* server_audit_info */);
      87        1522 : }
      88             : /*
      89             :   samr_ChangePasswordUser
      90             : 
      91             :   So old it is just not worth implementing
      92             :   because it does not supply a plaintext and so we can't do password
      93             :   complexity checking and cannot update all the other password hashes.
      94             : 
      95             : */
      96          24 : NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
      97             :                                         TALLOC_CTX *mem_ctx,
      98             :                                         struct samr_ChangePasswordUser *r)
      99             : {
     100          24 :         return NT_STATUS_NOT_IMPLEMENTED;
     101             : }
     102             : 
     103             : /*
     104             :   samr_OemChangePasswordUser2
     105             : 
     106             :   No longer implemented as it requires the LM hash
     107             : */
     108          26 : NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
     109             :                                             TALLOC_CTX *mem_ctx,
     110             :                                             struct samr_OemChangePasswordUser2 *r)
     111             : {
     112          26 :         return NT_STATUS_NOT_IMPLEMENTED;
     113             : }
     114             : 
     115             : /*
     116             :   samr_ChangePasswordUser4
     117             : */
     118         110 : NTSTATUS dcesrv_samr_ChangePasswordUser4(struct dcesrv_call_state *dce_call,
     119             :                                          TALLOC_CTX *mem_ctx,
     120             :                                          struct samr_ChangePasswordUser4 *r)
     121             : {
     122         110 :         struct ldb_context *sam_ctx = NULL;
     123         110 :         struct ldb_message *msg = NULL;
     124         110 :         struct ldb_dn *dn = NULL;
     125         110 :         const char *samAccountName = NULL;
     126         110 :         struct dom_sid *objectSid = NULL;
     127         110 :         struct samr_Password *nt_pwd = NULL;
     128           0 :         gnutls_datum_t nt_key;
     129         110 :         gnutls_datum_t salt = {
     130         110 :                 .data = r->in.password->salt,
     131             :                 .size = sizeof(r->in.password->salt),
     132             :         };
     133         110 :         uint8_t cdk_data[16] = {0};
     134         110 :         DATA_BLOB cdk = {
     135             :                 .data = cdk_data,
     136             :                 .length = sizeof(cdk_data),
     137             :         };
     138         110 :         struct auth_session_info *call_session_info = NULL;
     139         110 :         struct auth_session_info *old_session_info = NULL;
     140         110 :         NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
     141           0 :         int rc;
     142             : 
     143         110 :         r->out.result = NT_STATUS_WRONG_PASSWORD;
     144             : 
     145         110 :         if (r->in.password == NULL) {
     146           0 :                 return NT_STATUS_INVALID_PARAMETER;
     147             :         }
     148             : 
     149         110 :         if (r->in.password->PBKDF2Iterations < 5000 ||
     150         110 :             r->in.password->PBKDF2Iterations > 1000000) {
     151           0 :                 return NT_STATUS_INVALID_PARAMETER;
     152             :         }
     153             :         /*
     154             :          * Connect to a SAMDB with system privileges for fetching the old
     155             :          * password hashes.
     156             :          */
     157         220 :         sam_ctx = samdb_connect(mem_ctx,
     158             :                                 dce_call->event_ctx,
     159         110 :                                 dce_call->conn->dce_ctx->lp_ctx,
     160         110 :                                 system_session(dce_call->conn->dce_ctx->lp_ctx),
     161         110 :                                 dce_call->conn->remote_address,
     162             :                                 0);
     163         110 :         if (sam_ctx == NULL) {
     164           0 :                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
     165             :         }
     166             : 
     167         110 :         rc = ldb_transaction_start(sam_ctx);
     168         110 :         if (rc != LDB_SUCCESS) {
     169           0 :                 DBG_WARNING("Failed to start transaction: %s\n",
     170             :                             ldb_errstring(sam_ctx));
     171           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
     172             :         }
     173             : 
     174             :         /*
     175             :          * We use authsam_search_account() to be consistent with the
     176             :          * other callers in the bad password and audit log handling
     177             :          * systems.  It ensures we get DSDB_SEARCH_SHOW_EXTENDED_DN.
     178             :          */
     179         110 :         status = authsam_search_account(mem_ctx,
     180             :                                         sam_ctx,
     181         110 :                                         r->in.account->string,
     182             :                                         ldb_get_default_basedn(sam_ctx),
     183             :                                         &msg);
     184         110 :         if (!NT_STATUS_IS_OK(status)) {
     185           2 :                 ldb_transaction_cancel(sam_ctx);
     186           2 :                 goto done;
     187             :         }
     188             : 
     189         108 :         dn = msg->dn;
     190         108 :         samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
     191         108 :         objectSid = samdb_result_dom_sid(msg, msg, "objectSid");
     192             : 
     193         108 :         status = samdb_result_passwords(mem_ctx,
     194         108 :                                         dce_call->conn->dce_ctx->lp_ctx,
     195             :                                         msg,
     196             :                                         &nt_pwd);
     197         108 :         if (!NT_STATUS_IS_OK(status)) {
     198          10 :                 ldb_transaction_cancel(sam_ctx);
     199          10 :                 goto done;
     200             :         }
     201             : 
     202          98 :         if (nt_pwd == NULL) {
     203           0 :                 ldb_transaction_cancel(sam_ctx);
     204           0 :                 status = NT_STATUS_WRONG_PASSWORD;
     205           0 :                 goto done;
     206             :         }
     207             : 
     208          98 :         nt_key = (gnutls_datum_t){
     209          98 :                 .data = nt_pwd->hash,
     210             :                 .size = sizeof(nt_pwd->hash),
     211             :         };
     212             : 
     213          98 :         rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
     214             :                            &nt_key,
     215             :                            &salt,
     216          98 :                            r->in.password->PBKDF2Iterations,
     217          98 :                            cdk.data,
     218             :                            cdk.length);
     219          98 :         if (rc < 0) {
     220           0 :                 ldb_transaction_cancel(sam_ctx);
     221           0 :                 status = NT_STATUS_WRONG_PASSWORD;
     222           0 :                 goto done;
     223             :         }
     224             : 
     225             :         /* Drop to user privileges for the password change */
     226             : 
     227          98 :         old_session_info = ldb_get_opaque(sam_ctx, DSDB_SESSION_INFO);
     228          98 :         call_session_info = dcesrv_call_session_info(dce_call);
     229             : 
     230          98 :         rc = ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, call_session_info);
     231          98 :         if (rc != LDB_SUCCESS) {
     232           0 :                 ldb_transaction_cancel(sam_ctx);
     233           0 :                 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
     234           0 :                 goto done;
     235             :         }
     236             : 
     237          98 :         status = samr_set_password_aes(dce_call,
     238             :                                        mem_ctx,
     239             :                                        &cdk,
     240             :                                        sam_ctx,
     241             :                                        dn,
     242             :                                        NULL,
     243             :                                        r->in.password,
     244             :                                        DSDB_PASSWORD_CHECKED_AND_CORRECT);
     245          98 :         BURN_DATA(cdk_data);
     246             : 
     247             :         /* Restore our privileges to system level */
     248          98 :         if (old_session_info != NULL) {
     249          98 :                 ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info);
     250             :         }
     251             : 
     252          98 :         if (!NT_STATUS_IS_OK(status)) {
     253          38 :                 ldb_transaction_cancel(sam_ctx);
     254          38 :                 goto done;
     255             :         }
     256             : 
     257             :         /* And this confirms it in a transaction commit */
     258          60 :         rc = ldb_transaction_commit(sam_ctx);
     259          60 :         if (rc != LDB_SUCCESS) {
     260           0 :                 DBG_WARNING("Failed to commit transaction to change password "
     261             :                             "on %s: %s\n",
     262             :                             ldb_dn_get_linearized(dn),
     263             :                             ldb_errstring(sam_ctx));
     264           0 :                 status = NT_STATUS_TRANSACTION_ABORTED;
     265           0 :                 goto done;
     266             :         }
     267             : 
     268          60 :         status = NT_STATUS_OK;
     269         110 : done:
     270             :         {
     271           0 :                 struct imessaging_context *imsg_ctx =
     272         110 :                         dcesrv_imessaging_context(dce_call->conn);
     273             : 
     274         110 :                 log_password_change_event(imsg_ctx,
     275         110 :                                         dce_call->conn->dce_ctx->lp_ctx,
     276         110 :                                         dce_call->conn->remote_address,
     277         110 :                                         dce_call->conn->local_address,
     278             :                                         "samr_ChangePasswordUser4",
     279             :                                         "AES using NTLM-hash",
     280         110 :                                         r->in.account->string,
     281             :                                         samAccountName,
     282             :                                         status,
     283             :                                         objectSid);
     284             :         }
     285             : 
     286             :         /* Only update the badPwdCount if we found the user */
     287         110 :         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
     288          16 :                 authsam_update_bad_pwd_count(sam_ctx,
     289             :                                              msg,
     290             :                                              ldb_get_default_basedn(sam_ctx));
     291          94 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
     292             :                 /*
     293             :                  * Don't give the game away: (don't allow anonymous users to
     294             :                  * prove the existence of usernames)
     295             :                  */
     296           2 :                 status = NT_STATUS_WRONG_PASSWORD;
     297             :         }
     298             : 
     299         110 :         return status;
     300             : }
     301             : 
     302        1414 : static NTSTATUS dcesrv_samr_ChangePasswordUser_impl(struct dcesrv_call_state *dce_call,
     303             :                                                     TALLOC_CTX *mem_ctx,
     304             :                                                     struct samr_ChangePasswordUser3 *r,
     305             :                                                     const char *function_name)
     306             : {
     307           0 :         struct imessaging_context *imsg_ctx =
     308        1414 :                 dcesrv_imessaging_context(dce_call->conn);
     309        1414 :         NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
     310           0 :         DATA_BLOB new_password;
     311        1414 :         struct ldb_context *sam_ctx = NULL;
     312        1414 :         struct ldb_dn *user_dn = NULL;
     313           0 :         int ret;
     314        1414 :         struct ldb_message *msg = NULL;
     315           0 :         struct samr_Password *nt_pwd;
     316        1414 :         struct samr_DomInfo1 *dominfo = NULL;
     317        1414 :         struct userPwdChangeFailureInformation *reject = NULL;
     318        1414 :         enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
     319           0 :         uint8_t new_nt_hash[16];
     320           0 :         struct samr_Password nt_verifier;
     321        1414 :         const char *user_samAccountName = NULL;
     322        1414 :         struct dom_sid *user_objectSid = NULL;
     323        1414 :         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     324        1414 :         enum ntlm_auth_level ntlm_auth_level
     325        1414 :                 = lpcfg_ntlm_auth(lp_ctx);
     326        1414 :         gnutls_cipher_hd_t cipher_hnd = NULL;
     327           0 :         gnutls_datum_t nt_session_key;
     328        1414 :         struct auth_session_info *call_session_info = NULL;
     329        1414 :         struct auth_session_info *old_session_info = NULL;
     330           0 :         int rc;
     331             : 
     332        1414 :         *r->out.dominfo = NULL;
     333        1414 :         *r->out.reject = NULL;
     334             : 
     335             :         /* this call should be disabled without NTLM auth */
     336        1414 :         if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
     337           2 :                 DBG_WARNING("NTLM password changes not"
     338             :                             "permitted by configuration.\n");
     339           2 :                 return NT_STATUS_NTLM_BLOCKED;
     340             :         }
     341             : 
     342        1412 :         if (r->in.nt_password == NULL ||
     343        1412 :             r->in.nt_verifier == NULL) {
     344           0 :                 return NT_STATUS_INVALID_PARAMETER;
     345             :         }
     346             : 
     347             :         /* Connect to a SAMDB with system privileges for fetching the old pw
     348             :          * hashes. */
     349        1412 :         sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
     350        1412 :         if (sam_ctx == NULL) {
     351           0 :                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
     352             :         }
     353             : 
     354        1412 :         ret = ldb_transaction_start(sam_ctx);
     355        1412 :         if (ret != LDB_SUCCESS) {
     356           0 :                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
     357           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
     358             :         }
     359             : 
     360             :         /*
     361             :          * We use authsam_search_account() to be consistent with the
     362             :          * other callers in the bad password and audit log handling
     363             :          * systems.  It ensures we get DSDB_SEARCH_SHOW_EXTENDED_DN.
     364             :          */
     365        1412 :         status = authsam_search_account(mem_ctx,
     366             :                                         sam_ctx,
     367        1412 :                                         r->in.account->string,
     368             :                                         ldb_get_default_basedn(sam_ctx),
     369             :                                         &msg);
     370        1412 :         if (!NT_STATUS_IS_OK(status)) {
     371         301 :                 ldb_transaction_cancel(sam_ctx);
     372         301 :                 goto failed;
     373             :         }
     374             : 
     375        1111 :         user_dn = msg->dn;
     376        1111 :         user_samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
     377        1111 :         user_objectSid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
     378             : 
     379        1111 :         status = samdb_result_passwords(mem_ctx, lp_ctx,
     380             :                                         msg, &nt_pwd);
     381        1111 :         if (!NT_STATUS_IS_OK(status) ) {
     382          66 :                 ldb_transaction_cancel(sam_ctx);
     383          66 :                 goto failed;
     384             :         }
     385             : 
     386        1045 :         if (!nt_pwd) {
     387           0 :                 status = NT_STATUS_WRONG_PASSWORD;
     388           0 :                 ldb_transaction_cancel(sam_ctx);
     389           0 :                 goto failed;
     390             :         }
     391             : 
     392             :         /* decrypt the password we have been given */
     393        1045 :         nt_session_key = (gnutls_datum_t) {
     394        1045 :                 .data = nt_pwd->hash,
     395             :                 .size = sizeof(nt_pwd->hash),
     396             :         };
     397             : 
     398        1045 :         rc = gnutls_cipher_init(&cipher_hnd,
     399             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     400             :                                 &nt_session_key,
     401             :                                 NULL);
     402        1045 :         if (rc < 0) {
     403           0 :                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     404           0 :                 ldb_transaction_cancel(sam_ctx);
     405           0 :                 goto failed;
     406             :         }
     407             : 
     408        1045 :         rc = gnutls_cipher_decrypt(cipher_hnd,
     409        1045 :                                    r->in.nt_password->data,
     410             :                                    516);
     411        1045 :         gnutls_cipher_deinit(cipher_hnd);
     412        1045 :         if (rc < 0) {
     413           0 :                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     414           0 :                 ldb_transaction_cancel(sam_ctx);
     415           0 :                 goto failed;
     416             :         }
     417             : 
     418        1045 :         if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
     419         357 :                 DEBUG(3,("samr: failed to decode password buffer\n"));
     420         357 :                 status =  NT_STATUS_WRONG_PASSWORD;
     421         357 :                 ldb_transaction_cancel(sam_ctx);
     422         357 :                 goto failed;
     423             :         }
     424             : 
     425         688 :         if (r->in.nt_verifier == NULL) {
     426           0 :                 status = NT_STATUS_WRONG_PASSWORD;
     427           0 :                 ldb_transaction_cancel(sam_ctx);
     428           0 :                 goto failed;
     429             :         }
     430             : 
     431             :         /* check NT verifier */
     432         688 :         mdfour(new_nt_hash, new_password.data, new_password.length);
     433             : 
     434         688 :         rc = E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
     435         688 :         if (rc != 0) {
     436           0 :                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     437           0 :                 ldb_transaction_cancel(sam_ctx);
     438           0 :                 goto failed;
     439             :         }
     440         688 :         if (!mem_equal_const_time(nt_verifier.hash, r->in.nt_verifier->hash, 16)) {
     441         301 :                 status = NT_STATUS_WRONG_PASSWORD;
     442         301 :                 ldb_transaction_cancel(sam_ctx);
     443         301 :                 goto failed;
     444             :         }
     445             : 
     446             :         /* Drop to user privileges for the password change */
     447             : 
     448         387 :         old_session_info = ldb_get_opaque(sam_ctx, DSDB_SESSION_INFO);
     449         387 :         call_session_info = dcesrv_call_session_info(dce_call);
     450             : 
     451         387 :         ret = ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, call_session_info);
     452         387 :         if (ret != LDB_SUCCESS) {
     453           0 :                 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
     454           0 :                 ldb_transaction_cancel(sam_ctx);
     455           0 :                 goto failed;
     456             :         }
     457             : 
     458             :         /* Performs the password modification. We pass the old hashes read out
     459             :          * from the database since they were already checked against the user-
     460             :          * provided ones. */
     461         387 :         status = samdb_set_password(sam_ctx, mem_ctx,
     462             :                                     user_dn, NULL,
     463             :                                     &new_password,
     464             :                                     NULL,
     465             :                                     DSDB_PASSWORD_CHECKED_AND_CORRECT,
     466             :                                     &reason,
     467             :                                     &dominfo);
     468             : 
     469             :         /* Restore our privileges to system level */
     470         387 :         if (old_session_info != NULL) {
     471         387 :                 ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info);
     472             :         }
     473             : 
     474         387 :         if (!NT_STATUS_IS_OK(status)) {
     475         156 :                 ldb_transaction_cancel(sam_ctx);
     476         156 :                 goto failed;
     477             :         }
     478             : 
     479             :         /* And this confirms it in a transaction commit */
     480         231 :         ret = ldb_transaction_commit(sam_ctx);
     481         231 :         if (ret != LDB_SUCCESS) {
     482           0 :                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
     483             :                          ldb_dn_get_linearized(user_dn),
     484             :                          ldb_errstring(sam_ctx)));
     485           0 :                 status = NT_STATUS_TRANSACTION_ABORTED;
     486           0 :                 goto failed;
     487             :         }
     488             : 
     489         231 :         status = NT_STATUS_OK;
     490             : 
     491        1412 : failed:
     492             : 
     493        1412 :         log_password_change_event(imsg_ctx,
     494             :                                   lp_ctx,
     495        1412 :                                   dce_call->conn->remote_address,
     496        1412 :                                   dce_call->conn->local_address,
     497             :                                   function_name,
     498             :                                   "RC4/DES using NTLM-hash",
     499        1412 :                                   r->in.account->string,
     500             :                                   user_samAccountName,
     501             :                                   status,
     502             :                                   user_objectSid);
     503        1412 :         if (NT_STATUS_IS_OK(status)) {
     504         231 :                 return NT_STATUS_OK;
     505             :         }
     506             : 
     507             :         /* Only update the badPwdCount if we found the user */
     508        1181 :         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
     509           0 :                 NTSTATUS bad_pwd_status;
     510             : 
     511         658 :                 bad_pwd_status = authsam_update_bad_pwd_count(
     512             :                         sam_ctx, msg, ldb_get_default_basedn(sam_ctx));
     513         658 :                 if (NT_STATUS_EQUAL(bad_pwd_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
     514           0 :                         status = bad_pwd_status;
     515             :                 }
     516         523 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
     517             :                 /* Don't give the game away:  (don't allow anonymous users to prove the existence of usernames) */
     518         301 :                 status = NT_STATUS_WRONG_PASSWORD;
     519             :         }
     520             : 
     521        1181 :         reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
     522        1181 :         if (reject != NULL) {
     523        1181 :                 reject->extendedFailureReason = reason;
     524             : 
     525        1181 :                 *r->out.reject = reject;
     526             :         }
     527             : 
     528        1181 :         *r->out.dominfo = dominfo;
     529             : 
     530        1181 :         return status;
     531             : }
     532             : 
     533             : /*
     534             :   samr_ChangePasswordUser3
     535             : */
     536        1242 : NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
     537             :                                          TALLOC_CTX *mem_ctx,
     538             :                                          struct samr_ChangePasswordUser3 *r)
     539             : {
     540        1242 :         return dcesrv_samr_ChangePasswordUser_impl(dce_call, mem_ctx, r,
     541             :                                                    "samr_ChangePasswordUser3");
     542             : }
     543             : 
     544             : /*
     545             :   samr_ChangePasswordUser2
     546             : 
     547             :   easy - just a subset of samr_ChangePasswordUser3
     548             : */
     549         172 : NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
     550             :                                          TALLOC_CTX *mem_ctx,
     551             :                                          struct samr_ChangePasswordUser2 *r)
     552             : {
     553           0 :         struct samr_ChangePasswordUser3 r2;
     554         172 :         struct samr_DomInfo1 *dominfo = NULL;
     555         172 :         struct userPwdChangeFailureInformation *reject = NULL;
     556             : 
     557         172 :         r2.in.server = r->in.server;
     558         172 :         r2.in.account = r->in.account;
     559         172 :         r2.in.nt_password = r->in.nt_password;
     560         172 :         r2.in.nt_verifier = r->in.nt_verifier;
     561         172 :         r2.in.lm_change = r->in.lm_change;
     562         172 :         r2.in.lm_password = r->in.lm_password;
     563         172 :         r2.in.lm_verifier = r->in.lm_verifier;
     564         172 :         r2.in.password3 = NULL;
     565         172 :         r2.out.dominfo = &dominfo;
     566         172 :         r2.out.reject = &reject;
     567             : 
     568         172 :         return dcesrv_samr_ChangePasswordUser_impl(dce_call, mem_ctx, &r2,
     569             :                                                    "samr_ChangePasswordUser2");
     570             : }
     571             : 
     572             : 
     573             : /*
     574             :   set password via a samr_CryptPassword buffer
     575             : */
     576         247 : NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
     577             :                            struct ldb_context *sam_ctx,
     578             :                            struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
     579             :                            TALLOC_CTX *mem_ctx,
     580             :                            struct samr_CryptPassword *pwbuf)
     581             : {
     582           0 :         NTSTATUS nt_status;
     583           0 :         DATA_BLOB new_password;
     584         247 :         DATA_BLOB session_key = data_blob(NULL, 0);
     585         247 :         gnutls_cipher_hd_t cipher_hnd = NULL;
     586           0 :         gnutls_datum_t _session_key;
     587           0 :         struct auth_session_info *session_info =
     588         247 :                 dcesrv_call_session_info(dce_call);
     589         247 :         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     590           0 :         int rc;
     591           0 :         bool encrypted;
     592             : 
     593         247 :         encrypted = dcerpc_is_transport_encrypted(session_info);
     594         247 :         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
     595           0 :             !encrypted) {
     596           0 :                 return NT_STATUS_ACCESS_DENIED;
     597             :         }
     598             : 
     599         247 :         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
     600         247 :         if (!NT_STATUS_IS_OK(nt_status)) {
     601           0 :                 DBG_NOTICE("samr: failed to get session key: %s\n",
     602             :                            nt_errstr(nt_status));
     603           0 :                 return nt_status;
     604             :         }
     605             : 
     606         247 :         _session_key = (gnutls_datum_t) {
     607         247 :                 .data = session_key.data,
     608         247 :                 .size = session_key.length,
     609             :         };
     610             : 
     611             :         /*
     612             :          * This is safe to support as we only have a session key
     613             :          * over a SMB connection which we force to be encrypted.
     614             :          */
     615         247 :         GNUTLS_FIPS140_SET_LAX_MODE();
     616         247 :         rc = gnutls_cipher_init(&cipher_hnd,
     617             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     618             :                                 &_session_key,
     619             :                                 NULL);
     620         247 :         if (rc < 0) {
     621           0 :                 GNUTLS_FIPS140_SET_STRICT_MODE();
     622           0 :                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     623           0 :                 goto out;
     624             :         }
     625             : 
     626         247 :         rc = gnutls_cipher_decrypt(cipher_hnd,
     627         247 :                                    pwbuf->data,
     628             :                                    516);
     629         247 :         gnutls_cipher_deinit(cipher_hnd);
     630         247 :         GNUTLS_FIPS140_SET_STRICT_MODE();
     631         247 :         if (rc < 0) {
     632           0 :                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     633           0 :                 goto out;
     634             :         }
     635             : 
     636         247 :         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
     637          36 :                 DEBUG(3,("samr: failed to decode password buffer\n"));
     638          36 :                 return NT_STATUS_WRONG_PASSWORD;
     639             :         }
     640             : 
     641             :         /* set the password - samdb needs to know both the domain and user DNs,
     642             :            so the domain password policy can be used */
     643         211 :         nt_status = samdb_set_password(sam_ctx,
     644             :                                        mem_ctx,
     645             :                                        account_dn,
     646             :                                        domain_dn,
     647             :                                        &new_password,
     648             :                                        NULL,
     649             :                                        DSDB_PASSWORD_RESET,
     650             :                                        NULL,
     651             :                                        NULL);
     652         211 : out:
     653         211 :         return nt_status;
     654             : }
     655             : 
     656             : 
     657             : /*
     658             :   set password via a samr_CryptPasswordEx buffer
     659             : */
     660         678 : NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
     661             :                               struct ldb_context *sam_ctx,
     662             :                               struct ldb_dn *account_dn,
     663             :                               struct ldb_dn *domain_dn,
     664             :                               TALLOC_CTX *mem_ctx,
     665             :                               struct samr_CryptPasswordEx *pwbuf)
     666             : {
     667         678 :         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     668          72 :         struct auth_session_info *session_info =
     669         678 :                 dcesrv_call_session_info(dce_call);
     670          72 :         NTSTATUS nt_status;
     671          72 :         DATA_BLOB new_password;
     672             : 
     673             :         /* The confounder is in the last 16 bytes of the buffer */
     674         678 :         DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
     675         678 :         DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
     676         678 :         DATA_BLOB session_key = data_blob(NULL, 0);
     677          72 :         int rc;
     678          72 :         bool encrypted;
     679             : 
     680         678 :         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
     681         678 :         if (!NT_STATUS_IS_OK(nt_status)) {
     682           0 :                 DEBUG(3,("samr: failed to get session key: %s "
     683             :                          "=> NT_STATUS_WRONG_PASSWORD\n",
     684             :                         nt_errstr(nt_status)));
     685           0 :                 return NT_STATUS_WRONG_PASSWORD;
     686             :         }
     687             : 
     688         678 :         encrypted = dcerpc_is_transport_encrypted(session_info);
     689         678 :         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
     690           0 :             !encrypted) {
     691           0 :                 return NT_STATUS_ACCESS_DENIED;
     692             :         }
     693             : 
     694         678 :         GNUTLS_FIPS140_SET_LAX_MODE();
     695         678 :         rc = samba_gnutls_arcfour_confounded_md5(&confounder,
     696             :                                                  &session_key,
     697             :                                                  &pw_data,
     698             :                                                  SAMBA_GNUTLS_DECRYPT);
     699         678 :         GNUTLS_FIPS140_SET_STRICT_MODE();
     700         678 :         if (rc < 0) {
     701           0 :                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
     702           0 :                 goto out;
     703             :         }
     704             : 
     705         678 :         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
     706          60 :                 DEBUG(3,("samr: failed to decode password buffer\n"));
     707          60 :                 nt_status = NT_STATUS_WRONG_PASSWORD;
     708          60 :                 goto out;
     709             :         }
     710             : 
     711             :         /* set the password - samdb needs to know both the domain and user DNs,
     712             :            so the domain password policy can be used */
     713         618 :         nt_status = samdb_set_password(sam_ctx,
     714             :                                        mem_ctx,
     715             :                                        account_dn,
     716             :                                        domain_dn,
     717             :                                        &new_password,
     718             :                                        NULL,
     719             :                                        DSDB_PASSWORD_RESET,
     720             :                                        NULL,
     721             :                                        NULL);
     722         618 :         ZERO_ARRAY_LEN(new_password.data,
     723             :                        new_password.length);
     724             : 
     725         678 : out:
     726         678 :         return nt_status;
     727             : }
     728             : 
     729             : /*
     730             :   set password via encrypted NT and LM hash buffers
     731             : */
     732         310 : NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
     733             :                                    struct ldb_context *sam_ctx,
     734             :                                    struct ldb_dn *account_dn,
     735             :                                    struct ldb_dn *domain_dn,
     736             :                                    TALLOC_CTX *mem_ctx,
     737             :                                    const uint8_t *lm_pwd_hash,
     738             :                                    const uint8_t *nt_pwd_hash)
     739             : {
     740         310 :         struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
     741         310 :         uint8_t random_session_key[16] = { 0, };
     742         310 :         DATA_BLOB session_key = data_blob(NULL, 0);
     743           0 :         DATA_BLOB in, out;
     744         310 :         NTSTATUS nt_status = NT_STATUS_OK;
     745           0 :         int rc;
     746             : 
     747         310 :         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
     748         310 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
     749           0 :                 DEBUG(3,("samr: failed to get session key: %s "
     750             :                          "=> use a random session key\n",
     751             :                          nt_errstr(nt_status)));
     752             : 
     753             :                 /*
     754             :                  * Windows just uses a random key
     755             :                  */
     756           0 :                 generate_random_buffer(random_session_key,
     757             :                                        sizeof(random_session_key));
     758           0 :                 session_key = data_blob_const(random_session_key,
     759             :                                               sizeof(random_session_key));
     760           0 :                 nt_status = NT_STATUS_OK;
     761             :         }
     762         310 :         if (!NT_STATUS_IS_OK(nt_status)) {
     763           0 :                 return nt_status;
     764             :         }
     765             : 
     766         310 :         if (nt_pwd_hash != NULL) {
     767         310 :                 in = data_blob_const(nt_pwd_hash, 16);
     768         310 :                 out = data_blob_talloc_zero(mem_ctx, 16);
     769             : 
     770         310 :                 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
     771         310 :                 if (rc != 0) {
     772           0 :                         return gnutls_error_to_ntstatus(rc,
     773             :                                                         NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     774             :                 }
     775             : 
     776         310 :                 d_nt_pwd_hash = (struct samr_Password *) out.data;
     777             :         }
     778             : 
     779         310 :         if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
     780         310 :                 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
     781             :                                                domain_dn, NULL,
     782             :                                                d_nt_pwd_hash,
     783             :                                                DSDB_PASSWORD_RESET,
     784             :                                                NULL, NULL);
     785             :         }
     786             : 
     787         310 :         return nt_status;
     788             : }
     789             : 
     790         194 : NTSTATUS samr_set_password_aes(struct dcesrv_call_state *dce_call,
     791             :                                TALLOC_CTX *mem_ctx,
     792             :                                const DATA_BLOB *cdk,
     793             :                                struct ldb_context *sam_ctx,
     794             :                                struct ldb_dn *account_dn,
     795             :                                struct ldb_dn *domain_dn,
     796             :                                struct samr_EncryptedPasswordAES *pwbuf,
     797             :                                enum dsdb_password_checked old_password_checked)
     798             : {
     799         194 :         DATA_BLOB pw_data = data_blob_null;
     800         194 :         DATA_BLOB new_password = data_blob_null;
     801           0 :         const DATA_BLOB ciphertext =
     802         194 :                 data_blob_const(pwbuf->cipher, pwbuf->cipher_len);
     803         194 :         DATA_BLOB iv = data_blob_const(pwbuf->salt, sizeof(pwbuf->salt));
     804         194 :         NTSTATUS nt_status = NT_STATUS_OK;
     805           0 :         bool ok;
     806             : 
     807         194 :         nt_status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
     808             :                 mem_ctx,
     809             :                 &ciphertext,
     810             :                 cdk,
     811             :                 &samr_aes256_enc_key_salt,
     812             :                 &samr_aes256_mac_key_salt,
     813             :                 &iv,
     814         194 :                 pwbuf->auth_data,
     815             :                 &pw_data);
     816         194 :         if (!NT_STATUS_IS_OK(nt_status)) {
     817          64 :                 return NT_STATUS_WRONG_PASSWORD;
     818             :         }
     819             : 
     820         130 :         ok = extract_pwd_blob_from_buffer514(mem_ctx,
     821         130 :                                              pw_data.data,
     822             :                                              &new_password);
     823         130 :         TALLOC_FREE(pw_data.data);
     824         130 :         if (!ok) {
     825           0 :                 DBG_NOTICE("samr: failed to decode password buffer\n");
     826           0 :                 return NT_STATUS_WRONG_PASSWORD;
     827             :         }
     828             : 
     829         130 :         nt_status = samdb_set_password(sam_ctx,
     830             :                                        mem_ctx,
     831             :                                        account_dn,
     832             :                                        domain_dn,
     833             :                                        &new_password,
     834             :                                        NULL,
     835             :                                        old_password_checked,
     836             :                                        NULL,
     837             :                                        NULL);
     838         130 :         TALLOC_FREE(new_password.data);
     839             : 
     840         130 :         return nt_status;
     841             : }

Generated by: LCOV version 1.14