LCOV - code coverage report
Current view: top level - source3/libsmb - trusts_util.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 129 279 46.2 %
Date: 2024-02-28 12:06:22 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  Unix SMB/CIFS implementation.
       3             :  *  Routines to operate on various trust relationships
       4             :  *  Copyright (C) Andrew Bartlett                   2001
       5             :  *  Copyright (C) Rafal Szczesniak                  2003
       6             :  *
       7             :  *  This program is free software; you can redistribute it and/or modify
       8             :  *  it under the terms of the GNU General Public License as published by
       9             :  *  the Free Software Foundation; either version 3 of the License, or
      10             :  *  (at your option) any later version.
      11             :  *
      12             :  *  This program is distributed in the hope that it will be useful,
      13             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  *  GNU General Public License for more details.
      16             :  *
      17             :  *  You should have received a copy of the GNU General Public License
      18             :  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include "includes.h"
      22             : #include "../libcli/auth/libcli_auth.h"
      23             : #include "../libcli/auth/netlogon_creds_cli.h"
      24             : #include "rpc_client/cli_netlogon.h"
      25             : #include "rpc_client/cli_pipe.h"
      26             : #include "../librpc/gen_ndr/ndr_netlogon.h"
      27             : #include "librpc/gen_ndr/secrets.h"
      28             : #include "secrets.h"
      29             : #include "passdb.h"
      30             : #include "libsmb/libsmb.h"
      31             : #include "source3/include/messages.h"
      32             : #include "source3/include/g_lock.h"
      33             : #include "lib/util/util_tdb.h"
      34             : 
      35             : /*********************************************************
      36             :  Change the domain password on the PDC.
      37             :  Do most of the legwork ourselves.  Caller must have
      38             :  already setup the connection to the NETLOGON pipe
      39             : **********************************************************/
      40             : 
      41             : struct trust_pw_change_state {
      42             :         struct g_lock_ctx *g_ctx;
      43             :         char *g_lock_key;
      44             : };
      45             : 
      46           6 : static int trust_pw_change_state_destructor(struct trust_pw_change_state *state)
      47             : {
      48           6 :         g_lock_unlock(state->g_ctx,
      49           6 :                       string_term_tdb_data(state->g_lock_key));
      50           6 :         return 0;
      51             : }
      52             : 
      53          78 : char *trust_pw_new_value(TALLOC_CTX *mem_ctx,
      54             :                          enum netr_SchannelType sec_channel_type,
      55             :                          int security)
      56             : {
      57             :         /*
      58             :          * use secure defaults, which match
      59             :          * what windows uses for computer passwords.
      60             :          *
      61             :          * We used to have min=128 and max=255 here, but
      62             :          * it's a bad idea because of bugs in the Windows
      63             :          * RODC/RWDC PasswordUpdateForward handling via
      64             :          * NetrLogonSendToSam.
      65             :          *
      66             :          * See https://bugzilla.samba.org/show_bug.cgi?id=14984
      67             :          */
      68          78 :         size_t min = 120;
      69          78 :         size_t max = 120;
      70             : 
      71          78 :         switch (sec_channel_type) {
      72          78 :         case SEC_CHAN_WKSTA:
      73             :         case SEC_CHAN_BDC:
      74          78 :                 if (security == SEC_DOMAIN) {
      75             :                         /*
      76             :                          * The maximum length of a trust account password.
      77             :                          * Used when we randomly create it, 15 char passwords
      78             :                          * exceed NT4's max password length.
      79             :                          */
      80          18 :                         min = 14;
      81          18 :                         max = 14;
      82             :                 }
      83          78 :                 break;
      84           0 :         case SEC_CHAN_DNS_DOMAIN:
      85             :                 /*
      86             :                  * new_len * 2 = 498 bytes is the largest possible length
      87             :                  * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
      88             :                  * and a confounder with at least 2 bytes is required.
      89             :                  *
      90             :                  * Windows uses new_len = 120 => 240 bytes (utf16)
      91             :                  */
      92           0 :                 min = 120;
      93           0 :                 max = 120;
      94           0 :                 break;
      95           0 :         case SEC_CHAN_DOMAIN:
      96             :                 /*
      97             :                  * The maximum length of a trust account password.
      98             :                  * Used when we randomly create it, 15 char passwords
      99             :                  * exceed NT4's max password length.
     100             :                  */
     101           0 :                 min = 14;
     102           0 :                 max = 14;
     103           0 :                 break;
     104           0 :         default:
     105           0 :                 break;
     106             :         }
     107             : 
     108             :         /*
     109             :          * Create a random machine account password
     110             :          * We create a random buffer and convert that to utf8.
     111             :          * This is similar to what windows is doing.
     112             :          */
     113          78 :         return generate_random_machine_password(mem_ctx, min, max);
     114             : }
     115             : 
     116             : /*
     117             :  * Temporary function to wrap cli_auth in a lck
     118             :  */
     119             : 
     120          12 : static NTSTATUS netlogon_creds_cli_lck_auth(
     121             :         struct netlogon_creds_cli_context *context,
     122             :         struct dcerpc_binding_handle *b,
     123             :         uint8_t num_nt_hashes,
     124             :         const struct samr_Password * const *nt_hashes,
     125             :         uint8_t *idx_nt_hashes)
     126             : {
     127           0 :         struct netlogon_creds_cli_lck *lck;
     128           0 :         NTSTATUS status;
     129             : 
     130          12 :         status = netlogon_creds_cli_lck(
     131             :                 context, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
     132             :                 talloc_tos(), &lck);
     133          12 :         if (!NT_STATUS_IS_OK(status)) {
     134           0 :                 DBG_WARNING("netlogon_creds_cli_lck failed: %s\n",
     135             :                             nt_errstr(status));
     136           0 :                 return status;
     137             :         }
     138             : 
     139          12 :         status = netlogon_creds_cli_auth(context, b, num_nt_hashes, nt_hashes,
     140             :                                          idx_nt_hashes);
     141          12 :         TALLOC_FREE(lck);
     142             : 
     143          12 :         return status;
     144             : }
     145             : 
     146           6 : NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
     147             :                          struct messaging_context *msg_ctx,
     148             :                          struct dcerpc_binding_handle *b,
     149             :                          const char *domain,
     150             :                          const char *dcname,
     151             :                          bool force)
     152             : {
     153           6 :         TALLOC_CTX *frame = talloc_stackframe();
     154           6 :         const char *context_name = NULL;
     155           0 :         struct trust_pw_change_state *state;
     156           6 :         struct cli_credentials *creds = NULL;
     157           6 :         struct secrets_domain_info1 *info = NULL;
     158           6 :         struct secrets_domain_info1_change *prev = NULL;
     159           6 :         const struct samr_Password *current_nt_hash = NULL;
     160           6 :         const struct samr_Password *previous_nt_hash = NULL;
     161           6 :         uint8_t num_nt_hashes = 0;
     162           6 :         uint8_t idx = 0;
     163           6 :         const struct samr_Password *nt_hashes[1+3] = { NULL, };
     164           6 :         uint8_t idx_nt_hashes = 0;
     165           6 :         uint8_t idx_current = UINT8_MAX;
     166           6 :         enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
     167           0 :         time_t pass_last_set_time;
     168           6 :         uint32_t old_version = 0;
     169           6 :         struct pdb_trusted_domain *td = NULL;
     170           6 :         struct timeval g_timeout = { 0, };
     171           6 :         int timeout = 0;
     172           6 :         struct timeval tv = { 0, };
     173           6 :         char *new_trust_pw_str = NULL;
     174           6 :         size_t len = 0;
     175           6 :         DATA_BLOB new_trust_pw_blob = data_blob_null;
     176           6 :         uint32_t new_version = 0;
     177           6 :         uint32_t *new_trust_version = NULL;
     178           0 :         NTSTATUS status;
     179           0 :         bool ok;
     180             : 
     181           6 :         state = talloc_zero(frame, struct trust_pw_change_state);
     182           6 :         if (state == NULL) {
     183           0 :                 TALLOC_FREE(frame);
     184           0 :                 return NT_STATUS_NO_MEMORY;
     185             :         }
     186             : 
     187           6 :         state->g_ctx = g_lock_ctx_init(state, msg_ctx);
     188           6 :         if (state->g_ctx == NULL) {
     189           0 :                 TALLOC_FREE(frame);
     190           0 :                 return NT_STATUS_NO_MEMORY;
     191             :         }
     192             : 
     193           6 :         state->g_lock_key = talloc_asprintf(state,
     194             :                                 "trust_password_change_%s",
     195             :                                 domain);
     196           6 :         if (state->g_lock_key == NULL) {
     197           0 :                 TALLOC_FREE(frame);
     198           0 :                 return NT_STATUS_NO_MEMORY;
     199             :         }
     200             : 
     201           6 :         g_timeout = timeval_current_ofs(10, 0);
     202           6 :         status = g_lock_lock(state->g_ctx,
     203           6 :                              string_term_tdb_data(state->g_lock_key),
     204             :                              G_LOCK_WRITE, g_timeout, NULL, NULL);
     205           6 :         if (!NT_STATUS_IS_OK(status)) {
     206           0 :                 DEBUG(1, ("could not get g_lock on [%s]!\n",
     207             :                           state->g_lock_key));
     208           0 :                 TALLOC_FREE(frame);
     209           0 :                 return status;
     210             :         }
     211             : 
     212           6 :         talloc_set_destructor(state, trust_pw_change_state_destructor);
     213             : 
     214           6 :         status = pdb_get_trust_credentials(domain, NULL, frame, &creds);
     215           6 :         if (!NT_STATUS_IS_OK(status)) {
     216           0 :                 DEBUG(0, ("could not fetch domain creds for domain %s - %s!\n",
     217             :                           domain, nt_errstr(status)));
     218           0 :                 TALLOC_FREE(frame);
     219           0 :                 return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     220             :         }
     221             : 
     222           6 :         current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
     223           6 :         if (current_nt_hash == NULL) {
     224           0 :                 DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
     225             :                           domain));
     226           0 :                 TALLOC_FREE(frame);
     227           0 :                 return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     228             :         }
     229           6 :         previous_nt_hash = cli_credentials_get_old_nt_hash(creds, frame);
     230             : 
     231           6 :         old_version = cli_credentials_get_kvno(creds);
     232           6 :         pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
     233           6 :         sec_channel_type = cli_credentials_get_secure_channel_type(creds);
     234             : 
     235           6 :         new_version = old_version + 1;
     236             : 
     237           6 :         switch (sec_channel_type) {
     238           6 :         case SEC_CHAN_WKSTA:
     239             :         case SEC_CHAN_BDC:
     240           6 :                 break;
     241           0 :         case SEC_CHAN_DNS_DOMAIN:
     242             :         case SEC_CHAN_DOMAIN:
     243           0 :                 status = pdb_get_trusted_domain(frame, domain, &td);
     244           0 :                 if (!NT_STATUS_IS_OK(status)) {
     245           0 :                         DEBUG(0, ("pdb_get_trusted_domain() failed for domain %s - %s!\n",
     246             :                                   domain, nt_errstr(status)));
     247           0 :                         TALLOC_FREE(frame);
     248           0 :                         return status;
     249             :                 }
     250             : 
     251           0 :                 new_trust_version = &new_version;
     252           0 :                 break;
     253           0 :         default:
     254           0 :                 TALLOC_FREE(frame);
     255           0 :                 return NT_STATUS_NOT_SUPPORTED;
     256             :         }
     257             : 
     258           6 :         timeout = lp_machine_password_timeout();
     259           6 :         if (timeout == 0) {
     260           0 :                 if (!force) {
     261           0 :                         DEBUG(10,("machine password never expires\n"));
     262           0 :                         TALLOC_FREE(frame);
     263           0 :                         return NT_STATUS_OK;
     264             :                 }
     265             :         }
     266             : 
     267           6 :         tv.tv_sec = pass_last_set_time;
     268           6 :         DEBUG(10, ("password last changed %s\n",
     269             :                    timeval_string(talloc_tos(), &tv, false)));
     270           6 :         tv.tv_sec += timeout;
     271           6 :         DEBUGADD(10, ("password valid until %s\n",
     272             :                       timeval_string(talloc_tos(), &tv, false)));
     273             : 
     274           6 :         if (!force && !timeval_expired(&tv)) {
     275           0 :                 TALLOC_FREE(frame);
     276           0 :                 return NT_STATUS_OK;
     277             :         }
     278             : 
     279           6 :         context_name = netlogon_creds_cli_debug_string(context, talloc_tos());
     280           6 :         if (context_name == NULL) {
     281           0 :                 TALLOC_FREE(frame);
     282           0 :                 return NT_STATUS_NO_MEMORY;
     283             :         }
     284             : 
     285             :         /*
     286             :          * Create a random machine account password
     287             :          * We create a random buffer and convert that to utf8.
     288             :          * This is similar to what windows is doing.
     289             :          */
     290           6 :         new_trust_pw_str = trust_pw_new_value(frame, sec_channel_type,
     291             :                                               lp_security());
     292           6 :         if (new_trust_pw_str == NULL) {
     293           0 :                 DEBUG(0, ("trust_pw_new_value() failed\n"));
     294           0 :                 TALLOC_FREE(frame);
     295           0 :                 return NT_STATUS_NO_MEMORY;
     296             :         }
     297             : 
     298           6 :         len = strlen(new_trust_pw_str);
     299           6 :         ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
     300             :                                    new_trust_pw_str, len,
     301             :                                    (void **)&new_trust_pw_blob.data,
     302             :                                    &new_trust_pw_blob.length);
     303           6 :         if (!ok) {
     304           0 :                 status = NT_STATUS_UNMAPPABLE_CHARACTER;
     305           0 :                 if (errno == ENOMEM) {
     306           0 :                         status = NT_STATUS_NO_MEMORY;
     307             :                 }
     308           0 :                 DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
     309             :                         "failed for of %s - %s\n",
     310             :                         domain, nt_errstr(status));
     311           0 :                 TALLOC_FREE(frame);
     312           0 :                 return status;
     313             :         }
     314           6 :         talloc_keep_secret(new_trust_pw_blob.data);
     315             : 
     316           6 :         switch (sec_channel_type) {
     317             : 
     318           6 :         case SEC_CHAN_WKSTA:
     319             :         case SEC_CHAN_BDC:
     320           6 :                 status = secrets_prepare_password_change(domain, dcname,
     321             :                                                          new_trust_pw_str,
     322             :                                                          frame, &info, &prev);
     323           6 :                 if (!NT_STATUS_IS_OK(status)) {
     324           0 :                         DEBUG(0, ("secrets_prepare_password_change() failed for domain %s!\n",
     325             :                                   domain));
     326           0 :                         TALLOC_FREE(frame);
     327           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     328             :                 }
     329           6 :                 TALLOC_FREE(new_trust_pw_str);
     330             : 
     331           6 :                 if (prev != NULL) {
     332             :                         /*
     333             :                          * We had a failure before we changed the password.
     334             :                          */
     335           0 :                         nt_hashes[idx++] = &prev->password->nt_hash;
     336             : 
     337           0 :                         DEBUG(0,("%s : %s(%s): A password change was already "
     338             :                                  "started against '%s' at %s. Trying to "
     339             :                                  "recover...\n",
     340             :                                  current_timestring(talloc_tos(), false),
     341             :                                  __func__, domain,
     342             :                                  prev->password->change_server,
     343             :                                  nt_time_string(talloc_tos(),
     344             :                                  prev->password->change_time)));
     345           0 :                         DEBUG(0,("%s : %s(%s): Last failure local[%s] remote[%s] "
     346             :                                  "against '%s' at %s.\n",
     347             :                                  current_timestring(talloc_tos(), false),
     348             :                                  __func__, domain,
     349             :                                  nt_errstr(prev->local_status),
     350             :                                  nt_errstr(prev->remote_status),
     351             :                                  prev->change_server,
     352             :                                  nt_time_string(talloc_tos(),
     353             :                                  prev->change_time)));
     354             :                 }
     355             : 
     356           6 :                 idx_current = idx;
     357           6 :                 nt_hashes[idx++] = &info->password->nt_hash;
     358           6 :                 if (info->old_password != NULL) {
     359           0 :                         nt_hashes[idx++] = &info->old_password->nt_hash;
     360             :                 }
     361           6 :                 if (info->older_password != NULL) {
     362           0 :                         nt_hashes[idx++] = &info->older_password->nt_hash;
     363             :                 }
     364             : 
     365             :                 /*
     366             :                  * We use the password that's already persistent in
     367             :                  * our database in order to handle failures.
     368             :                  */
     369           6 :                 data_blob_free(&new_trust_pw_blob);
     370           6 :                 new_trust_pw_blob = info->next_change->password->cleartext_blob;
     371           6 :                 break;
     372             : 
     373           0 :         case SEC_CHAN_DNS_DOMAIN:
     374             :         case SEC_CHAN_DOMAIN:
     375           0 :                 idx_current = idx;
     376           0 :                 nt_hashes[idx++] = current_nt_hash;
     377           0 :                 if (previous_nt_hash != NULL) {
     378           0 :                         nt_hashes[idx++] = previous_nt_hash;
     379             :                 }
     380           0 :                 break;
     381             : 
     382           0 :         default:
     383           0 :                 smb_panic("Unsupported secure channel type");
     384           0 :                 break;
     385             :         }
     386           6 :         num_nt_hashes = idx;
     387             : 
     388           6 :         DEBUG(0,("%s : %s(%s): Verifying passwords remotely %s.\n",
     389             :                  current_timestring(talloc_tos(), false),
     390             :                  __func__, domain, context_name));
     391             : 
     392             :         /*
     393             :          * Check which password the dc knows about.
     394             :          *
     395             :          * TODO:
     396             :          * If the previous password is the only password in common with the dc,
     397             :          * we better skip the password change, or use something like
     398             :          * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
     399             :          * local secrets before doing the change.
     400             :          */
     401           6 :         status = netlogon_creds_cli_lck_auth(context, b,
     402             :                                              num_nt_hashes,
     403             :                                              nt_hashes,
     404             :                                              &idx_nt_hashes);
     405           6 :         if (!NT_STATUS_IS_OK(status)) {
     406           0 :                 DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old passwords (%u) - %s!\n",
     407             :                           context_name, num_nt_hashes, nt_errstr(status)));
     408           0 :                 TALLOC_FREE(frame);
     409           0 :                 return status;
     410             :         }
     411             : 
     412           6 :         if (prev != NULL && idx_nt_hashes == 0) {
     413           0 :                 DEBUG(0,("%s : %s(%s): Verified new password remotely "
     414             :                          "without changing %s\n",
     415             :                          current_timestring(talloc_tos(), false),
     416             :                          __func__, domain, context_name));
     417             : 
     418           0 :                 status = secrets_finish_password_change(prev->password->change_server,
     419           0 :                                                         prev->password->change_time,
     420             :                                                         info);
     421           0 :                 if (!NT_STATUS_IS_OK(status)) {
     422           0 :                         DEBUG(0, ("secrets_prepare_password_change() failed for domain %s!\n",
     423             :                                   domain));
     424           0 :                         TALLOC_FREE(frame);
     425           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     426             :                 }
     427             : 
     428           0 :                 DEBUG(0,("%s : %s(%s): Recovered previous password change.\n",
     429             :                          current_timestring(talloc_tos(), false),
     430             :                          __func__, domain));
     431           0 :                 TALLOC_FREE(frame);
     432           0 :                 return NT_STATUS_OK;
     433             :         }
     434             : 
     435           6 :         if (idx_nt_hashes != idx_current) {
     436           0 :                 DEBUG(0,("%s : %s(%s): Verified older password remotely "
     437             :                          "skip changing %s\n",
     438             :                          current_timestring(talloc_tos(), false),
     439             :                          __func__, domain, context_name));
     440             : 
     441           0 :                 if (info == NULL) {
     442           0 :                         TALLOC_FREE(frame);
     443           0 :                         return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     444             :                 }
     445             : 
     446           0 :                 status = secrets_defer_password_change(dcname,
     447           0 :                                         NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE,
     448           0 :                                         NT_STATUS_NOT_COMMITTED,
     449             :                                         info);
     450           0 :                 if (!NT_STATUS_IS_OK(status)) {
     451           0 :                         DEBUG(0, ("secrets_defer_password_change() failed for domain %s!\n",
     452             :                                   domain));
     453           0 :                         TALLOC_FREE(frame);
     454           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     455             :                 }
     456           0 :                 TALLOC_FREE(frame);
     457           0 :                 return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     458             :         }
     459             : 
     460           6 :         DEBUG(0,("%s : %s(%s): Verified old password remotely using %s\n",
     461             :                  current_timestring(talloc_tos(), false),
     462             :                  __func__, domain, context_name));
     463             : 
     464             :         /*
     465             :          * Return the result of trying to write the new password
     466             :          * back into the trust account file.
     467             :          */
     468             : 
     469           6 :         switch (sec_channel_type) {
     470             : 
     471           6 :         case SEC_CHAN_WKSTA:
     472             :         case SEC_CHAN_BDC:
     473             :                 /*
     474             :                  * we called secrets_prepare_password_change() above.
     475             :                  */
     476           6 :                 break;
     477             : 
     478           0 :         case SEC_CHAN_DNS_DOMAIN:
     479             :         case SEC_CHAN_DOMAIN:
     480             :                 /*
     481             :                  * we need to get the sid first for the
     482             :                  * pdb_set_trusteddom_pw call
     483             :                  */
     484           0 :                 ok = pdb_set_trusteddom_pw(domain, new_trust_pw_str,
     485           0 :                                            &td->security_identifier);
     486           0 :                 if (!ok) {
     487           0 :                         DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
     488             :                                   domain));
     489           0 :                         TALLOC_FREE(frame);
     490           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     491             :                 }
     492           0 :                 TALLOC_FREE(new_trust_pw_str);
     493           0 :                 break;
     494             : 
     495           0 :         default:
     496           0 :                 smb_panic("Unsupported secure channel type");
     497           0 :                 break;
     498             :         }
     499             : 
     500           6 :         DEBUG(0,("%s : %s(%s): Changed password locally\n",
     501             :                  current_timestring(talloc_tos(), false), __func__, domain));
     502             : 
     503           6 :         status = netlogon_creds_cli_ServerPasswordSet(context, b,
     504             :                                                       &new_trust_pw_blob,
     505             :                                                       new_trust_version);
     506           6 :         if (!NT_STATUS_IS_OK(status)) {
     507           0 :                 NTSTATUS status2;
     508           0 :                 const char *fn = NULL;
     509             : 
     510           0 :                 ok = dcerpc_binding_handle_is_connected(b);
     511             : 
     512           0 :                 DEBUG(0,("%s : %s(%s) remote password change with %s failed "
     513             :                          "- %s (%s)\n",
     514             :                          current_timestring(talloc_tos(), false),
     515             :                          __func__, domain, context_name,
     516             :                          nt_errstr(status),
     517             :                          ok ? "connected": "disconnected"));
     518             : 
     519           0 :                 if (!ok) {
     520             :                         /*
     521             :                          * The connection is broken, we don't
     522             :                          * know if the password was changed,
     523             :                          * we hope to have more luck next time.
     524             :                          */
     525           0 :                         status2 = secrets_failed_password_change(dcname,
     526           0 :                                                         NT_STATUS_NOT_COMMITTED,
     527             :                                                         status,
     528             :                                                         info);
     529           0 :                         fn = "secrets_failed_password_change";
     530             :                 } else {
     531             :                         /*
     532             :                          * The server rejected the change, we don't
     533             :                          * retry and defer the change to the next
     534             :                          * "machine password timeout" interval.
     535             :                          */
     536           0 :                         status2 = secrets_defer_password_change(dcname,
     537           0 :                                                         NT_STATUS_NOT_COMMITTED,
     538             :                                                         status,
     539             :                                                         info);
     540           0 :                         fn = "secrets_defer_password_change";
     541             :                 }
     542           0 :                 if (!NT_STATUS_IS_OK(status2)) {
     543           0 :                         DEBUG(0, ("%s() failed for domain %s!\n",
     544             :                                   fn, domain));
     545           0 :                         TALLOC_FREE(frame);
     546           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     547             :                 }
     548             : 
     549           0 :                 TALLOC_FREE(frame);
     550           0 :                 return status;
     551             :         }
     552             : 
     553           6 :         DEBUG(0,("%s : %s(%s): Changed password remotely using %s\n",
     554             :                  current_timestring(talloc_tos(), false),
     555             :                  __func__, domain, context_name));
     556             : 
     557           6 :         switch (sec_channel_type) {
     558             : 
     559           6 :         case SEC_CHAN_WKSTA:
     560             :         case SEC_CHAN_BDC:
     561           6 :                 status = secrets_finish_password_change(
     562           6 :                                         info->next_change->change_server,
     563           6 :                                         info->next_change->change_time,
     564             :                                         info);
     565           6 :                 if (!NT_STATUS_IS_OK(status)) {
     566           0 :                         DEBUG(0, ("secrets_finish_password_change() failed for domain %s!\n",
     567             :                                   domain));
     568           0 :                         TALLOC_FREE(frame);
     569           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     570             :                 }
     571             : 
     572           6 :                 DEBUG(0,("%s : %s(%s): Finished password change.\n",
     573             :                          current_timestring(talloc_tos(), false),
     574             :                          __func__, domain));
     575           6 :                 break;
     576             : 
     577           0 :         case SEC_CHAN_DNS_DOMAIN:
     578             :         case SEC_CHAN_DOMAIN:
     579             :                 /*
     580             :                  * we used pdb_set_trusteddom_pw().
     581             :                  */
     582           0 :                 break;
     583             : 
     584           0 :         default:
     585           0 :                 smb_panic("Unsupported secure channel type");
     586           0 :                 break;
     587             :         }
     588             : 
     589           6 :         ok = cli_credentials_set_utf16_password(creds,
     590             :                                                 &new_trust_pw_blob,
     591             :                                                 CRED_SPECIFIED);
     592           6 :         if (!ok) {
     593           0 :                 DEBUG(0, ("cli_credentials_set_password failed for domain %s!\n",
     594             :                           domain));
     595           0 :                 TALLOC_FREE(frame);
     596           0 :                 return NT_STATUS_NO_MEMORY;
     597             :         }
     598             : 
     599           6 :         current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
     600           6 :         if (current_nt_hash == NULL) {
     601           0 :                 DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
     602             :                           domain));
     603           0 :                 TALLOC_FREE(frame);
     604           0 :                 return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
     605             :         }
     606             : 
     607             :         /*
     608             :          * Now we verify the new password.
     609             :          */
     610           6 :         idx = 0;
     611           6 :         nt_hashes[idx++] = current_nt_hash;
     612           6 :         num_nt_hashes = idx;
     613           6 :         status = netlogon_creds_cli_lck_auth(context, b,
     614             :                                              num_nt_hashes,
     615             :                                              nt_hashes,
     616             :                                              &idx_nt_hashes);
     617           6 :         if (!NT_STATUS_IS_OK(status)) {
     618           0 :                 DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for new password - %s!\n",
     619             :                           context_name, nt_errstr(status)));
     620           0 :                 TALLOC_FREE(frame);
     621           0 :                 return status;
     622             :         }
     623             : 
     624           6 :         DEBUG(0,("%s : %s(%s): Verified new password remotely using %s\n",
     625             :                  current_timestring(talloc_tos(), false),
     626             :                  __func__, domain, context_name));
     627             : 
     628           6 :         TALLOC_FREE(frame);
     629           6 :         return NT_STATUS_OK;
     630             : }

Generated by: LCOV version 1.14