LCOV - code coverage report
Current view: top level - source4/rpc_server/samr - samr_password.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 277 366 75.7 %
Date: 2024-06-10 12:05:21 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             :                                        r->in.password,
     243             :                                        DSDB_PASSWORD_CHECKED_AND_CORRECT);
     244          98 :         BURN_DATA(cdk_data);
     245             : 
     246             :         /* Restore our privileges to system level */
     247          98 :         if (old_session_info != NULL) {
     248          98 :                 ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info);
     249             :         }
     250             : 
     251          98 :         if (!NT_STATUS_IS_OK(status)) {
     252          38 :                 ldb_transaction_cancel(sam_ctx);
     253          38 :                 goto done;
     254             :         }
     255             : 
     256             :         /* And this confirms it in a transaction commit */
     257          60 :         rc = ldb_transaction_commit(sam_ctx);
     258          60 :         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          60 :         status = NT_STATUS_OK;
     268         110 : done:
     269             :         {
     270           0 :                 struct imessaging_context *imsg_ctx =
     271         110 :                         dcesrv_imessaging_context(dce_call->conn);
     272             : 
     273         110 :                 log_password_change_event(imsg_ctx,
     274         110 :                                         dce_call->conn->dce_ctx->lp_ctx,
     275         110 :                                         dce_call->conn->remote_address,
     276         110 :                                         dce_call->conn->local_address,
     277             :                                         "samr_ChangePasswordUser4",
     278             :                                         "AES using NTLM-hash",
     279         110 :                                         r->in.account->string,
     280             :                                         samAccountName,
     281             :                                         status,
     282             :                                         objectSid);
     283             :         }
     284             : 
     285             :         /* Only update the badPwdCount if we found the user */
     286         110 :         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
     287          16 :                 authsam_update_bad_pwd_count(sam_ctx,
     288             :                                              msg,
     289             :                                              ldb_get_default_basedn(sam_ctx));
     290          94 :         } 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           2 :                 status = NT_STATUS_WRONG_PASSWORD;
     296             :         }
     297             : 
     298         110 :         return status;
     299             : }
     300             : 
     301        1414 : static NTSTATUS dcesrv_samr_ChangePasswordUser_impl(struct dcesrv_call_state *dce_call,
     302             :                                                     TALLOC_CTX *mem_ctx,
     303             :                                                     struct samr_ChangePasswordUser3 *r,
     304             :                                                     const char *function_name)
     305             : {
     306           0 :         struct imessaging_context *imsg_ctx =
     307        1414 :                 dcesrv_imessaging_context(dce_call->conn);
     308        1414 :         NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
     309           0 :         DATA_BLOB new_password;
     310        1414 :         struct ldb_context *sam_ctx = NULL;
     311        1414 :         struct ldb_dn *user_dn = NULL;
     312           0 :         int ret;
     313        1414 :         struct ldb_message *msg = NULL;
     314           0 :         struct samr_Password *nt_pwd;
     315        1414 :         struct samr_DomInfo1 *dominfo = NULL;
     316        1414 :         struct userPwdChangeFailureInformation *reject = NULL;
     317        1414 :         enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
     318           0 :         uint8_t new_nt_hash[16];
     319           0 :         struct samr_Password nt_verifier;
     320        1414 :         const char *user_samAccountName = NULL;
     321        1414 :         struct dom_sid *user_objectSid = NULL;
     322        1414 :         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     323        1414 :         enum ntlm_auth_level ntlm_auth_level
     324        1414 :                 = lpcfg_ntlm_auth(lp_ctx);
     325        1414 :         gnutls_cipher_hd_t cipher_hnd = NULL;
     326           0 :         gnutls_datum_t nt_session_key;
     327        1414 :         struct auth_session_info *call_session_info = NULL;
     328        1414 :         struct auth_session_info *old_session_info = NULL;
     329           0 :         int rc;
     330             : 
     331        1414 :         *r->out.dominfo = NULL;
     332        1414 :         *r->out.reject = NULL;
     333             : 
     334             :         /* this call should be disabled without NTLM auth */
     335        1414 :         if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
     336           2 :                 DBG_WARNING("NTLM password changes not"
     337             :                             "permitted by configuration.\n");
     338           2 :                 return NT_STATUS_NTLM_BLOCKED;
     339             :         }
     340             : 
     341        1412 :         if (r->in.nt_password == NULL ||
     342        1412 :             r->in.nt_verifier == NULL) {
     343           0 :                 return NT_STATUS_INVALID_PARAMETER;
     344             :         }
     345             : 
     346             :         /* Connect to a SAMDB with system privileges for fetching the old pw
     347             :          * hashes. */
     348        1412 :         sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
     349        1412 :         if (sam_ctx == NULL) {
     350           0 :                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
     351             :         }
     352             : 
     353        1412 :         ret = ldb_transaction_start(sam_ctx);
     354        1412 :         if (ret != LDB_SUCCESS) {
     355           0 :                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
     356           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
     357             :         }
     358             : 
     359             :         /*
     360             :          * We use authsam_search_account() to be consistent with the
     361             :          * other callers in the bad password and audit log handling
     362             :          * systems.  It ensures we get DSDB_SEARCH_SHOW_EXTENDED_DN.
     363             :          */
     364        1412 :         status = authsam_search_account(mem_ctx,
     365             :                                         sam_ctx,
     366        1412 :                                         r->in.account->string,
     367             :                                         ldb_get_default_basedn(sam_ctx),
     368             :                                         &msg);
     369        1412 :         if (!NT_STATUS_IS_OK(status)) {
     370         301 :                 ldb_transaction_cancel(sam_ctx);
     371         301 :                 goto failed;
     372             :         }
     373             : 
     374        1111 :         user_dn = msg->dn;
     375        1111 :         user_samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
     376        1111 :         user_objectSid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
     377             : 
     378        1111 :         status = samdb_result_passwords(mem_ctx, lp_ctx,
     379             :                                         msg, &nt_pwd);
     380        1111 :         if (!NT_STATUS_IS_OK(status) ) {
     381          66 :                 ldb_transaction_cancel(sam_ctx);
     382          66 :                 goto failed;
     383             :         }
     384             : 
     385        1045 :         if (!nt_pwd) {
     386           0 :                 status = NT_STATUS_WRONG_PASSWORD;
     387           0 :                 ldb_transaction_cancel(sam_ctx);
     388           0 :                 goto failed;
     389             :         }
     390             : 
     391             :         /* decrypt the password we have been given */
     392        1045 :         nt_session_key = (gnutls_datum_t) {
     393        1045 :                 .data = nt_pwd->hash,
     394             :                 .size = sizeof(nt_pwd->hash),
     395             :         };
     396             : 
     397        1045 :         rc = gnutls_cipher_init(&cipher_hnd,
     398             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     399             :                                 &nt_session_key,
     400             :                                 NULL);
     401        1045 :         if (rc < 0) {
     402           0 :                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     403           0 :                 ldb_transaction_cancel(sam_ctx);
     404           0 :                 goto failed;
     405             :         }
     406             : 
     407        1045 :         rc = gnutls_cipher_decrypt(cipher_hnd,
     408        1045 :                                    r->in.nt_password->data,
     409             :                                    516);
     410        1045 :         gnutls_cipher_deinit(cipher_hnd);
     411        1045 :         if (rc < 0) {
     412           0 :                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     413           0 :                 ldb_transaction_cancel(sam_ctx);
     414           0 :                 goto failed;
     415             :         }
     416             : 
     417        1045 :         if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
     418         357 :                 DEBUG(3,("samr: failed to decode password buffer\n"));
     419         357 :                 status =  NT_STATUS_WRONG_PASSWORD;
     420         357 :                 ldb_transaction_cancel(sam_ctx);
     421         357 :                 goto failed;
     422             :         }
     423             : 
     424         688 :         if (r->in.nt_verifier == NULL) {
     425           0 :                 status = NT_STATUS_WRONG_PASSWORD;
     426           0 :                 ldb_transaction_cancel(sam_ctx);
     427           0 :                 goto failed;
     428             :         }
     429             : 
     430             :         /* check NT verifier */
     431         688 :         mdfour(new_nt_hash, new_password.data, new_password.length);
     432             : 
     433         688 :         rc = E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
     434         688 :         if (rc != 0) {
     435           0 :                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     436           0 :                 ldb_transaction_cancel(sam_ctx);
     437           0 :                 goto failed;
     438             :         }
     439         688 :         if (!mem_equal_const_time(nt_verifier.hash, r->in.nt_verifier->hash, 16)) {
     440         301 :                 status = NT_STATUS_WRONG_PASSWORD;
     441         301 :                 ldb_transaction_cancel(sam_ctx);
     442         301 :                 goto failed;
     443             :         }
     444             : 
     445             :         /* Drop to user privileges for the password change */
     446             : 
     447         387 :         old_session_info = ldb_get_opaque(sam_ctx, DSDB_SESSION_INFO);
     448         387 :         call_session_info = dcesrv_call_session_info(dce_call);
     449             : 
     450         387 :         ret = ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, call_session_info);
     451         387 :         if (ret != LDB_SUCCESS) {
     452           0 :                 status = NT_STATUS_INVALID_SYSTEM_SERVICE;
     453           0 :                 ldb_transaction_cancel(sam_ctx);
     454           0 :                 goto failed;
     455             :         }
     456             : 
     457             :         /* Performs the password modification. We pass the old hashes read out
     458             :          * from the database since they were already checked against the user-
     459             :          * provided ones. */
     460         387 :         status = samdb_set_password(sam_ctx, mem_ctx,
     461             :                                     user_dn,
     462             :                                     &new_password,
     463             :                                     NULL,
     464             :                                     DSDB_PASSWORD_CHECKED_AND_CORRECT,
     465             :                                     &reason,
     466             :                                     &dominfo);
     467             : 
     468             :         /* Restore our privileges to system level */
     469         387 :         if (old_session_info != NULL) {
     470         387 :                 ldb_set_opaque(sam_ctx, DSDB_SESSION_INFO, old_session_info);
     471             :         }
     472             : 
     473         387 :         if (!NT_STATUS_IS_OK(status)) {
     474         156 :                 ldb_transaction_cancel(sam_ctx);
     475         156 :                 goto failed;
     476             :         }
     477             : 
     478             :         /* And this confirms it in a transaction commit */
     479         231 :         ret = ldb_transaction_commit(sam_ctx);
     480         231 :         if (ret != LDB_SUCCESS) {
     481           0 :                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
     482             :                          ldb_dn_get_linearized(user_dn),
     483             :                          ldb_errstring(sam_ctx)));
     484           0 :                 status = NT_STATUS_TRANSACTION_ABORTED;
     485           0 :                 goto failed;
     486             :         }
     487             : 
     488         231 :         status = NT_STATUS_OK;
     489             : 
     490        1412 : failed:
     491             : 
     492        1412 :         log_password_change_event(imsg_ctx,
     493             :                                   lp_ctx,
     494        1412 :                                   dce_call->conn->remote_address,
     495        1412 :                                   dce_call->conn->local_address,
     496             :                                   function_name,
     497             :                                   "RC4/DES using NTLM-hash",
     498        1412 :                                   r->in.account->string,
     499             :                                   user_samAccountName,
     500             :                                   status,
     501             :                                   user_objectSid);
     502        1412 :         if (NT_STATUS_IS_OK(status)) {
     503         231 :                 return NT_STATUS_OK;
     504             :         }
     505             : 
     506             :         /* Only update the badPwdCount if we found the user */
     507        1181 :         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
     508           0 :                 NTSTATUS bad_pwd_status;
     509             : 
     510         658 :                 bad_pwd_status = authsam_update_bad_pwd_count(
     511             :                         sam_ctx, msg, ldb_get_default_basedn(sam_ctx));
     512         658 :                 if (NT_STATUS_EQUAL(bad_pwd_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
     513           0 :                         status = bad_pwd_status;
     514             :                 }
     515         523 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
     516             :                 /* Don't give the game away:  (don't allow anonymous users to prove the existence of usernames) */
     517         301 :                 status = NT_STATUS_WRONG_PASSWORD;
     518             :         }
     519             : 
     520        1181 :         reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
     521        1181 :         if (reject != NULL) {
     522        1181 :                 reject->extendedFailureReason = reason;
     523             : 
     524        1181 :                 *r->out.reject = reject;
     525             :         }
     526             : 
     527        1181 :         *r->out.dominfo = dominfo;
     528             : 
     529        1181 :         return status;
     530             : }
     531             : 
     532             : /*
     533             :   samr_ChangePasswordUser3
     534             : */
     535        1242 : NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
     536             :                                          TALLOC_CTX *mem_ctx,
     537             :                                          struct samr_ChangePasswordUser3 *r)
     538             : {
     539        1242 :         return dcesrv_samr_ChangePasswordUser_impl(dce_call, mem_ctx, r,
     540             :                                                    "samr_ChangePasswordUser3");
     541             : }
     542             : 
     543             : /*
     544             :   samr_ChangePasswordUser2
     545             : 
     546             :   easy - just a subset of samr_ChangePasswordUser3
     547             : */
     548         172 : NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
     549             :                                          TALLOC_CTX *mem_ctx,
     550             :                                          struct samr_ChangePasswordUser2 *r)
     551             : {
     552           0 :         struct samr_ChangePasswordUser3 r2;
     553         172 :         struct samr_DomInfo1 *dominfo = NULL;
     554         172 :         struct userPwdChangeFailureInformation *reject = NULL;
     555             : 
     556         172 :         r2.in.server = r->in.server;
     557         172 :         r2.in.account = r->in.account;
     558         172 :         r2.in.nt_password = r->in.nt_password;
     559         172 :         r2.in.nt_verifier = r->in.nt_verifier;
     560         172 :         r2.in.lm_change = r->in.lm_change;
     561         172 :         r2.in.lm_password = r->in.lm_password;
     562         172 :         r2.in.lm_verifier = r->in.lm_verifier;
     563         172 :         r2.in.password3 = NULL;
     564         172 :         r2.out.dominfo = &dominfo;
     565         172 :         r2.out.reject = &reject;
     566             : 
     567         172 :         return dcesrv_samr_ChangePasswordUser_impl(dce_call, mem_ctx, &r2,
     568             :                                                    "samr_ChangePasswordUser2");
     569             : }
     570             : 
     571             : 
     572             : /*
     573             :   set password via a samr_CryptPassword buffer
     574             : */
     575         247 : NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
     576             :                            struct ldb_context *sam_ctx,
     577             :                            struct ldb_dn *account_dn,
     578             :                            TALLOC_CTX *mem_ctx,
     579             :                            struct samr_CryptPassword *pwbuf)
     580             : {
     581           0 :         NTSTATUS nt_status;
     582           0 :         DATA_BLOB new_password;
     583         247 :         DATA_BLOB session_key = data_blob(NULL, 0);
     584         247 :         gnutls_cipher_hd_t cipher_hnd = NULL;
     585           0 :         gnutls_datum_t _session_key;
     586           0 :         struct auth_session_info *session_info =
     587         247 :                 dcesrv_call_session_info(dce_call);
     588         247 :         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     589           0 :         int rc;
     590           0 :         bool encrypted;
     591             : 
     592         247 :         encrypted = dcerpc_is_transport_encrypted(session_info);
     593         247 :         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
     594           0 :             !encrypted) {
     595           0 :                 return NT_STATUS_ACCESS_DENIED;
     596             :         }
     597             : 
     598         247 :         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
     599         247 :         if (!NT_STATUS_IS_OK(nt_status)) {
     600           0 :                 DBG_NOTICE("samr: failed to get session key: %s\n",
     601             :                            nt_errstr(nt_status));
     602           0 :                 return nt_status;
     603             :         }
     604             : 
     605         247 :         _session_key = (gnutls_datum_t) {
     606         247 :                 .data = session_key.data,
     607         247 :                 .size = session_key.length,
     608             :         };
     609             : 
     610             :         /*
     611             :          * This is safe to support as we only have a session key
     612             :          * over a SMB connection which we force to be encrypted.
     613             :          */
     614         247 :         GNUTLS_FIPS140_SET_LAX_MODE();
     615         247 :         rc = gnutls_cipher_init(&cipher_hnd,
     616             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     617             :                                 &_session_key,
     618             :                                 NULL);
     619         247 :         if (rc < 0) {
     620           0 :                 GNUTLS_FIPS140_SET_STRICT_MODE();
     621           0 :                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     622           0 :                 goto out;
     623             :         }
     624             : 
     625         247 :         rc = gnutls_cipher_decrypt(cipher_hnd,
     626         247 :                                    pwbuf->data,
     627             :                                    516);
     628         247 :         gnutls_cipher_deinit(cipher_hnd);
     629         247 :         GNUTLS_FIPS140_SET_STRICT_MODE();
     630         247 :         if (rc < 0) {
     631           0 :                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     632           0 :                 goto out;
     633             :         }
     634             : 
     635         247 :         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
     636          36 :                 DEBUG(3,("samr: failed to decode password buffer\n"));
     637          36 :                 return NT_STATUS_WRONG_PASSWORD;
     638             :         }
     639             : 
     640             :         /* set the password - samdb needs to know both the domain and user DNs,
     641             :            so the domain password policy can be used */
     642         211 :         nt_status = samdb_set_password(sam_ctx,
     643             :                                        mem_ctx,
     644             :                                        account_dn,
     645             :                                        &new_password,
     646             :                                        NULL,
     647             :                                        DSDB_PASSWORD_RESET,
     648             :                                        NULL,
     649             :                                        NULL);
     650         211 : out:
     651         211 :         return nt_status;
     652             : }
     653             : 
     654             : 
     655             : /*
     656             :   set password via a samr_CryptPasswordEx buffer
     657             : */
     658         678 : NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
     659             :                               struct ldb_context *sam_ctx,
     660             :                               struct ldb_dn *account_dn,
     661             :                               TALLOC_CTX *mem_ctx,
     662             :                               struct samr_CryptPasswordEx *pwbuf)
     663             : {
     664         678 :         struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     665          72 :         struct auth_session_info *session_info =
     666         678 :                 dcesrv_call_session_info(dce_call);
     667          72 :         NTSTATUS nt_status;
     668          72 :         DATA_BLOB new_password;
     669             : 
     670             :         /* The confounder is in the last 16 bytes of the buffer */
     671         678 :         DATA_BLOB confounder = data_blob_const(&pwbuf->data[516], 16);
     672         678 :         DATA_BLOB pw_data = data_blob_const(pwbuf->data, 516);
     673         678 :         DATA_BLOB session_key = data_blob(NULL, 0);
     674          72 :         int rc;
     675          72 :         bool encrypted;
     676             : 
     677         678 :         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
     678         678 :         if (!NT_STATUS_IS_OK(nt_status)) {
     679           0 :                 DEBUG(3,("samr: failed to get session key: %s "
     680             :                          "=> NT_STATUS_WRONG_PASSWORD\n",
     681             :                         nt_errstr(nt_status)));
     682           0 :                 return NT_STATUS_WRONG_PASSWORD;
     683             :         }
     684             : 
     685         678 :         encrypted = dcerpc_is_transport_encrypted(session_info);
     686         678 :         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED &&
     687           0 :             !encrypted) {
     688           0 :                 return NT_STATUS_ACCESS_DENIED;
     689             :         }
     690             : 
     691         678 :         GNUTLS_FIPS140_SET_LAX_MODE();
     692         678 :         rc = samba_gnutls_arcfour_confounded_md5(&confounder,
     693             :                                                  &session_key,
     694             :                                                  &pw_data,
     695             :                                                  SAMBA_GNUTLS_DECRYPT);
     696         678 :         GNUTLS_FIPS140_SET_STRICT_MODE();
     697         678 :         if (rc < 0) {
     698           0 :                 nt_status = gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
     699           0 :                 goto out;
     700             :         }
     701             : 
     702         678 :         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
     703          60 :                 DEBUG(3,("samr: failed to decode password buffer\n"));
     704          60 :                 nt_status = NT_STATUS_WRONG_PASSWORD;
     705          60 :                 goto out;
     706             :         }
     707             : 
     708             :         /* set the password - samdb needs to know both the domain and user DNs,
     709             :            so the domain password policy can be used */
     710         618 :         nt_status = samdb_set_password(sam_ctx,
     711             :                                        mem_ctx,
     712             :                                        account_dn,
     713             :                                        &new_password,
     714             :                                        NULL,
     715             :                                        DSDB_PASSWORD_RESET,
     716             :                                        NULL,
     717             :                                        NULL);
     718         618 :         ZERO_ARRAY_LEN(new_password.data,
     719             :                        new_password.length);
     720             : 
     721         678 : out:
     722         678 :         return nt_status;
     723             : }
     724             : 
     725             : /*
     726             :   set password via encrypted NT and LM hash buffers
     727             : */
     728         310 : NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
     729             :                                    struct ldb_context *sam_ctx,
     730             :                                    struct ldb_dn *account_dn,
     731             :                                    TALLOC_CTX *mem_ctx,
     732             :                                    const uint8_t *lm_pwd_hash,
     733             :                                    const uint8_t *nt_pwd_hash)
     734             : {
     735         310 :         struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
     736         310 :         uint8_t random_session_key[16] = { 0, };
     737         310 :         DATA_BLOB session_key = data_blob(NULL, 0);
     738           0 :         DATA_BLOB in, out;
     739         310 :         NTSTATUS nt_status = NT_STATUS_OK;
     740           0 :         int rc;
     741             : 
     742         310 :         nt_status = dcesrv_transport_session_key(dce_call, &session_key);
     743         310 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
     744           0 :                 DEBUG(3,("samr: failed to get session key: %s "
     745             :                          "=> use a random session key\n",
     746             :                          nt_errstr(nt_status)));
     747             : 
     748             :                 /*
     749             :                  * Windows just uses a random key
     750             :                  */
     751           0 :                 generate_random_buffer(random_session_key,
     752             :                                        sizeof(random_session_key));
     753           0 :                 session_key = data_blob_const(random_session_key,
     754             :                                               sizeof(random_session_key));
     755           0 :                 nt_status = NT_STATUS_OK;
     756             :         }
     757         310 :         if (!NT_STATUS_IS_OK(nt_status)) {
     758           0 :                 return nt_status;
     759             :         }
     760             : 
     761         310 :         if (nt_pwd_hash != NULL) {
     762         310 :                 in = data_blob_const(nt_pwd_hash, 16);
     763         310 :                 out = data_blob_talloc_zero(mem_ctx, 16);
     764             : 
     765         310 :                 rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_DECRYPT);
     766         310 :                 if (rc != 0) {
     767           0 :                         return gnutls_error_to_ntstatus(rc,
     768             :                                                         NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     769             :                 }
     770             : 
     771         310 :                 d_nt_pwd_hash = (struct samr_Password *) out.data;
     772             :         }
     773             : 
     774         310 :         if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
     775         310 :                 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
     776             :                                                NULL,
     777             :                                                d_nt_pwd_hash,
     778             :                                                DSDB_PASSWORD_RESET,
     779             :                                                NULL, NULL);
     780             :         }
     781             : 
     782         310 :         return nt_status;
     783             : }
     784             : 
     785         194 : NTSTATUS samr_set_password_aes(struct dcesrv_call_state *dce_call,
     786             :                                TALLOC_CTX *mem_ctx,
     787             :                                const DATA_BLOB *cdk,
     788             :                                struct ldb_context *sam_ctx,
     789             :                                struct ldb_dn *account_dn,
     790             :                                struct samr_EncryptedPasswordAES *pwbuf,
     791             :                                enum dsdb_password_checked old_password_checked)
     792             : {
     793         194 :         DATA_BLOB pw_data = data_blob_null;
     794         194 :         DATA_BLOB new_password = data_blob_null;
     795           0 :         const DATA_BLOB ciphertext =
     796         194 :                 data_blob_const(pwbuf->cipher, pwbuf->cipher_len);
     797         194 :         DATA_BLOB iv = data_blob_const(pwbuf->salt, sizeof(pwbuf->salt));
     798         194 :         NTSTATUS nt_status = NT_STATUS_OK;
     799           0 :         bool ok;
     800             : 
     801         194 :         nt_status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
     802             :                 mem_ctx,
     803             :                 &ciphertext,
     804             :                 cdk,
     805             :                 &samr_aes256_enc_key_salt,
     806             :                 &samr_aes256_mac_key_salt,
     807             :                 &iv,
     808         194 :                 pwbuf->auth_data,
     809             :                 &pw_data);
     810         194 :         if (!NT_STATUS_IS_OK(nt_status)) {
     811          64 :                 return NT_STATUS_WRONG_PASSWORD;
     812             :         }
     813             : 
     814         130 :         ok = extract_pwd_blob_from_buffer514(mem_ctx,
     815         130 :                                              pw_data.data,
     816             :                                              &new_password);
     817         130 :         TALLOC_FREE(pw_data.data);
     818         130 :         if (!ok) {
     819           0 :                 DBG_NOTICE("samr: failed to decode password buffer\n");
     820           0 :                 return NT_STATUS_WRONG_PASSWORD;
     821             :         }
     822             : 
     823         130 :         nt_status = samdb_set_password(sam_ctx,
     824             :                                        mem_ctx,
     825             :                                        account_dn,
     826             :                                        &new_password,
     827             :                                        NULL,
     828             :                                        old_password_checked,
     829             :                                        NULL,
     830             :                                        NULL);
     831         130 :         TALLOC_FREE(new_password.data);
     832             : 
     833         130 :         return nt_status;
     834             : }

Generated by: LCOV version 1.14