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 : }
|