winbindd: force netlogon reauth for certain errors in reset_cm_connection_on_error()
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob10345fb81d24b63ca0d939ec82ccc9749a774427
1 /*
2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
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.
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.
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/>.
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "ntdomain.h"
28 #include "librpc/gen_ndr/srv_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
31 #include "idmap.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
34 #include "passdb.h"
35 #include "../source4/dsdb/samdb/samdb.h"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
39 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
41 *r->out.out_data = r->in.in_data;
44 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
45 NTSTATUS status)
47 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
48 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
49 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
50 invalidate_cm_connection(domain);
51 domain->conn.netlogon_force_reauth = true;
52 return true;
55 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
56 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
58 invalidate_cm_connection(domain);
59 /* We invalidated the connection. */
60 return true;
62 return false;
65 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
67 struct winbindd_domain *domain = wb_child_domain();
68 char *dom_name;
69 char *name;
70 enum lsa_SidType type;
71 NTSTATUS status;
73 if (domain == NULL) {
74 return NT_STATUS_REQUEST_NOT_ACCEPTED;
77 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
78 &dom_name, &name, &type);
79 reset_cm_connection_on_error(domain, status);
80 if (!NT_STATUS_IS_OK(status)) {
81 return status;
84 *r->out.domain = dom_name;
85 *r->out.name = name;
86 *r->out.type = type;
87 return NT_STATUS_OK;
90 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
92 struct winbindd_domain *domain = wb_child_domain();
93 struct lsa_RefDomainList *domains = r->out.domains;
94 NTSTATUS status;
96 if (domain == NULL) {
97 return NT_STATUS_REQUEST_NOT_ACCEPTED;
101 * This breaks the winbindd_domain->methods abstraction: This
102 * is only called for remote domains, and both winbindd_msrpc
103 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
104 * done at the wbint RPC layer.
106 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
107 &domains, &r->out.names);
109 if (domains != NULL) {
110 r->out.domains = domains;
113 reset_cm_connection_on_error(domain, status);
114 return status;
117 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
119 struct winbindd_domain *domain = wb_child_domain();
120 NTSTATUS status;
122 if (domain == NULL) {
123 return NT_STATUS_REQUEST_NOT_ACCEPTED;
126 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
127 r->in.name, r->in.flags,
128 r->out.sid, r->out.type);
129 reset_cm_connection_on_error(domain, status);
130 return status;
133 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
134 struct wbint_Sids2UnixIDs *r)
136 uint32_t i;
138 struct lsa_DomainInfo *d;
139 struct wbint_TransID *ids;
140 uint32_t num_ids;
142 struct id_map **id_map_ptrs = NULL;
143 struct idmap_domain *dom;
144 NTSTATUS status = NT_STATUS_NO_MEMORY;
146 if (r->in.domains->count != 1) {
147 return NT_STATUS_INVALID_PARAMETER;
150 d = &r->in.domains->domains[0];
151 ids = r->in.ids->ids;
152 num_ids = r->in.ids->num_ids;
154 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
155 if (dom == NULL) {
156 DEBUG(10, ("idmap domain %s:%s not found\n",
157 d->name.string, sid_string_dbg(d->sid)));
159 for (i=0; i<num_ids; i++) {
161 ids[i].xid = (struct unixid) {
162 .id = UINT32_MAX,
163 .type = ID_TYPE_NOT_SPECIFIED
167 return NT_STATUS_OK;
170 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
171 if (id_map_ptrs == NULL) {
172 goto nomem;
176 * Convert the input data into a list of id_map structs
177 * suitable for handing in to the idmap sids_to_unixids
178 * method.
181 for (i=0; i<num_ids; i++) {
182 struct id_map *m = id_map_ptrs[i];
184 sid_compose(m->sid, d->sid, ids[i].rid);
185 m->status = ID_UNKNOWN;
186 m->xid = (struct unixid) { .type = ids[i].type };
189 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
191 if (!NT_STATUS_IS_OK(status)) {
192 DEBUG(10, ("sids_to_unixids returned %s\n",
193 nt_errstr(status)));
194 goto done;
198 * Extract the results for handing them back to the caller.
201 for (i=0; i<num_ids; i++) {
202 struct id_map *m = id_map_ptrs[i];
204 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
205 DBG_DEBUG("id %"PRIu32" is out of range "
206 "%"PRIu32"-%"PRIu32" for domain %s\n",
207 m->xid.id, dom->low_id, dom->high_id,
208 dom->name);
209 m->status = ID_UNMAPPED;
212 if (m->status == ID_MAPPED) {
213 ids[i].xid = m->xid;
214 } else {
215 ids[i].xid.id = UINT32_MAX;
216 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
220 goto done;
221 nomem:
222 status = NT_STATUS_NO_MEMORY;
223 done:
224 TALLOC_FREE(id_map_ptrs);
225 return status;
228 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
229 struct wbint_UnixIDs2Sids *r)
231 struct id_map **maps;
232 NTSTATUS status;
233 uint32_t i;
235 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
236 if (maps == NULL) {
237 return NT_STATUS_NO_MEMORY;
240 for (i=0; i<r->in.num_ids; i++) {
241 maps[i]->status = ID_UNKNOWN;
242 maps[i]->xid = r->in.xids[i];
245 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
246 r->in.domain_sid);
247 if (!NT_STATUS_IS_OK(status)) {
248 TALLOC_FREE(maps);
249 return status;
252 for (i=0; i<r->in.num_ids; i++) {
253 r->out.xids[i] = maps[i]->xid;
254 sid_copy(&r->out.sids[i], maps[i]->sid);
257 TALLOC_FREE(maps);
259 return NT_STATUS_OK;
262 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
264 struct unixid xid;
265 NTSTATUS status;
267 status = idmap_allocate_uid(&xid);
268 if (!NT_STATUS_IS_OK(status)) {
269 return status;
271 *r->out.uid = xid.id;
272 return NT_STATUS_OK;
275 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
277 struct unixid xid;
278 NTSTATUS status;
280 status = idmap_allocate_gid(&xid);
281 if (!NT_STATUS_IS_OK(status)) {
282 return status;
284 *r->out.gid = xid.id;
285 return NT_STATUS_OK;
288 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
290 struct idmap_domain *domain;
291 NTSTATUS status;
293 domain = idmap_find_domain(r->in.info->domain_name);
294 if ((domain == NULL) || (domain->query_user == NULL)) {
295 return NT_STATUS_REQUEST_NOT_ACCEPTED;
298 status = domain->query_user(domain, r->in.info);
299 return status;
302 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
303 struct wbint_LookupUserAliases *r)
305 struct winbindd_domain *domain = wb_child_domain();
306 NTSTATUS status;
308 if (domain == NULL) {
309 return NT_STATUS_REQUEST_NOT_ACCEPTED;
312 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
313 r->in.sids->num_sids,
314 r->in.sids->sids,
315 &r->out.rids->num_rids,
316 &r->out.rids->rids);
317 reset_cm_connection_on_error(domain, status);
318 return status;
321 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
322 struct wbint_LookupUserGroups *r)
324 struct winbindd_domain *domain = wb_child_domain();
325 NTSTATUS status;
327 if (domain == NULL) {
328 return NT_STATUS_REQUEST_NOT_ACCEPTED;
331 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
332 &r->out.sids->num_sids,
333 &r->out.sids->sids);
334 reset_cm_connection_on_error(domain, status);
335 return status;
338 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
339 struct wbint_QuerySequenceNumber *r)
341 struct winbindd_domain *domain = wb_child_domain();
342 NTSTATUS status;
344 if (domain == NULL) {
345 return NT_STATUS_REQUEST_NOT_ACCEPTED;
348 status = wb_cache_sequence_number(domain, r->out.sequence);
349 reset_cm_connection_on_error(domain, status);
350 return status;
353 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
354 struct wbint_LookupGroupMembers *r)
356 struct winbindd_domain *domain = wb_child_domain();
357 uint32_t i, num_names;
358 struct dom_sid *sid_mem;
359 char **names;
360 uint32_t *name_types;
361 NTSTATUS status;
363 if (domain == NULL) {
364 return NT_STATUS_REQUEST_NOT_ACCEPTED;
367 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
368 r->in.type, &num_names, &sid_mem,
369 &names, &name_types);
370 reset_cm_connection_on_error(domain, status);
371 if (!NT_STATUS_IS_OK(status)) {
372 return status;
375 r->out.members->num_principals = num_names;
376 r->out.members->principals = talloc_array(
377 r->out.members, struct wbint_Principal, num_names);
378 if (r->out.members->principals == NULL) {
379 return NT_STATUS_NO_MEMORY;
382 for (i=0; i<num_names; i++) {
383 struct wbint_Principal *m = &r->out.members->principals[i];
384 sid_copy(&m->sid, &sid_mem[i]);
385 m->name = talloc_move(r->out.members->principals, &names[i]);
386 m->type = (enum lsa_SidType)name_types[i];
389 return NT_STATUS_OK;
392 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
393 struct wbint_QueryGroupList *r)
395 TALLOC_CTX *frame = NULL;
396 struct winbindd_domain *domain = wb_child_domain();
397 uint32_t i;
398 uint32_t num_local_groups = 0;
399 struct wb_acct_info *local_groups = NULL;
400 uint32_t num_dom_groups = 0;
401 struct wb_acct_info *dom_groups = NULL;
402 uint32_t ti = 0;
403 uint64_t num_total = 0;
404 struct wbint_Principal *result;
405 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
406 bool include_local_groups = false;
408 if (domain == NULL) {
409 return NT_STATUS_REQUEST_NOT_ACCEPTED;
412 frame = talloc_stackframe();
414 switch (lp_server_role()) {
415 case ROLE_ACTIVE_DIRECTORY_DC:
416 if (domain->internal) {
418 * we want to include local groups
419 * for BUILTIN and WORKGROUP
421 include_local_groups = true;
423 break;
424 default:
426 * We might include local groups in more
427 * setups later, but that requires more work
428 * elsewhere.
430 break;
433 if (include_local_groups) {
434 status = wb_cache_enum_local_groups(domain, frame,
435 &num_local_groups,
436 &local_groups);
437 reset_cm_connection_on_error(domain, status);
438 if (!NT_STATUS_IS_OK(status)) {
439 goto out;
443 status = wb_cache_enum_dom_groups(domain, frame,
444 &num_dom_groups,
445 &dom_groups);
446 reset_cm_connection_on_error(domain, status);
447 if (!NT_STATUS_IS_OK(status)) {
448 goto out;
451 num_total = num_local_groups + num_dom_groups;
452 if (num_total > UINT32_MAX) {
453 status = NT_STATUS_INTERNAL_ERROR;
454 goto out;
457 result = talloc_array(frame, struct wbint_Principal, num_total);
458 if (result == NULL) {
459 status = NT_STATUS_NO_MEMORY;
460 goto out;
463 for (i = 0; i < num_local_groups; i++) {
464 struct wb_acct_info *lg = &local_groups[i];
465 struct wbint_Principal *rg = &result[ti++];
467 sid_compose(&rg->sid, &domain->sid, lg->rid);
468 rg->type = SID_NAME_ALIAS;
469 rg->name = talloc_strdup(result, lg->acct_name);
470 if (rg->name == NULL) {
471 status = NT_STATUS_NO_MEMORY;
472 goto out;
475 num_local_groups = 0;
477 for (i = 0; i < num_dom_groups; i++) {
478 struct wb_acct_info *dg = &dom_groups[i];
479 struct wbint_Principal *rg = &result[ti++];
481 sid_compose(&rg->sid, &domain->sid, dg->rid);
482 rg->type = SID_NAME_DOM_GRP;
483 rg->name = talloc_strdup(result, dg->acct_name);
484 if (rg->name == NULL) {
485 status = NT_STATUS_NO_MEMORY;
486 goto out;
489 num_dom_groups = 0;
491 r->out.groups->num_principals = ti;
492 r->out.groups->principals = talloc_move(r->out.groups, &result);
494 status = NT_STATUS_OK;
495 out:
496 TALLOC_FREE(frame);
497 return status;
500 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
501 struct wbint_QueryUserRidList *r)
503 struct winbindd_domain *domain = wb_child_domain();
504 NTSTATUS status;
506 if (domain == NULL) {
507 return NT_STATUS_REQUEST_NOT_ACCEPTED;
511 * Right now this is overkill. We should add a backend call
512 * just querying the rids.
515 status = wb_cache_query_user_list(domain, p->mem_ctx,
516 &r->out.rids->rids);
517 reset_cm_connection_on_error(domain, status);
519 if (!NT_STATUS_IS_OK(status)) {
520 return status;
523 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
525 return NT_STATUS_OK;
528 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
530 struct winbindd_domain *domain = wb_child_domain();
531 struct rpc_pipe_client *netlogon_pipe;
532 struct netr_DsRGetDCNameInfo *dc_info;
533 NTSTATUS status;
534 WERROR werr;
535 unsigned int orig_timeout;
536 struct dcerpc_binding_handle *b;
538 if (domain == NULL) {
539 return dsgetdcname(p->mem_ctx, server_messaging_context(),
540 r->in.domain_name, r->in.domain_guid,
541 r->in.site_name ? r->in.site_name : "",
542 r->in.flags,
543 r->out.dc_info);
546 status = cm_connect_netlogon(domain, &netlogon_pipe);
548 reset_cm_connection_on_error(domain, status);
549 if (!NT_STATUS_IS_OK(status)) {
550 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
551 return status;
554 b = netlogon_pipe->binding_handle;
556 /* This call can take a long time - allow the server to time out.
557 35 seconds should do it. */
559 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
561 if (domain->active_directory) {
562 status = dcerpc_netr_DsRGetDCName(b,
563 p->mem_ctx, domain->dcname,
564 r->in.domain_name, NULL, r->in.domain_guid,
565 r->in.flags, r->out.dc_info, &werr);
566 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
567 goto done;
569 if (reset_cm_connection_on_error(domain, status)) {
570 /* Re-initialize. */
571 status = cm_connect_netlogon(domain, &netlogon_pipe);
573 reset_cm_connection_on_error(domain, status);
574 if (!NT_STATUS_IS_OK(status)) {
575 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
576 return status;
579 b = netlogon_pipe->binding_handle;
581 /* This call can take a long time - allow the server to time out.
582 35 seconds should do it. */
584 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
589 * Fallback to less capable methods
592 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
593 if (dc_info == NULL) {
594 status = NT_STATUS_NO_MEMORY;
595 goto done;
598 if (r->in.flags & DS_PDC_REQUIRED) {
599 status = dcerpc_netr_GetDcName(b,
600 p->mem_ctx, domain->dcname,
601 r->in.domain_name, &dc_info->dc_unc, &werr);
602 } else {
603 status = dcerpc_netr_GetAnyDCName(b,
604 p->mem_ctx, domain->dcname,
605 r->in.domain_name, &dc_info->dc_unc, &werr);
608 reset_cm_connection_on_error(domain, status);
609 if (!NT_STATUS_IS_OK(status)) {
610 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
611 nt_errstr(status)));
612 goto done;
614 if (!W_ERROR_IS_OK(werr)) {
615 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
616 win_errstr(werr)));
617 status = werror_to_ntstatus(werr);
618 goto done;
621 *r->out.dc_info = dc_info;
622 status = NT_STATUS_OK;
624 done:
625 /* And restore our original timeout. */
626 rpccli_set_timeout(netlogon_pipe, orig_timeout);
628 return status;
631 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
633 struct winbindd_domain *domain = wb_child_domain();
634 char *domain_name;
635 char **names;
636 enum lsa_SidType *types;
637 struct wbint_Principal *result;
638 NTSTATUS status;
639 uint32_t i;
641 if (domain == NULL) {
642 return NT_STATUS_REQUEST_NOT_ACCEPTED;
645 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
646 r->in.rids->rids, r->in.rids->num_rids,
647 &domain_name, &names, &types);
648 reset_cm_connection_on_error(domain, status);
649 if (!NT_STATUS_IS_OK(status)) {
650 return status;
653 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
655 result = talloc_array(p->mem_ctx, struct wbint_Principal,
656 r->in.rids->num_rids);
657 if (result == NULL) {
658 return NT_STATUS_NO_MEMORY;
661 for (i=0; i<r->in.rids->num_rids; i++) {
662 sid_compose(&result[i].sid, r->in.domain_sid,
663 r->in.rids->rids[i]);
664 result[i].type = types[i];
665 result[i].name = talloc_move(result, &names[i]);
667 TALLOC_FREE(types);
668 TALLOC_FREE(names);
670 r->out.names->num_principals = r->in.rids->num_rids;
671 r->out.names->principals = result;
672 return NT_STATUS_OK;
675 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
676 struct wbint_CheckMachineAccount *r)
678 struct winbindd_domain *domain;
679 int num_retries = 0;
680 NTSTATUS status;
682 domain = wb_child_domain();
683 if (domain == NULL) {
684 return NT_STATUS_REQUEST_NOT_ACCEPTED;
687 again:
688 invalidate_cm_connection(domain);
689 domain->conn.netlogon_force_reauth = true;
692 struct rpc_pipe_client *netlogon_pipe = NULL;
693 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
694 status = cm_connect_netlogon_secure(domain,
695 &netlogon_pipe,
696 &netlogon_creds_ctx);
699 /* There is a race condition between fetching the trust account
700 password and the periodic machine password change. So it's
701 possible that the trust account password has been changed on us.
702 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
704 #define MAX_RETRIES 3
706 if ((num_retries < MAX_RETRIES)
707 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
708 num_retries++;
709 goto again;
712 if (!NT_STATUS_IS_OK(status)) {
713 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
714 goto done;
717 /* Pass back result code - zero for success, other values for
718 specific failures. */
720 DEBUG(3,("domain %s secret is %s\n", domain->name,
721 NT_STATUS_IS_OK(status) ? "good" : "bad"));
723 done:
724 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
725 ("Checking the trust account password for domain %s returned %s\n",
726 domain->name, nt_errstr(status)));
728 return status;
731 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
732 struct wbint_ChangeMachineAccount *r)
734 struct messaging_context *msg_ctx = server_messaging_context();
735 struct winbindd_domain *domain;
736 NTSTATUS status;
737 struct rpc_pipe_client *netlogon_pipe = NULL;
738 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
740 domain = wb_child_domain();
741 if (domain == NULL) {
742 return NT_STATUS_REQUEST_NOT_ACCEPTED;
745 status = cm_connect_netlogon_secure(domain,
746 &netlogon_pipe,
747 &netlogon_creds_ctx);
748 if (!NT_STATUS_IS_OK(status)) {
749 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
750 goto done;
753 status = trust_pw_change(netlogon_creds_ctx,
754 msg_ctx,
755 netlogon_pipe->binding_handle,
756 domain->name,
757 domain->dcname,
758 true); /* force */
760 /* Pass back result code - zero for success, other values for
761 specific failures. */
763 DEBUG(3,("domain %s secret %s\n", domain->name,
764 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
766 done:
767 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
768 ("Changing the trust account password for domain %s returned %s\n",
769 domain->name, nt_errstr(status)));
771 return status;
774 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
776 NTSTATUS status;
777 struct winbindd_domain *domain;
778 struct rpc_pipe_client *netlogon_pipe;
779 union netr_CONTROL_QUERY_INFORMATION info;
780 WERROR werr;
781 fstring logon_server;
782 struct dcerpc_binding_handle *b;
783 bool retry = false;
785 domain = wb_child_domain();
786 if (domain == NULL) {
787 return NT_STATUS_REQUEST_NOT_ACCEPTED;
790 reconnect:
791 status = cm_connect_netlogon(domain, &netlogon_pipe);
792 reset_cm_connection_on_error(domain, status);
793 if (!NT_STATUS_IS_OK(status)) {
794 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
795 nt_errstr(status)));
796 return status;
799 b = netlogon_pipe->binding_handle;
801 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
802 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
803 if (*r->out.dcname == NULL) {
804 DEBUG(2, ("Could not allocate memory\n"));
805 return NT_STATUS_NO_MEMORY;
809 * This provokes a WERR_NOT_SUPPORTED error message. This is
810 * documented in the wspp docs. I could not get a successful
811 * call to work, but the main point here is testing that the
812 * netlogon pipe works.
814 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
815 logon_server, NETLOGON_CONTROL_QUERY,
816 2, &info, &werr);
818 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
819 DEBUG(10, ("Session might have expired. "
820 "Reconnect and retry once.\n"));
821 invalidate_cm_connection(domain);
822 retry = true;
823 goto reconnect;
826 reset_cm_connection_on_error(domain, status);
827 if (!NT_STATUS_IS_OK(status)) {
828 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
829 nt_errstr(status)));
830 return status;
833 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
834 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
835 "WERR_NOT_SUPPORTED\n",
836 win_errstr(werr)));
837 return werror_to_ntstatus(werr);
840 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
841 return NT_STATUS_OK;
844 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
845 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
847 struct winbindd_domain *domain;
848 NTSTATUS status;
849 struct rpc_pipe_client *netlogon_pipe = NULL;
850 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
852 domain = wb_child_domain();
853 if (domain == NULL) {
854 return NT_STATUS_REQUEST_NOT_ACCEPTED;
857 status = cm_connect_netlogon_secure(domain,
858 &netlogon_pipe,
859 &netlogon_creds_ctx);
860 if (!NT_STATUS_IS_OK(status)) {
861 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
862 goto done;
865 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
866 netlogon_pipe->binding_handle,
867 r->in.site_name,
868 r->in.dns_ttl,
869 r->in.dns_names);
871 /* Pass back result code - zero for success, other values for
872 specific failures. */
874 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
875 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
877 done:
878 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
879 ("Update of DNS records via RW DC %s returned %s\n",
880 domain->name, nt_errstr(status)));
882 return status;
885 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
886 struct winbind_SamLogon *r)
888 struct winbindd_domain *domain;
889 NTSTATUS status;
890 struct netr_IdentityInfo *identity_info = NULL;
891 const uint8_t chal_zero[8] = {0, };
892 const uint8_t *challenge = chal_zero;
893 DATA_BLOB lm_response, nt_response;
894 uint32_t flags = 0;
895 uint16_t validation_level;
896 union netr_Validation *validation = NULL;
897 bool interactive = false;
899 domain = wb_child_domain();
900 if (domain == NULL) {
901 return NT_STATUS_REQUEST_NOT_ACCEPTED;
904 switch (r->in.validation_level) {
905 case 3:
906 case 6:
907 break;
908 default:
909 return NT_STATUS_REQUEST_NOT_ACCEPTED;
912 switch (r->in.logon_level) {
913 case NetlogonInteractiveInformation:
914 case NetlogonServiceInformation:
915 case NetlogonInteractiveTransitiveInformation:
916 case NetlogonServiceTransitiveInformation:
917 if (r->in.logon.password == NULL) {
918 return NT_STATUS_REQUEST_NOT_ACCEPTED;
921 interactive = true;
922 identity_info = &r->in.logon.password->identity_info;
924 challenge = chal_zero;
925 lm_response = data_blob_talloc(p->mem_ctx,
926 r->in.logon.password->lmpassword.hash,
927 sizeof(r->in.logon.password->lmpassword.hash));
928 nt_response = data_blob_talloc(p->mem_ctx,
929 r->in.logon.password->ntpassword.hash,
930 sizeof(r->in.logon.password->ntpassword.hash));
931 break;
933 case NetlogonNetworkInformation:
934 case NetlogonNetworkTransitiveInformation:
935 if (r->in.logon.network == NULL) {
936 return NT_STATUS_REQUEST_NOT_ACCEPTED;
939 interactive = false;
940 identity_info = &r->in.logon.network->identity_info;
942 challenge = r->in.logon.network->challenge;
943 lm_response = data_blob_talloc(p->mem_ctx,
944 r->in.logon.network->lm.data,
945 r->in.logon.network->lm.length);
946 nt_response = data_blob_talloc(p->mem_ctx,
947 r->in.logon.network->nt.data,
948 r->in.logon.network->nt.length);
949 break;
951 case NetlogonGenericInformation:
952 if (r->in.logon.generic == NULL) {
953 return NT_STATUS_REQUEST_NOT_ACCEPTED;
956 identity_info = &r->in.logon.generic->identity_info;
958 * Not implemented here...
960 return NT_STATUS_REQUEST_NOT_ACCEPTED;
962 default:
963 return NT_STATUS_REQUEST_NOT_ACCEPTED;
966 status = winbind_dual_SamLogon(domain, p->mem_ctx,
967 interactive,
968 identity_info->parameter_control,
969 identity_info->account_name.string,
970 identity_info->domain_name.string,
971 identity_info->workstation.string,
972 challenge,
973 lm_response, nt_response,
974 &r->out.authoritative,
975 true, /* skip_sam */
976 &flags,
977 &validation_level,
978 &validation);
979 if (!NT_STATUS_IS_OK(status)) {
980 return status;
982 switch (r->in.validation_level) {
983 case 3:
984 status = map_validation_to_info3(p->mem_ctx,
985 validation_level,
986 validation,
987 &r->out.validation.sam3);
988 TALLOC_FREE(validation);
989 if (!NT_STATUS_IS_OK(status)) {
990 return status;
992 return NT_STATUS_OK;
993 case 6:
994 status = map_validation_to_info6(p->mem_ctx,
995 validation_level,
996 validation,
997 &r->out.validation.sam6);
998 TALLOC_FREE(validation);
999 if (!NT_STATUS_IS_OK(status)) {
1000 return status;
1002 return NT_STATUS_OK;
1005 smb_panic(__location__);
1006 return NT_STATUS_INTERNAL_ERROR;
1009 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1010 struct winbindd_domain *domain,
1011 struct winbind_LogonControl *r)
1013 NTSTATUS status;
1014 struct rpc_pipe_client *netlogon_pipe = NULL;
1015 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1016 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1017 WERROR check_result = WERR_INTERNAL_ERROR;
1019 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1020 if (info2 == NULL) {
1021 return WERR_NOT_ENOUGH_MEMORY;
1024 if (domain->internal) {
1025 check_result = WERR_OK;
1026 goto check_return;
1030 * For now we just force a reconnect
1032 * TODO: take care of the optional '\dcname'
1034 invalidate_cm_connection(domain);
1035 domain->conn.netlogon_force_reauth = true;
1036 status = cm_connect_netlogon_secure(domain,
1037 &netlogon_pipe,
1038 &netlogon_creds_ctx);
1039 reset_cm_connection_on_error(domain, status);
1040 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1041 status = NT_STATUS_NO_LOGON_SERVERS;
1043 if (!NT_STATUS_IS_OK(status)) {
1044 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1045 __func__, domain->name, domain->alt_name,
1046 nt_errstr(status)));
1048 * Here we return a top level error!
1049 * This is different than TC_QUERY or TC_VERIFY.
1051 return ntstatus_to_werror(status);
1053 check_result = WERR_OK;
1055 check_return:
1056 info2->pdc_connection_status = WERR_OK;
1057 if (domain->dcname != NULL) {
1058 info2->flags |= NETLOGON_HAS_IP;
1059 info2->flags |= NETLOGON_HAS_TIMESERV;
1060 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1061 domain->dcname);
1062 if (info2->trusted_dc_name == NULL) {
1063 return WERR_NOT_ENOUGH_MEMORY;
1065 } else {
1066 info2->trusted_dc_name = talloc_strdup(info2, "");
1067 if (info2->trusted_dc_name == NULL) {
1068 return WERR_NOT_ENOUGH_MEMORY;
1071 info2->tc_connection_status = check_result;
1073 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1074 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1075 "pdc_connection[%s] tc_connection[%s]\n",
1076 __func__, domain->name, domain->alt_name,
1077 domain->dcname,
1078 win_errstr(info2->pdc_connection_status),
1079 win_errstr(info2->tc_connection_status)));
1082 r->out.query->info2 = info2;
1084 DEBUG(5, ("%s: succeeded.\n", __func__));
1085 return WERR_OK;
1088 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1089 struct winbindd_domain *domain,
1090 struct winbind_LogonControl *r)
1092 NTSTATUS status;
1093 struct rpc_pipe_client *netlogon_pipe = NULL;
1094 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1095 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1096 WERROR check_result = WERR_INTERNAL_ERROR;
1098 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1099 if (info2 == NULL) {
1100 return WERR_NOT_ENOUGH_MEMORY;
1103 if (domain->internal) {
1104 check_result = WERR_OK;
1105 goto check_return;
1108 status = cm_connect_netlogon_secure(domain,
1109 &netlogon_pipe,
1110 &netlogon_creds_ctx);
1111 reset_cm_connection_on_error(domain, status);
1112 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1113 status = NT_STATUS_NO_LOGON_SERVERS;
1115 if (!NT_STATUS_IS_OK(status)) {
1116 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1117 nt_errstr(status)));
1118 check_result = ntstatus_to_werror(status);
1119 goto check_return;
1121 check_result = WERR_OK;
1123 check_return:
1124 info2->pdc_connection_status = WERR_OK;
1125 if (domain->dcname != NULL) {
1126 info2->flags |= NETLOGON_HAS_IP;
1127 info2->flags |= NETLOGON_HAS_TIMESERV;
1128 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1129 domain->dcname);
1130 if (info2->trusted_dc_name == NULL) {
1131 return WERR_NOT_ENOUGH_MEMORY;
1133 } else {
1134 info2->trusted_dc_name = talloc_strdup(info2, "");
1135 if (info2->trusted_dc_name == NULL) {
1136 return WERR_NOT_ENOUGH_MEMORY;
1139 info2->tc_connection_status = check_result;
1141 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1142 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1143 "pdc_connection[%s] tc_connection[%s]\n",
1144 __func__, domain->name, domain->alt_name,
1145 domain->dcname,
1146 win_errstr(info2->pdc_connection_status),
1147 win_errstr(info2->tc_connection_status)));
1150 r->out.query->info2 = info2;
1152 DEBUG(5, ("%s: succeeded.\n", __func__));
1153 return WERR_OK;
1156 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1157 struct winbindd_domain *domain,
1158 struct winbind_LogonControl *r)
1160 TALLOC_CTX *frame = talloc_stackframe();
1161 NTSTATUS status;
1162 NTSTATUS result;
1163 struct lsa_String trusted_domain_name = {};
1164 struct lsa_StringLarge trusted_domain_name_l = {};
1165 struct rpc_pipe_client *local_lsa_pipe = NULL;
1166 struct policy_handle local_lsa_policy = {};
1167 struct dcerpc_binding_handle *local_lsa = NULL;
1168 struct rpc_pipe_client *netlogon_pipe = NULL;
1169 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1170 struct cli_credentials *creds = NULL;
1171 struct samr_Password *cur_nt_hash = NULL;
1172 uint32_t trust_attributes = 0;
1173 struct samr_Password new_owf_password = {};
1174 int cmp_new = -1;
1175 struct samr_Password old_owf_password = {};
1176 int cmp_old = -1;
1177 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1178 bool fetch_fti = false;
1179 struct lsa_ForestTrustInformation *new_fti = NULL;
1180 struct netr_TrustInfo *trust_info = NULL;
1181 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1182 struct dcerpc_binding_handle *b = NULL;
1183 WERROR check_result = WERR_INTERNAL_ERROR;
1184 WERROR verify_result = WERR_INTERNAL_ERROR;
1185 bool retry = false;
1187 trusted_domain_name.string = domain->name;
1188 trusted_domain_name_l.string = domain->name;
1190 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1191 if (info2 == NULL) {
1192 TALLOC_FREE(frame);
1193 return WERR_NOT_ENOUGH_MEMORY;
1196 if (domain->internal) {
1197 check_result = WERR_OK;
1198 goto check_return;
1201 status = pdb_get_trust_credentials(domain->name,
1202 domain->alt_name,
1203 frame,
1204 &creds);
1205 if (NT_STATUS_IS_OK(status)) {
1206 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1207 TALLOC_FREE(creds);
1210 if (!domain->primary) {
1211 union lsa_TrustedDomainInfo *tdi = NULL;
1213 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1214 &local_lsa_policy);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1217 __location__, __func__, nt_errstr(status)));
1218 TALLOC_FREE(frame);
1219 return WERR_INTERNAL_ERROR;
1221 local_lsa = local_lsa_pipe->binding_handle;
1223 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1224 &local_lsa_policy,
1225 &trusted_domain_name,
1226 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1227 &tdi, &result);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1230 __location__, __func__, domain->name, nt_errstr(status)));
1231 TALLOC_FREE(frame);
1232 return WERR_INTERNAL_ERROR;
1234 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1235 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1236 __location__, __func__, domain->name));
1237 TALLOC_FREE(frame);
1238 return WERR_NO_SUCH_DOMAIN;
1240 if (!NT_STATUS_IS_OK(result)) {
1241 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1242 __location__, __func__, domain->name, nt_errstr(result)));
1243 TALLOC_FREE(frame);
1244 return WERR_INTERNAL_ERROR;
1246 if (tdi == NULL) {
1247 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1248 "returned no trusted domain information\n",
1249 __location__, __func__));
1250 TALLOC_FREE(frame);
1251 return WERR_INTERNAL_ERROR;
1254 local_tdo = &tdi->info_ex;
1255 trust_attributes = local_tdo->trust_attributes;
1258 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1259 struct lsa_ForestTrustInformation *old_fti = NULL;
1261 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1262 &local_lsa_policy,
1263 &trusted_domain_name,
1264 LSA_FOREST_TRUST_DOMAIN_INFO,
1265 &old_fti, &result);
1266 if (!NT_STATUS_IS_OK(status)) {
1267 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1268 __location__, __func__, domain->name, nt_errstr(status)));
1269 TALLOC_FREE(frame);
1270 return WERR_INTERNAL_ERROR;
1272 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1273 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1274 __func__, domain->name));
1275 old_fti = NULL;
1276 fetch_fti = true;
1277 result = NT_STATUS_OK;
1279 if (!NT_STATUS_IS_OK(result)) {
1280 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1281 __location__, __func__, domain->name, nt_errstr(result)));
1282 TALLOC_FREE(frame);
1283 return WERR_INTERNAL_ERROR;
1286 TALLOC_FREE(old_fti);
1289 reconnect:
1290 status = cm_connect_netlogon_secure(domain,
1291 &netlogon_pipe,
1292 &netlogon_creds_ctx);
1293 reset_cm_connection_on_error(domain, status);
1294 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1295 status = NT_STATUS_NO_LOGON_SERVERS;
1297 if (!NT_STATUS_IS_OK(status)) {
1298 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1299 nt_errstr(status)));
1300 check_result = ntstatus_to_werror(status);
1301 goto check_return;
1303 check_result = WERR_OK;
1304 b = netlogon_pipe->binding_handle;
1306 if (cur_nt_hash == NULL) {
1307 verify_result = WERR_NO_TRUST_LSA_SECRET;
1308 goto verify_return;
1311 if (fetch_fti) {
1312 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1313 b, frame,
1314 &new_fti);
1315 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1316 status = NT_STATUS_NOT_SUPPORTED;
1318 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1319 new_fti = NULL;
1320 status = NT_STATUS_OK;
1322 if (!NT_STATUS_IS_OK(status)) {
1323 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1324 invalidate_cm_connection(domain);
1325 retry = true;
1326 goto reconnect;
1328 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1329 "failed: %s\n",
1330 domain->name, nt_errstr(status)));
1331 check_result = ntstatus_to_werror(status);
1332 goto check_return;
1336 if (new_fti != NULL) {
1337 struct lsa_ForestTrustInformation old_fti = {};
1338 struct lsa_ForestTrustInformation *merged_fti = NULL;
1339 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1341 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1342 &old_fti, new_fti,
1343 &merged_fti);
1344 if (!NT_STATUS_IS_OK(status)) {
1345 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1346 __location__, __func__,
1347 domain->name, nt_errstr(status)));
1348 TALLOC_FREE(frame);
1349 return ntstatus_to_werror(status);
1352 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1353 &local_lsa_policy,
1354 &trusted_domain_name_l,
1355 LSA_FOREST_TRUST_DOMAIN_INFO,
1356 merged_fti,
1357 0, /* check_only=0 => store it! */
1358 &collision_info,
1359 &result);
1360 if (!NT_STATUS_IS_OK(status)) {
1361 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1362 __location__, __func__, domain->name, nt_errstr(status)));
1363 TALLOC_FREE(frame);
1364 return WERR_INTERNAL_ERROR;
1366 if (!NT_STATUS_IS_OK(result)) {
1367 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1368 __location__, __func__, domain->name, nt_errstr(result)));
1369 TALLOC_FREE(frame);
1370 return ntstatus_to_werror(result);
1374 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1375 b, frame,
1376 &new_owf_password,
1377 &old_owf_password,
1378 &trust_info);
1379 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1380 status = NT_STATUS_NOT_SUPPORTED;
1382 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1383 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1384 nt_errstr(status)));
1385 verify_result = WERR_OK;
1386 goto verify_return;
1388 if (!NT_STATUS_IS_OK(status)) {
1389 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1390 invalidate_cm_connection(domain);
1391 retry = true;
1392 goto reconnect;
1394 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1395 nt_errstr(status)));
1397 if (!dcerpc_binding_handle_is_connected(b)) {
1398 check_result = ntstatus_to_werror(status);
1399 goto check_return;
1400 } else {
1401 verify_result = ntstatus_to_werror(status);
1402 goto verify_return;
1406 if (trust_info != NULL && trust_info->count >= 1) {
1407 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1409 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1410 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1411 goto verify_return;
1415 cmp_new = memcmp(new_owf_password.hash,
1416 cur_nt_hash->hash,
1417 sizeof(cur_nt_hash->hash));
1418 cmp_old = memcmp(old_owf_password.hash,
1419 cur_nt_hash->hash,
1420 sizeof(cur_nt_hash->hash));
1421 if (cmp_new != 0 && cmp_old != 0) {
1422 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1423 "any password known to dcname[%s]\n",
1424 __func__, domain->name, domain->alt_name,
1425 domain->dcname));
1426 verify_result = WERR_WRONG_PASSWORD;
1427 goto verify_return;
1430 if (cmp_new != 0) {
1431 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1432 "against the old password known to dcname[%s]\n",
1433 __func__, domain->name, domain->alt_name,
1434 domain->dcname));
1437 verify_result = WERR_OK;
1438 goto verify_return;
1440 check_return:
1441 verify_result = check_result;
1442 verify_return:
1443 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1444 info2->pdc_connection_status = verify_result;
1445 if (domain->dcname != NULL) {
1446 info2->flags |= NETLOGON_HAS_IP;
1447 info2->flags |= NETLOGON_HAS_TIMESERV;
1448 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1449 domain->dcname);
1450 if (info2->trusted_dc_name == NULL) {
1451 TALLOC_FREE(frame);
1452 return WERR_NOT_ENOUGH_MEMORY;
1454 } else {
1455 info2->trusted_dc_name = talloc_strdup(info2, "");
1456 if (info2->trusted_dc_name == NULL) {
1457 TALLOC_FREE(frame);
1458 return WERR_NOT_ENOUGH_MEMORY;
1461 info2->tc_connection_status = check_result;
1463 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1464 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1465 "pdc_connection[%s] tc_connection[%s]\n",
1466 __func__, domain->name, domain->alt_name,
1467 domain->dcname,
1468 win_errstr(info2->pdc_connection_status),
1469 win_errstr(info2->tc_connection_status)));
1472 r->out.query->info2 = info2;
1474 DEBUG(5, ("%s: succeeded.\n", __func__));
1475 TALLOC_FREE(frame);
1476 return WERR_OK;
1479 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1480 struct winbindd_domain *domain,
1481 struct winbind_LogonControl *r)
1483 struct messaging_context *msg_ctx = server_messaging_context();
1484 NTSTATUS status;
1485 struct rpc_pipe_client *netlogon_pipe = NULL;
1486 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1487 struct cli_credentials *creds = NULL;
1488 struct samr_Password *cur_nt_hash = NULL;
1489 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1490 struct dcerpc_binding_handle *b;
1491 WERROR change_result = WERR_OK;
1492 bool retry = false;
1494 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1495 if (info1 == NULL) {
1496 return WERR_NOT_ENOUGH_MEMORY;
1499 if (domain->internal) {
1500 return WERR_NOT_SUPPORTED;
1503 status = pdb_get_trust_credentials(domain->name,
1504 domain->alt_name,
1505 p->mem_ctx,
1506 &creds);
1507 if (NT_STATUS_IS_OK(status)) {
1508 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1509 TALLOC_FREE(creds);
1512 reconnect:
1513 status = cm_connect_netlogon_secure(domain,
1514 &netlogon_pipe,
1515 &netlogon_creds_ctx);
1516 reset_cm_connection_on_error(domain, status);
1517 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1518 status = NT_STATUS_NO_LOGON_SERVERS;
1520 if (!NT_STATUS_IS_OK(status)) {
1521 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1522 __func__, domain->name, domain->alt_name,
1523 nt_errstr(status)));
1525 * Here we return a top level error!
1526 * This is different than TC_QUERY or TC_VERIFY.
1528 return ntstatus_to_werror(status);
1530 b = netlogon_pipe->binding_handle;
1532 if (cur_nt_hash == NULL) {
1533 change_result = WERR_NO_TRUST_LSA_SECRET;
1534 goto change_return;
1536 TALLOC_FREE(cur_nt_hash);
1538 status = trust_pw_change(netlogon_creds_ctx,
1539 msg_ctx, b, domain->name,
1540 domain->dcname,
1541 true); /* force */
1542 if (!NT_STATUS_IS_OK(status)) {
1543 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1544 invalidate_cm_connection(domain);
1545 retry = true;
1546 goto reconnect;
1549 DEBUG(1, ("trust_pw_change(%s): %s\n",
1550 domain->name, nt_errstr(status)));
1552 change_result = ntstatus_to_werror(status);
1553 goto change_return;
1556 change_result = WERR_OK;
1558 change_return:
1559 info1->pdc_connection_status = change_result;
1561 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1562 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1563 "pdc_connection[%s]\n",
1564 __func__, domain->name, domain->alt_name,
1565 domain->dcname,
1566 win_errstr(info1->pdc_connection_status)));
1569 r->out.query->info1 = info1;
1571 DEBUG(5, ("%s: succeeded.\n", __func__));
1572 return WERR_OK;
1575 WERROR _winbind_LogonControl(struct pipes_struct *p,
1576 struct winbind_LogonControl *r)
1578 struct winbindd_domain *domain;
1580 domain = wb_child_domain();
1581 if (domain == NULL) {
1582 return WERR_NO_SUCH_DOMAIN;
1585 switch (r->in.function_code) {
1586 case NETLOGON_CONTROL_REDISCOVER:
1587 if (r->in.level != 2) {
1588 return WERR_INVALID_PARAMETER;
1590 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1591 case NETLOGON_CONTROL_TC_QUERY:
1592 if (r->in.level != 2) {
1593 return WERR_INVALID_PARAMETER;
1595 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1596 case NETLOGON_CONTROL_TC_VERIFY:
1597 if (r->in.level != 2) {
1598 return WERR_INVALID_PARAMETER;
1600 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1601 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1602 if (r->in.level != 1) {
1603 return WERR_INVALID_PARAMETER;
1605 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1606 default:
1607 break;
1610 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1611 __func__, r->in.function_code));
1612 return WERR_NOT_SUPPORTED;
1615 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1616 struct winbind_GetForestTrustInformation *r)
1618 TALLOC_CTX *frame = talloc_stackframe();
1619 NTSTATUS status, result;
1620 struct winbindd_domain *domain;
1621 struct rpc_pipe_client *netlogon_pipe = NULL;
1622 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1623 struct dcerpc_binding_handle *b;
1624 bool retry = false;
1625 struct lsa_String trusted_domain_name = {};
1626 struct lsa_StringLarge trusted_domain_name_l = {};
1627 union lsa_TrustedDomainInfo *tdi = NULL;
1628 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1629 struct lsa_ForestTrustInformation _old_fti = {};
1630 struct lsa_ForestTrustInformation *old_fti = NULL;
1631 struct lsa_ForestTrustInformation *new_fti = NULL;
1632 struct lsa_ForestTrustInformation *merged_fti = NULL;
1633 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1634 bool update_fti = false;
1635 struct rpc_pipe_client *local_lsa_pipe;
1636 struct policy_handle local_lsa_policy;
1637 struct dcerpc_binding_handle *local_lsa = NULL;
1639 domain = wb_child_domain();
1640 if (domain == NULL) {
1641 TALLOC_FREE(frame);
1642 return WERR_NO_SUCH_DOMAIN;
1646 * checking for domain->internal and domain->primary
1647 * makes sure we only do some work when running as DC.
1650 if (domain->internal) {
1651 TALLOC_FREE(frame);
1652 return WERR_NO_SUCH_DOMAIN;
1655 if (domain->primary) {
1656 TALLOC_FREE(frame);
1657 return WERR_NO_SUCH_DOMAIN;
1660 trusted_domain_name.string = domain->name;
1661 trusted_domain_name_l.string = domain->name;
1663 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1664 &local_lsa_policy);
1665 if (!NT_STATUS_IS_OK(status)) {
1666 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1667 __location__, __func__, nt_errstr(status)));
1668 TALLOC_FREE(frame);
1669 return WERR_INTERNAL_ERROR;
1671 local_lsa = local_lsa_pipe->binding_handle;
1673 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1674 &local_lsa_policy,
1675 &trusted_domain_name,
1676 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1677 &tdi, &result);
1678 if (!NT_STATUS_IS_OK(status)) {
1679 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1680 __location__, __func__, domain->name, nt_errstr(status)));
1681 TALLOC_FREE(frame);
1682 return WERR_INTERNAL_ERROR;
1684 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1685 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1686 __location__, __func__, domain->name));
1687 TALLOC_FREE(frame);
1688 return WERR_NO_SUCH_DOMAIN;
1690 if (!NT_STATUS_IS_OK(result)) {
1691 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1692 __location__, __func__, domain->name, nt_errstr(result)));
1693 TALLOC_FREE(frame);
1694 return WERR_INTERNAL_ERROR;
1696 if (tdi == NULL) {
1697 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1698 "returned no trusted domain information\n",
1699 __location__, __func__));
1700 TALLOC_FREE(frame);
1701 return WERR_INTERNAL_ERROR;
1704 tdo = &tdi->info_ex;
1706 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1707 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1708 __func__, tdo->netbios_name.string,
1709 tdo->domain_name.string,
1710 (unsigned)tdo->trust_attributes));
1711 TALLOC_FREE(frame);
1712 return WERR_NO_SUCH_DOMAIN;
1715 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1716 TALLOC_FREE(frame);
1717 return WERR_INVALID_FLAGS;
1720 reconnect:
1721 status = cm_connect_netlogon_secure(domain,
1722 &netlogon_pipe,
1723 &netlogon_creds_ctx);
1724 reset_cm_connection_on_error(domain, status);
1725 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1726 status = NT_STATUS_NO_LOGON_SERVERS;
1728 if (!NT_STATUS_IS_OK(status)) {
1729 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1730 nt_errstr(status)));
1731 TALLOC_FREE(frame);
1732 return ntstatus_to_werror(status);
1734 b = netlogon_pipe->binding_handle;
1736 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1737 b, p->mem_ctx,
1738 &new_fti);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1741 invalidate_cm_connection(domain);
1742 retry = true;
1743 goto reconnect;
1745 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1746 domain->name, nt_errstr(status)));
1747 TALLOC_FREE(frame);
1748 return ntstatus_to_werror(status);
1751 *r->out.forest_trust_info = new_fti;
1753 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1754 update_fti = true;
1757 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1758 &local_lsa_policy,
1759 &trusted_domain_name,
1760 LSA_FOREST_TRUST_DOMAIN_INFO,
1761 &old_fti, &result);
1762 if (!NT_STATUS_IS_OK(status)) {
1763 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1764 __location__, __func__, domain->name, nt_errstr(status)));
1765 TALLOC_FREE(frame);
1766 return WERR_INTERNAL_ERROR;
1768 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1769 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1770 __func__, domain->name));
1771 update_fti = true;
1772 old_fti = &_old_fti;
1773 result = NT_STATUS_OK;
1775 if (!NT_STATUS_IS_OK(result)) {
1776 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1777 __location__, __func__, domain->name, nt_errstr(result)));
1778 TALLOC_FREE(frame);
1779 return WERR_INTERNAL_ERROR;
1782 if (old_fti == NULL) {
1783 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1784 "returned success without returning forest trust information\n",
1785 __location__, __func__));
1786 TALLOC_FREE(frame);
1787 return WERR_INTERNAL_ERROR;
1790 if (!update_fti) {
1791 goto done;
1794 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1795 &merged_fti);
1796 if (!NT_STATUS_IS_OK(status)) {
1797 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1798 __location__, __func__, domain->name, nt_errstr(status)));
1799 TALLOC_FREE(frame);
1800 return ntstatus_to_werror(status);
1803 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1804 &local_lsa_policy,
1805 &trusted_domain_name_l,
1806 LSA_FOREST_TRUST_DOMAIN_INFO,
1807 merged_fti,
1808 0, /* check_only=0 => store it! */
1809 &collision_info,
1810 &result);
1811 if (!NT_STATUS_IS_OK(status)) {
1812 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1813 __location__, __func__, domain->name, nt_errstr(status)));
1814 TALLOC_FREE(frame);
1815 return WERR_INTERNAL_ERROR;
1817 if (!NT_STATUS_IS_OK(result)) {
1818 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1819 __location__, __func__, domain->name, nt_errstr(result)));
1820 TALLOC_FREE(frame);
1821 return ntstatus_to_werror(result);
1824 done:
1825 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1826 TALLOC_FREE(frame);
1827 return WERR_OK;
1830 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1832 struct winbindd_domain *domain;
1833 NTSTATUS status;
1834 struct rpc_pipe_client *netlogon_pipe;
1835 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1837 DEBUG(5, ("_winbind_SendToSam received\n"));
1838 domain = wb_child_domain();
1839 if (domain == NULL) {
1840 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1843 status = cm_connect_netlogon_secure(domain,
1844 &netlogon_pipe,
1845 &netlogon_creds_ctx);
1846 if (!NT_STATUS_IS_OK(status)) {
1847 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1848 return status;
1851 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1852 netlogon_pipe->binding_handle,
1853 &r->in.message);
1855 return status;