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

Generated by: LCOV version 1.13