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 ourselfs. 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 0 : static int trust_pw_change_state_destructor(struct trust_pw_change_state *state)
47 : {
48 0 : g_lock_unlock(state->g_ctx,
49 0 : string_term_tdb_data(state->g_lock_key));
50 0 : return 0;
51 : }
52 :
53 28 : 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 28 : size_t min = 120;
69 28 : size_t max = 120;
70 :
71 28 : switch (sec_channel_type) {
72 28 : case SEC_CHAN_WKSTA:
73 : case SEC_CHAN_BDC:
74 28 : 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 2 : min = 14;
81 2 : max = 14;
82 : }
83 28 : 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 28 : 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 0 : 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 : struct netlogon_creds_cli_lck *lck;
128 : NTSTATUS status;
129 :
130 0 : status = netlogon_creds_cli_lck(
131 : context, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
132 : talloc_tos(), &lck);
133 0 : 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 0 : status = netlogon_creds_cli_auth(context, b, num_nt_hashes, nt_hashes,
140 : idx_nt_hashes);
141 0 : TALLOC_FREE(lck);
142 :
143 0 : return status;
144 : }
145 :
146 0 : 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 0 : TALLOC_CTX *frame = talloc_stackframe();
154 0 : const char *context_name = NULL;
155 : struct trust_pw_change_state *state;
156 0 : struct cli_credentials *creds = NULL;
157 0 : struct secrets_domain_info1 *info = NULL;
158 0 : struct secrets_domain_info1_change *prev = NULL;
159 0 : const struct samr_Password *current_nt_hash = NULL;
160 0 : const struct samr_Password *previous_nt_hash = NULL;
161 0 : uint8_t num_nt_hashes = 0;
162 0 : uint8_t idx = 0;
163 0 : const struct samr_Password *nt_hashes[1+3] = { NULL, };
164 0 : uint8_t idx_nt_hashes = 0;
165 0 : uint8_t idx_current = UINT8_MAX;
166 0 : enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
167 : time_t pass_last_set_time;
168 0 : uint32_t old_version = 0;
169 0 : struct pdb_trusted_domain *td = NULL;
170 0 : struct timeval g_timeout = { 0, };
171 0 : int timeout = 0;
172 0 : struct timeval tv = { 0, };
173 0 : char *new_trust_pw_str = NULL;
174 0 : size_t len = 0;
175 0 : DATA_BLOB new_trust_pw_blob = data_blob_null;
176 0 : uint32_t new_version = 0;
177 0 : uint32_t *new_trust_version = NULL;
178 : NTSTATUS status;
179 : bool ok;
180 :
181 0 : state = talloc_zero(frame, struct trust_pw_change_state);
182 0 : if (state == NULL) {
183 0 : TALLOC_FREE(frame);
184 0 : return NT_STATUS_NO_MEMORY;
185 : }
186 :
187 0 : state->g_ctx = g_lock_ctx_init(state, msg_ctx);
188 0 : if (state->g_ctx == NULL) {
189 0 : TALLOC_FREE(frame);
190 0 : return NT_STATUS_NO_MEMORY;
191 : }
192 :
193 0 : state->g_lock_key = talloc_asprintf(state,
194 : "trust_password_change_%s",
195 : domain);
196 0 : if (state->g_lock_key == NULL) {
197 0 : TALLOC_FREE(frame);
198 0 : return NT_STATUS_NO_MEMORY;
199 : }
200 :
201 0 : g_timeout = timeval_current_ofs(10, 0);
202 0 : status = g_lock_lock(state->g_ctx,
203 0 : string_term_tdb_data(state->g_lock_key),
204 : G_LOCK_WRITE, g_timeout);
205 0 : 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 0 : talloc_set_destructor(state, trust_pw_change_state_destructor);
213 :
214 0 : status = pdb_get_trust_credentials(domain, NULL, frame, &creds);
215 0 : 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 0 : current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
223 0 : 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 0 : previous_nt_hash = cli_credentials_get_old_nt_hash(creds, frame);
230 :
231 0 : old_version = cli_credentials_get_kvno(creds);
232 0 : pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
233 0 : sec_channel_type = cli_credentials_get_secure_channel_type(creds);
234 :
235 0 : new_version = old_version + 1;
236 :
237 0 : switch (sec_channel_type) {
238 0 : case SEC_CHAN_WKSTA:
239 : case SEC_CHAN_BDC:
240 0 : 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 0 : timeout = lp_machine_password_timeout();
259 0 : 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 0 : tv.tv_sec = pass_last_set_time;
268 0 : DEBUG(10, ("password last changed %s\n",
269 : timeval_string(talloc_tos(), &tv, false)));
270 0 : tv.tv_sec += timeout;
271 0 : DEBUGADD(10, ("password valid until %s\n",
272 : timeval_string(talloc_tos(), &tv, false)));
273 :
274 0 : if (!force && !timeval_expired(&tv)) {
275 0 : TALLOC_FREE(frame);
276 0 : return NT_STATUS_OK;
277 : }
278 :
279 0 : context_name = netlogon_creds_cli_debug_string(context, talloc_tos());
280 0 : 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 0 : new_trust_pw_str = trust_pw_new_value(frame, sec_channel_type,
291 : lp_security());
292 0 : 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 0 : len = strlen(new_trust_pw_str);
299 0 : 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 0 : 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 :
315 0 : switch (sec_channel_type) {
316 :
317 0 : case SEC_CHAN_WKSTA:
318 : case SEC_CHAN_BDC:
319 0 : status = secrets_prepare_password_change(domain, dcname,
320 : new_trust_pw_str,
321 : frame, &info, &prev);
322 0 : if (!NT_STATUS_IS_OK(status)) {
323 0 : DEBUG(0, ("secrets_prepare_password_change() failed for domain %s!\n",
324 : domain));
325 0 : TALLOC_FREE(frame);
326 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
327 : }
328 0 : TALLOC_FREE(new_trust_pw_str);
329 :
330 0 : if (prev != NULL) {
331 : /*
332 : * We had a failure before we changed the password.
333 : */
334 0 : nt_hashes[idx++] = &prev->password->nt_hash;
335 :
336 0 : DEBUG(0,("%s : %s(%s): A password change was already "
337 : "started against '%s' at %s. Trying to "
338 : "recover...\n",
339 : current_timestring(talloc_tos(), false),
340 : __func__, domain,
341 : prev->password->change_server,
342 : nt_time_string(talloc_tos(),
343 : prev->password->change_time)));
344 0 : DEBUG(0,("%s : %s(%s): Last failure local[%s] remote[%s] "
345 : "against '%s' at %s.\n",
346 : current_timestring(talloc_tos(), false),
347 : __func__, domain,
348 : nt_errstr(prev->local_status),
349 : nt_errstr(prev->remote_status),
350 : prev->change_server,
351 : nt_time_string(talloc_tos(),
352 : prev->change_time)));
353 : }
354 :
355 0 : idx_current = idx;
356 0 : nt_hashes[idx++] = &info->password->nt_hash;
357 0 : if (info->old_password != NULL) {
358 0 : nt_hashes[idx++] = &info->old_password->nt_hash;
359 : }
360 0 : if (info->older_password != NULL) {
361 0 : nt_hashes[idx++] = &info->older_password->nt_hash;
362 : }
363 :
364 : /*
365 : * We use the password that's already persistent in
366 : * our database in order to handle failures.
367 : */
368 0 : data_blob_clear_free(&new_trust_pw_blob);
369 0 : new_trust_pw_blob = info->next_change->password->cleartext_blob;
370 0 : break;
371 :
372 0 : case SEC_CHAN_DNS_DOMAIN:
373 : case SEC_CHAN_DOMAIN:
374 0 : idx_current = idx;
375 0 : nt_hashes[idx++] = current_nt_hash;
376 0 : if (previous_nt_hash != NULL) {
377 0 : nt_hashes[idx++] = previous_nt_hash;
378 : }
379 0 : break;
380 :
381 0 : default:
382 0 : smb_panic("Unsupported secure channel type");
383 : break;
384 : }
385 0 : num_nt_hashes = idx;
386 :
387 0 : DEBUG(0,("%s : %s(%s): Verifying passwords remotely %s.\n",
388 : current_timestring(talloc_tos(), false),
389 : __func__, domain, context_name));
390 :
391 : /*
392 : * Check which password the dc knows about.
393 : *
394 : * TODO:
395 : * If the previous password is the only password in common with the dc,
396 : * we better skip the password change, or use something like
397 : * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
398 : * local secrets before doing the change.
399 : */
400 0 : status = netlogon_creds_cli_lck_auth(context, b,
401 : num_nt_hashes,
402 : nt_hashes,
403 : &idx_nt_hashes);
404 0 : if (!NT_STATUS_IS_OK(status)) {
405 0 : DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old passwords (%u) - %s!\n",
406 : context_name, num_nt_hashes, nt_errstr(status)));
407 0 : TALLOC_FREE(frame);
408 0 : return status;
409 : }
410 :
411 0 : if (prev != NULL && idx_nt_hashes == 0) {
412 0 : DEBUG(0,("%s : %s(%s): Verified new password remotely "
413 : "without changing %s\n",
414 : current_timestring(talloc_tos(), false),
415 : __func__, domain, context_name));
416 :
417 0 : status = secrets_finish_password_change(prev->password->change_server,
418 0 : prev->password->change_time,
419 : info);
420 0 : if (!NT_STATUS_IS_OK(status)) {
421 0 : DEBUG(0, ("secrets_prepare_password_change() failed for domain %s!\n",
422 : domain));
423 0 : TALLOC_FREE(frame);
424 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
425 : }
426 :
427 0 : DEBUG(0,("%s : %s(%s): Recovered previous password change.\n",
428 : current_timestring(talloc_tos(), false),
429 : __func__, domain));
430 0 : TALLOC_FREE(frame);
431 0 : return NT_STATUS_OK;
432 : }
433 :
434 0 : if (idx_nt_hashes != idx_current) {
435 0 : DEBUG(0,("%s : %s(%s): Verified older password remotely "
436 : "skip changing %s\n",
437 : current_timestring(talloc_tos(), false),
438 : __func__, domain, context_name));
439 :
440 0 : if (info == NULL) {
441 0 : TALLOC_FREE(frame);
442 0 : return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
443 : }
444 :
445 0 : status = secrets_defer_password_change(dcname,
446 0 : NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE,
447 0 : NT_STATUS_NOT_COMMITTED,
448 : info);
449 0 : if (!NT_STATUS_IS_OK(status)) {
450 0 : DEBUG(0, ("secrets_defer_password_change() failed for domain %s!\n",
451 : domain));
452 0 : TALLOC_FREE(frame);
453 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
454 : }
455 0 : TALLOC_FREE(frame);
456 0 : return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
457 : }
458 :
459 0 : DEBUG(0,("%s : %s(%s): Verified old password remotely using %s\n",
460 : current_timestring(talloc_tos(), false),
461 : __func__, domain, context_name));
462 :
463 : /*
464 : * Return the result of trying to write the new password
465 : * back into the trust account file.
466 : */
467 :
468 0 : switch (sec_channel_type) {
469 :
470 0 : case SEC_CHAN_WKSTA:
471 : case SEC_CHAN_BDC:
472 : /*
473 : * we called secrets_prepare_password_change() above.
474 : */
475 0 : break;
476 :
477 0 : case SEC_CHAN_DNS_DOMAIN:
478 : case SEC_CHAN_DOMAIN:
479 : /*
480 : * we need to get the sid first for the
481 : * pdb_set_trusteddom_pw call
482 : */
483 0 : ok = pdb_set_trusteddom_pw(domain, new_trust_pw_str,
484 0 : &td->security_identifier);
485 0 : if (!ok) {
486 0 : DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
487 : domain));
488 0 : TALLOC_FREE(frame);
489 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
490 : }
491 0 : TALLOC_FREE(new_trust_pw_str);
492 0 : break;
493 :
494 0 : default:
495 0 : smb_panic("Unsupported secure channel type");
496 : break;
497 : }
498 :
499 0 : DEBUG(0,("%s : %s(%s): Changed password locally\n",
500 : current_timestring(talloc_tos(), false), __func__, domain));
501 :
502 0 : status = netlogon_creds_cli_ServerPasswordSet(context, b,
503 : &new_trust_pw_blob,
504 : new_trust_version);
505 0 : if (!NT_STATUS_IS_OK(status)) {
506 : NTSTATUS status2;
507 0 : const char *fn = NULL;
508 :
509 0 : ok = dcerpc_binding_handle_is_connected(b);
510 :
511 0 : DEBUG(0,("%s : %s(%s) remote password change with %s failed "
512 : "- %s (%s)\n",
513 : current_timestring(talloc_tos(), false),
514 : __func__, domain, context_name,
515 : nt_errstr(status),
516 : ok ? "connected": "disconnected"));
517 :
518 0 : if (!ok) {
519 : /*
520 : * The connection is broken, we don't
521 : * know if the password was changed,
522 : * we hope to have more luck next time.
523 : */
524 0 : status2 = secrets_failed_password_change(dcname,
525 0 : NT_STATUS_NOT_COMMITTED,
526 : status,
527 : info);
528 0 : fn = "secrets_failed_password_change";
529 : } else {
530 : /*
531 : * The server rejected the change, we don't
532 : * retry and defer the change to the next
533 : * "machine password timeout" interval.
534 : */
535 0 : status2 = secrets_defer_password_change(dcname,
536 0 : NT_STATUS_NOT_COMMITTED,
537 : status,
538 : info);
539 0 : fn = "secrets_defer_password_change";
540 : }
541 0 : if (!NT_STATUS_IS_OK(status2)) {
542 0 : DEBUG(0, ("%s() failed for domain %s!\n",
543 : fn, domain));
544 0 : TALLOC_FREE(frame);
545 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
546 : }
547 :
548 0 : TALLOC_FREE(frame);
549 0 : return status;
550 : }
551 :
552 0 : DEBUG(0,("%s : %s(%s): Changed password remotely using %s\n",
553 : current_timestring(talloc_tos(), false),
554 : __func__, domain, context_name));
555 :
556 0 : switch (sec_channel_type) {
557 :
558 0 : case SEC_CHAN_WKSTA:
559 : case SEC_CHAN_BDC:
560 0 : status = secrets_finish_password_change(
561 0 : info->next_change->change_server,
562 0 : info->next_change->change_time,
563 : info);
564 0 : if (!NT_STATUS_IS_OK(status)) {
565 0 : DEBUG(0, ("secrets_finish_password_change() failed for domain %s!\n",
566 : domain));
567 0 : TALLOC_FREE(frame);
568 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
569 : }
570 :
571 0 : DEBUG(0,("%s : %s(%s): Finished password change.\n",
572 : current_timestring(talloc_tos(), false),
573 : __func__, domain));
574 0 : break;
575 :
576 0 : case SEC_CHAN_DNS_DOMAIN:
577 : case SEC_CHAN_DOMAIN:
578 : /*
579 : * we used pdb_set_trusteddom_pw().
580 : */
581 0 : break;
582 :
583 0 : default:
584 0 : smb_panic("Unsupported secure channel type");
585 : break;
586 : }
587 :
588 0 : ok = cli_credentials_set_utf16_password(creds,
589 : &new_trust_pw_blob,
590 : CRED_SPECIFIED);
591 0 : if (!ok) {
592 0 : DEBUG(0, ("cli_credentials_set_password failed for domain %s!\n",
593 : domain));
594 0 : TALLOC_FREE(frame);
595 0 : return NT_STATUS_NO_MEMORY;
596 : }
597 :
598 0 : current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
599 0 : if (current_nt_hash == NULL) {
600 0 : DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
601 : domain));
602 0 : TALLOC_FREE(frame);
603 0 : return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
604 : }
605 :
606 : /*
607 : * Now we verify the new password.
608 : */
609 0 : idx = 0;
610 0 : nt_hashes[idx++] = current_nt_hash;
611 0 : num_nt_hashes = idx;
612 0 : status = netlogon_creds_cli_lck_auth(context, b,
613 : num_nt_hashes,
614 : nt_hashes,
615 : &idx_nt_hashes);
616 0 : if (!NT_STATUS_IS_OK(status)) {
617 0 : DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for new password - %s!\n",
618 : context_name, nt_errstr(status)));
619 0 : TALLOC_FREE(frame);
620 0 : return status;
621 : }
622 :
623 0 : DEBUG(0,("%s : %s(%s): Verified new password remotely using %s\n",
624 : current_timestring(talloc_tos(), false),
625 : __func__, domain, context_name));
626 :
627 0 : TALLOC_FREE(frame);
628 0 : return NT_STATUS_OK;
629 : }
|