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

Generated by: LCOV version 1.13