winbindd: add retry to _winbind_SendToSam
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob8ed95c81a371e97e633e98586a8085ad9efa129f
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"
37 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
39 *r->out.out_data = r->in.in_data;
42 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
43 struct dcerpc_binding_handle *b,
44 NTSTATUS status)
46 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
47 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
48 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
49 invalidate_cm_connection(domain);
50 domain->conn.netlogon_force_reauth = true;
51 return true;
54 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
55 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
57 invalidate_cm_connection(domain);
58 /* We invalidated the connection. */
59 return true;
62 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
63 invalidate_cm_connection(domain);
64 return true;
67 return false;
70 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
72 struct winbindd_domain *domain = wb_child_domain();
73 char *dom_name;
74 char *name;
75 enum lsa_SidType type;
76 NTSTATUS status;
78 if (domain == NULL) {
79 return NT_STATUS_REQUEST_NOT_ACCEPTED;
82 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
83 &dom_name, &name, &type);
84 reset_cm_connection_on_error(domain, NULL, status);
85 if (!NT_STATUS_IS_OK(status)) {
86 return status;
89 *r->out.domain = dom_name;
90 *r->out.name = name;
91 *r->out.type = type;
92 return NT_STATUS_OK;
95 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
97 struct winbindd_domain *domain = wb_child_domain();
98 struct lsa_RefDomainList *domains = r->out.domains;
99 NTSTATUS status;
100 bool retry = false;
102 if (domain == NULL) {
103 return NT_STATUS_REQUEST_NOT_ACCEPTED;
107 * This breaks the winbindd_domain->methods abstraction: This
108 * is only called for remote domains, and both winbindd_msrpc
109 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
110 * done at the wbint RPC layer.
112 again:
113 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
114 &domains, &r->out.names);
116 if (domains != NULL) {
117 r->out.domains = domains;
120 if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
121 retry = true;
122 goto again;
125 return status;
128 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
130 struct winbindd_domain *domain = wb_child_domain();
131 NTSTATUS status;
133 if (domain == NULL) {
134 return NT_STATUS_REQUEST_NOT_ACCEPTED;
137 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
138 r->in.name, r->in.flags,
139 r->out.sid, r->out.type);
140 reset_cm_connection_on_error(domain, NULL, status);
141 return status;
144 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
145 struct wbint_Sids2UnixIDs *r)
147 uint32_t i;
149 struct lsa_DomainInfo *d;
150 struct wbint_TransID *ids;
151 uint32_t num_ids;
153 struct id_map **id_map_ptrs = NULL;
154 struct idmap_domain *dom;
155 NTSTATUS status = NT_STATUS_NO_MEMORY;
157 if (r->in.domains->count != 1) {
158 return NT_STATUS_INVALID_PARAMETER;
161 d = &r->in.domains->domains[0];
162 ids = r->in.ids->ids;
163 num_ids = r->in.ids->num_ids;
165 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
166 if (dom == NULL) {
167 DEBUG(10, ("idmap domain %s:%s not found\n",
168 d->name.string, sid_string_dbg(d->sid)));
170 for (i=0; i<num_ids; i++) {
172 ids[i].xid = (struct unixid) {
173 .id = UINT32_MAX,
174 .type = ID_TYPE_NOT_SPECIFIED
178 return NT_STATUS_OK;
181 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
182 if (id_map_ptrs == NULL) {
183 goto nomem;
187 * Convert the input data into a list of id_map structs
188 * suitable for handing in to the idmap sids_to_unixids
189 * method.
192 for (i=0; i<num_ids; i++) {
193 struct id_map *m = id_map_ptrs[i];
195 sid_compose(m->sid, d->sid, ids[i].rid);
196 m->status = ID_UNKNOWN;
197 m->xid = (struct unixid) { .type = ids[i].type };
200 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
202 if (!NT_STATUS_IS_OK(status)) {
203 DEBUG(10, ("sids_to_unixids returned %s\n",
204 nt_errstr(status)));
205 goto done;
209 * Extract the results for handing them back to the caller.
212 for (i=0; i<num_ids; i++) {
213 struct id_map *m = id_map_ptrs[i];
215 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
216 DBG_DEBUG("id %"PRIu32" is out of range "
217 "%"PRIu32"-%"PRIu32" for domain %s\n",
218 m->xid.id, dom->low_id, dom->high_id,
219 dom->name);
220 m->status = ID_UNMAPPED;
223 if (m->status == ID_MAPPED) {
224 ids[i].xid = m->xid;
225 } else {
226 ids[i].xid.id = UINT32_MAX;
227 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
231 goto done;
232 nomem:
233 status = NT_STATUS_NO_MEMORY;
234 done:
235 TALLOC_FREE(id_map_ptrs);
236 return status;
239 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
240 struct wbint_UnixIDs2Sids *r)
242 struct id_map **maps;
243 NTSTATUS status;
244 uint32_t i;
246 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
247 if (maps == NULL) {
248 return NT_STATUS_NO_MEMORY;
251 for (i=0; i<r->in.num_ids; i++) {
252 maps[i]->status = ID_UNKNOWN;
253 maps[i]->xid = r->in.xids[i];
256 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
257 r->in.domain_sid);
258 if (!NT_STATUS_IS_OK(status)) {
259 TALLOC_FREE(maps);
260 return status;
263 for (i=0; i<r->in.num_ids; i++) {
264 r->out.xids[i] = maps[i]->xid;
265 sid_copy(&r->out.sids[i], maps[i]->sid);
268 TALLOC_FREE(maps);
270 return NT_STATUS_OK;
273 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
275 struct unixid xid;
276 NTSTATUS status;
278 status = idmap_allocate_uid(&xid);
279 if (!NT_STATUS_IS_OK(status)) {
280 return status;
282 *r->out.uid = xid.id;
283 return NT_STATUS_OK;
286 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
288 struct unixid xid;
289 NTSTATUS status;
291 status = idmap_allocate_gid(&xid);
292 if (!NT_STATUS_IS_OK(status)) {
293 return status;
295 *r->out.gid = xid.id;
296 return NT_STATUS_OK;
299 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
301 struct idmap_domain *domain;
302 NTSTATUS status;
304 domain = idmap_find_domain(r->in.info->domain_name);
305 if ((domain == NULL) || (domain->query_user == NULL)) {
306 return NT_STATUS_REQUEST_NOT_ACCEPTED;
309 status = domain->query_user(domain, r->in.info);
310 return status;
313 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
314 struct wbint_LookupUserAliases *r)
316 struct winbindd_domain *domain = wb_child_domain();
317 NTSTATUS status;
319 if (domain == NULL) {
320 return NT_STATUS_REQUEST_NOT_ACCEPTED;
323 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
324 r->in.sids->num_sids,
325 r->in.sids->sids,
326 &r->out.rids->num_rids,
327 &r->out.rids->rids);
328 reset_cm_connection_on_error(domain, NULL, status);
329 return status;
332 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
333 struct wbint_LookupUserGroups *r)
335 struct winbindd_domain *domain = wb_child_domain();
336 NTSTATUS status;
338 if (domain == NULL) {
339 return NT_STATUS_REQUEST_NOT_ACCEPTED;
342 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
343 &r->out.sids->num_sids,
344 &r->out.sids->sids);
345 reset_cm_connection_on_error(domain, NULL, status);
346 return status;
349 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
350 struct wbint_QuerySequenceNumber *r)
352 struct winbindd_domain *domain = wb_child_domain();
353 NTSTATUS status;
355 if (domain == NULL) {
356 return NT_STATUS_REQUEST_NOT_ACCEPTED;
359 status = wb_cache_sequence_number(domain, r->out.sequence);
360 reset_cm_connection_on_error(domain, NULL, status);
361 return status;
364 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
365 struct wbint_LookupGroupMembers *r)
367 struct winbindd_domain *domain = wb_child_domain();
368 uint32_t i, num_names;
369 struct dom_sid *sid_mem;
370 char **names;
371 uint32_t *name_types;
372 NTSTATUS status;
374 if (domain == NULL) {
375 return NT_STATUS_REQUEST_NOT_ACCEPTED;
378 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
379 r->in.type, &num_names, &sid_mem,
380 &names, &name_types);
381 reset_cm_connection_on_error(domain, NULL, status);
382 if (!NT_STATUS_IS_OK(status)) {
383 return status;
386 r->out.members->num_principals = num_names;
387 r->out.members->principals = talloc_array(
388 r->out.members, struct wbint_Principal, num_names);
389 if (r->out.members->principals == NULL) {
390 return NT_STATUS_NO_MEMORY;
393 for (i=0; i<num_names; i++) {
394 struct wbint_Principal *m = &r->out.members->principals[i];
395 sid_copy(&m->sid, &sid_mem[i]);
396 m->name = talloc_move(r->out.members->principals, &names[i]);
397 m->type = (enum lsa_SidType)name_types[i];
400 return NT_STATUS_OK;
403 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
404 struct wbint_QueryGroupList *r)
406 struct winbindd_domain *domain = wb_child_domain();
407 uint32_t i;
408 uint32_t num_local_groups = 0;
409 struct wb_acct_info *local_groups = NULL;
410 uint32_t num_dom_groups = 0;
411 struct wb_acct_info *dom_groups = NULL;
412 uint32_t ti = 0;
413 uint64_t num_total = 0;
414 struct wbint_Principal *result;
415 NTSTATUS status;
416 bool include_local_groups = false;
418 if (domain == NULL) {
419 return NT_STATUS_REQUEST_NOT_ACCEPTED;
422 switch (lp_server_role()) {
423 case ROLE_ACTIVE_DIRECTORY_DC:
424 if (domain->internal) {
426 * we want to include local groups
427 * for BUILTIN and WORKGROUP
429 include_local_groups = true;
431 break;
432 default:
434 * We might include local groups in more
435 * setups later, but that requires more work
436 * elsewhere.
438 break;
441 if (include_local_groups) {
442 status = wb_cache_enum_local_groups(domain, talloc_tos(),
443 &num_local_groups,
444 &local_groups);
445 reset_cm_connection_on_error(domain, NULL, status);
446 if (!NT_STATUS_IS_OK(status)) {
447 return status;
451 status = wb_cache_enum_dom_groups(domain, talloc_tos(),
452 &num_dom_groups,
453 &dom_groups);
454 reset_cm_connection_on_error(domain, NULL, status);
455 if (!NT_STATUS_IS_OK(status)) {
456 return status;
459 num_total = num_local_groups + num_dom_groups;
460 if (num_total > UINT32_MAX) {
461 return NT_STATUS_INTERNAL_ERROR;
464 result = talloc_array(r->out.groups, struct wbint_Principal,
465 num_total);
466 if (result == NULL) {
467 return NT_STATUS_NO_MEMORY;
470 for (i = 0; i < num_local_groups; i++) {
471 struct wb_acct_info *lg = &local_groups[i];
472 struct wbint_Principal *rg = &result[ti++];
474 sid_compose(&rg->sid, &domain->sid, lg->rid);
475 rg->type = SID_NAME_ALIAS;
476 rg->name = talloc_strdup(result, lg->acct_name);
477 if (rg->name == NULL) {
478 TALLOC_FREE(result);
479 TALLOC_FREE(dom_groups);
480 TALLOC_FREE(local_groups);
481 return NT_STATUS_NO_MEMORY;
484 num_local_groups = 0;
485 TALLOC_FREE(local_groups);
487 for (i = 0; i < num_dom_groups; i++) {
488 struct wb_acct_info *dg = &dom_groups[i];
489 struct wbint_Principal *rg = &result[ti++];
491 sid_compose(&rg->sid, &domain->sid, dg->rid);
492 rg->type = SID_NAME_DOM_GRP;
493 rg->name = talloc_strdup(result, dg->acct_name);
494 if (rg->name == NULL) {
495 TALLOC_FREE(result);
496 TALLOC_FREE(dom_groups);
497 TALLOC_FREE(local_groups);
498 return NT_STATUS_NO_MEMORY;
501 num_dom_groups = 0;
502 TALLOC_FREE(dom_groups);
504 r->out.groups->num_principals = ti;
505 r->out.groups->principals = result;
507 return NT_STATUS_OK;
510 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
511 struct wbint_QueryUserRidList *r)
513 struct winbindd_domain *domain = wb_child_domain();
514 NTSTATUS status;
516 if (domain == NULL) {
517 return NT_STATUS_REQUEST_NOT_ACCEPTED;
521 * Right now this is overkill. We should add a backend call
522 * just querying the rids.
525 status = wb_cache_query_user_list(domain, p->mem_ctx,
526 &r->out.rids->rids);
527 reset_cm_connection_on_error(domain, NULL, status);
529 if (!NT_STATUS_IS_OK(status)) {
530 return status;
533 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
535 return NT_STATUS_OK;
538 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
540 struct winbindd_domain *domain = wb_child_domain();
541 struct rpc_pipe_client *netlogon_pipe;
542 struct netr_DsRGetDCNameInfo *dc_info;
543 NTSTATUS status;
544 WERROR werr;
545 unsigned int orig_timeout;
546 struct dcerpc_binding_handle *b;
547 bool retry = false;
548 bool try_dsrgetdcname = false;
550 if (domain == NULL) {
551 return dsgetdcname(p->mem_ctx, server_messaging_context(),
552 r->in.domain_name, r->in.domain_guid,
553 r->in.site_name ? r->in.site_name : "",
554 r->in.flags,
555 r->out.dc_info);
558 if (domain->active_directory) {
559 try_dsrgetdcname = true;
562 reconnect:
563 status = cm_connect_netlogon(domain, &netlogon_pipe);
565 reset_cm_connection_on_error(domain, NULL, status);
566 if (!NT_STATUS_IS_OK(status)) {
567 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
568 return status;
571 b = netlogon_pipe->binding_handle;
573 /* This call can take a long time - allow the server to time out.
574 35 seconds should do it. */
576 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
578 if (try_dsrgetdcname) {
579 status = dcerpc_netr_DsRGetDCName(b,
580 p->mem_ctx, domain->dcname,
581 r->in.domain_name, NULL, r->in.domain_guid,
582 r->in.flags, r->out.dc_info, &werr);
583 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
584 goto done;
586 if (!retry &&
587 reset_cm_connection_on_error(domain, NULL, status))
589 retry = true;
590 goto reconnect;
592 try_dsrgetdcname = false;
593 retry = false;
597 * Fallback to less capable methods
600 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
601 if (dc_info == NULL) {
602 status = NT_STATUS_NO_MEMORY;
603 goto done;
606 if (r->in.flags & DS_PDC_REQUIRED) {
607 status = dcerpc_netr_GetDcName(b,
608 p->mem_ctx, domain->dcname,
609 r->in.domain_name, &dc_info->dc_unc, &werr);
610 } else {
611 status = dcerpc_netr_GetAnyDCName(b,
612 p->mem_ctx, domain->dcname,
613 r->in.domain_name, &dc_info->dc_unc, &werr);
616 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
617 retry = true;
618 goto reconnect;
620 if (!NT_STATUS_IS_OK(status)) {
621 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
622 nt_errstr(status)));
623 goto done;
625 if (!W_ERROR_IS_OK(werr)) {
626 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
627 win_errstr(werr)));
628 status = werror_to_ntstatus(werr);
629 goto done;
632 *r->out.dc_info = dc_info;
633 status = NT_STATUS_OK;
635 done:
636 /* And restore our original timeout. */
637 rpccli_set_timeout(netlogon_pipe, orig_timeout);
639 return status;
642 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
644 struct winbindd_domain *domain = wb_child_domain();
645 char *domain_name;
646 char **names;
647 enum lsa_SidType *types;
648 struct wbint_Principal *result;
649 NTSTATUS status;
650 uint32_t i;
652 if (domain == NULL) {
653 return NT_STATUS_REQUEST_NOT_ACCEPTED;
656 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
657 r->in.rids->rids, r->in.rids->num_rids,
658 &domain_name, &names, &types);
659 reset_cm_connection_on_error(domain, NULL, status);
660 if (!NT_STATUS_IS_OK(status)) {
661 return status;
664 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
666 result = talloc_array(p->mem_ctx, struct wbint_Principal,
667 r->in.rids->num_rids);
668 if (result == NULL) {
669 return NT_STATUS_NO_MEMORY;
672 for (i=0; i<r->in.rids->num_rids; i++) {
673 sid_compose(&result[i].sid, r->in.domain_sid,
674 r->in.rids->rids[i]);
675 result[i].type = types[i];
676 result[i].name = talloc_move(result, &names[i]);
678 TALLOC_FREE(types);
679 TALLOC_FREE(names);
681 r->out.names->num_principals = r->in.rids->num_rids;
682 r->out.names->principals = result;
683 return NT_STATUS_OK;
686 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
687 struct wbint_CheckMachineAccount *r)
689 struct winbindd_domain *domain;
690 int num_retries = 0;
691 NTSTATUS status;
693 domain = wb_child_domain();
694 if (domain == NULL) {
695 return NT_STATUS_REQUEST_NOT_ACCEPTED;
698 again:
699 invalidate_cm_connection(domain);
700 domain->conn.netlogon_force_reauth = true;
703 struct rpc_pipe_client *netlogon_pipe;
704 status = cm_connect_netlogon(domain, &netlogon_pipe);
707 /* There is a race condition between fetching the trust account
708 password and the periodic machine password change. So it's
709 possible that the trust account password has been changed on us.
710 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
712 #define MAX_RETRIES 3
714 if ((num_retries < MAX_RETRIES)
715 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
716 num_retries++;
717 goto again;
720 if (!NT_STATUS_IS_OK(status)) {
721 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
722 goto done;
725 /* Pass back result code - zero for success, other values for
726 specific failures. */
728 DEBUG(3,("domain %s secret is %s\n", domain->name,
729 NT_STATUS_IS_OK(status) ? "good" : "bad"));
731 done:
732 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
733 ("Checking the trust account password for domain %s returned %s\n",
734 domain->name, nt_errstr(status)));
736 return status;
739 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
740 struct wbint_ChangeMachineAccount *r)
742 struct messaging_context *msg_ctx = server_messaging_context();
743 struct winbindd_domain *domain;
744 NTSTATUS status;
745 struct rpc_pipe_client *netlogon_pipe;
747 domain = wb_child_domain();
748 if (domain == NULL) {
749 return NT_STATUS_REQUEST_NOT_ACCEPTED;
752 status = cm_connect_netlogon(domain, &netlogon_pipe);
753 if (!NT_STATUS_IS_OK(status)) {
754 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
755 goto done;
758 status = trust_pw_change(domain->conn.netlogon_creds,
759 msg_ctx,
760 netlogon_pipe->binding_handle,
761 domain->name,
762 domain->dcname,
763 true); /* force */
765 /* Pass back result code - zero for success, other values for
766 specific failures. */
768 DEBUG(3,("domain %s secret %s\n", domain->name,
769 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
771 done:
772 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
773 ("Changing the trust account password for domain %s returned %s\n",
774 domain->name, nt_errstr(status)));
776 return status;
779 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
781 NTSTATUS status;
782 struct winbindd_domain *domain;
783 struct rpc_pipe_client *netlogon_pipe;
784 union netr_CONTROL_QUERY_INFORMATION info;
785 WERROR werr;
786 fstring logon_server;
787 struct dcerpc_binding_handle *b;
788 bool retry = false;
790 domain = wb_child_domain();
791 if (domain == NULL) {
792 return NT_STATUS_REQUEST_NOT_ACCEPTED;
795 reconnect:
796 status = cm_connect_netlogon(domain, &netlogon_pipe);
797 reset_cm_connection_on_error(domain, NULL, status);
798 if (!NT_STATUS_IS_OK(status)) {
799 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
800 nt_errstr(status)));
801 return status;
804 b = netlogon_pipe->binding_handle;
806 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
807 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
808 if (*r->out.dcname == NULL) {
809 DEBUG(2, ("Could not allocate memory\n"));
810 return NT_STATUS_NO_MEMORY;
814 * This provokes a WERR_NOT_SUPPORTED error message. This is
815 * documented in the wspp docs. I could not get a successful
816 * call to work, but the main point here is testing that the
817 * netlogon pipe works.
819 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
820 logon_server, NETLOGON_CONTROL_QUERY,
821 2, &info, &werr);
823 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
824 retry = true;
825 goto reconnect;
828 if (!NT_STATUS_IS_OK(status)) {
829 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
830 nt_errstr(status)));
831 return status;
834 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
835 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
836 "WERR_NOT_SUPPORTED\n",
837 win_errstr(werr)));
838 return werror_to_ntstatus(werr);
841 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
842 return NT_STATUS_OK;
845 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
846 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
848 struct winbindd_domain *domain;
849 NTSTATUS status;
850 struct rpc_pipe_client *netlogon_pipe;
851 struct dcerpc_binding_handle *b = NULL;
852 bool retry = false;
854 domain = wb_child_domain();
855 if (domain == NULL) {
856 return NT_STATUS_REQUEST_NOT_ACCEPTED;
859 reconnect:
860 status = cm_connect_netlogon(domain, &netlogon_pipe);
861 if (!NT_STATUS_IS_OK(status)) {
862 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
863 goto done;
866 b = netlogon_pipe->binding_handle;
868 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
869 netlogon_pipe->binding_handle,
870 r->in.site_name,
871 r->in.dns_ttl,
872 r->in.dns_names);
874 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
875 retry = true;
876 goto reconnect;
879 /* Pass back result code - zero for success, other values for
880 specific failures. */
882 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
883 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
885 done:
886 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
887 ("Update of DNS records via RW DC %s returned %s\n",
888 domain->name, nt_errstr(status)));
890 return status;
893 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
894 struct winbind_SamLogon *r)
896 struct winbindd_domain *domain;
897 NTSTATUS status;
898 DATA_BLOB lm_response, nt_response;
899 uint32_t flags = 0;
901 domain = wb_child_domain();
902 if (domain == NULL) {
903 return NT_STATUS_REQUEST_NOT_ACCEPTED;
906 /* TODO: Handle interactive logons here */
907 if (r->in.validation_level != 3 ||
908 r->in.logon.network == NULL ||
909 (r->in.logon_level != NetlogonNetworkInformation
910 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
911 return NT_STATUS_REQUEST_NOT_ACCEPTED;
915 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
916 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
918 status = winbind_dual_SamLogon(domain, p->mem_ctx,
919 r->in.logon.network->identity_info.parameter_control,
920 r->in.logon.network->identity_info.account_name.string,
921 r->in.logon.network->identity_info.domain_name.string,
922 r->in.logon.network->identity_info.workstation.string,
923 r->in.logon.network->challenge,
924 lm_response, nt_response,
925 &r->out.authoritative,
926 true,
927 &flags,
928 &r->out.validation.sam3);
929 return status;
932 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
933 struct winbindd_domain *domain,
934 struct winbind_LogonControl *r)
936 NTSTATUS status;
937 struct rpc_pipe_client *netlogon_pipe = NULL;
938 struct netr_NETLOGON_INFO_2 *info2 = NULL;
939 WERROR check_result = WERR_INTERNAL_ERROR;
941 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
942 if (info2 == NULL) {
943 return WERR_NOT_ENOUGH_MEMORY;
946 if (domain->internal) {
947 check_result = WERR_OK;
948 goto check_return;
952 * For now we just force a reconnect
954 * TODO: take care of the optional '\dcname'
956 invalidate_cm_connection(domain);
957 domain->conn.netlogon_force_reauth = true;
958 status = cm_connect_netlogon(domain, &netlogon_pipe);
959 reset_cm_connection_on_error(domain, NULL, status);
960 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
961 status = NT_STATUS_NO_LOGON_SERVERS;
963 if (!NT_STATUS_IS_OK(status)) {
964 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
965 __func__, domain->name, domain->alt_name,
966 nt_errstr(status)));
968 * Here we return a top level error!
969 * This is different than TC_QUERY or TC_VERIFY.
971 return ntstatus_to_werror(status);
973 check_result = WERR_OK;
975 check_return:
976 info2->pdc_connection_status = WERR_OK;
977 if (domain->dcname != NULL) {
978 info2->flags |= NETLOGON_HAS_IP;
979 info2->flags |= NETLOGON_HAS_TIMESERV;
980 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
981 domain->dcname);
982 if (info2->trusted_dc_name == NULL) {
983 return WERR_NOT_ENOUGH_MEMORY;
985 } else {
986 info2->trusted_dc_name = talloc_strdup(info2, "");
987 if (info2->trusted_dc_name == NULL) {
988 return WERR_NOT_ENOUGH_MEMORY;
991 info2->tc_connection_status = check_result;
993 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
994 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
995 "pdc_connection[%s] tc_connection[%s]\n",
996 __func__, domain->name, domain->alt_name,
997 domain->dcname,
998 win_errstr(info2->pdc_connection_status),
999 win_errstr(info2->tc_connection_status)));
1002 r->out.query->info2 = info2;
1004 DEBUG(5, ("%s: succeeded.\n", __func__));
1005 return WERR_OK;
1008 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1009 struct winbindd_domain *domain,
1010 struct winbind_LogonControl *r)
1012 NTSTATUS status;
1013 struct rpc_pipe_client *netlogon_pipe = NULL;
1014 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1015 WERROR check_result = WERR_INTERNAL_ERROR;
1017 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1018 if (info2 == NULL) {
1019 return WERR_NOT_ENOUGH_MEMORY;
1022 if (domain->internal) {
1023 check_result = WERR_OK;
1024 goto check_return;
1027 status = cm_connect_netlogon(domain, &netlogon_pipe);
1028 reset_cm_connection_on_error(domain, NULL, status);
1029 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1030 status = NT_STATUS_NO_LOGON_SERVERS;
1032 if (!NT_STATUS_IS_OK(status)) {
1033 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1034 nt_errstr(status)));
1035 check_result = ntstatus_to_werror(status);
1036 goto check_return;
1038 check_result = WERR_OK;
1040 check_return:
1041 info2->pdc_connection_status = WERR_OK;
1042 if (domain->dcname != NULL) {
1043 info2->flags |= NETLOGON_HAS_IP;
1044 info2->flags |= NETLOGON_HAS_TIMESERV;
1045 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1046 domain->dcname);
1047 if (info2->trusted_dc_name == NULL) {
1048 return WERR_NOT_ENOUGH_MEMORY;
1050 } else {
1051 info2->trusted_dc_name = talloc_strdup(info2, "");
1052 if (info2->trusted_dc_name == NULL) {
1053 return WERR_NOT_ENOUGH_MEMORY;
1056 info2->tc_connection_status = check_result;
1058 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1059 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1060 "pdc_connection[%s] tc_connection[%s]\n",
1061 __func__, domain->name, domain->alt_name,
1062 domain->dcname,
1063 win_errstr(info2->pdc_connection_status),
1064 win_errstr(info2->tc_connection_status)));
1067 r->out.query->info2 = info2;
1069 DEBUG(5, ("%s: succeeded.\n", __func__));
1070 return WERR_OK;
1073 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1074 struct winbindd_domain *domain,
1075 struct winbind_LogonControl *r)
1077 TALLOC_CTX *frame = talloc_stackframe();
1078 NTSTATUS status;
1079 NTSTATUS result;
1080 struct lsa_String trusted_domain_name = {};
1081 struct lsa_StringLarge trusted_domain_name_l = {};
1082 struct rpc_pipe_client *local_lsa_pipe = NULL;
1083 struct policy_handle local_lsa_policy = {};
1084 struct dcerpc_binding_handle *local_lsa = NULL;
1085 struct rpc_pipe_client *netlogon_pipe = NULL;
1086 struct cli_credentials *creds = NULL;
1087 struct samr_Password *cur_nt_hash = NULL;
1088 uint32_t trust_attributes = 0;
1089 struct samr_Password new_owf_password = {};
1090 int cmp_new = -1;
1091 struct samr_Password old_owf_password = {};
1092 int cmp_old = -1;
1093 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1094 bool fetch_fti = false;
1095 struct lsa_ForestTrustInformation *new_fti = NULL;
1096 struct netr_TrustInfo *trust_info = NULL;
1097 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1098 struct dcerpc_binding_handle *b = NULL;
1099 WERROR check_result = WERR_INTERNAL_ERROR;
1100 WERROR verify_result = WERR_INTERNAL_ERROR;
1101 bool retry = false;
1103 trusted_domain_name.string = domain->name;
1104 trusted_domain_name_l.string = domain->name;
1106 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1107 if (info2 == NULL) {
1108 TALLOC_FREE(frame);
1109 return WERR_NOT_ENOUGH_MEMORY;
1112 if (domain->internal) {
1113 check_result = WERR_OK;
1114 goto check_return;
1117 status = pdb_get_trust_credentials(domain->name,
1118 domain->alt_name,
1119 frame,
1120 &creds);
1121 if (NT_STATUS_IS_OK(status)) {
1122 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1123 TALLOC_FREE(creds);
1126 if (!domain->primary) {
1127 union lsa_TrustedDomainInfo *tdi = NULL;
1129 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1130 &local_lsa_policy);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1133 __location__, __func__, nt_errstr(status)));
1134 TALLOC_FREE(frame);
1135 return WERR_INTERNAL_ERROR;
1137 local_lsa = local_lsa_pipe->binding_handle;
1139 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1140 &local_lsa_policy,
1141 &trusted_domain_name,
1142 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1143 &tdi, &result);
1144 if (!NT_STATUS_IS_OK(status)) {
1145 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1146 __location__, __func__, domain->name, nt_errstr(status)));
1147 TALLOC_FREE(frame);
1148 return WERR_INTERNAL_ERROR;
1150 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1151 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1152 __location__, __func__, domain->name));
1153 TALLOC_FREE(frame);
1154 return WERR_NO_SUCH_DOMAIN;
1156 if (!NT_STATUS_IS_OK(result)) {
1157 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1158 __location__, __func__, domain->name, nt_errstr(result)));
1159 TALLOC_FREE(frame);
1160 return WERR_INTERNAL_ERROR;
1162 if (tdi == NULL) {
1163 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1164 "returned no trusted domain information\n",
1165 __location__, __func__));
1166 TALLOC_FREE(frame);
1167 return WERR_INTERNAL_ERROR;
1170 local_tdo = &tdi->info_ex;
1171 trust_attributes = local_tdo->trust_attributes;
1174 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1175 struct lsa_ForestTrustInformation *old_fti = NULL;
1177 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1178 &local_lsa_policy,
1179 &trusted_domain_name,
1180 LSA_FOREST_TRUST_DOMAIN_INFO,
1181 &old_fti, &result);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1184 __location__, __func__, domain->name, nt_errstr(status)));
1185 TALLOC_FREE(frame);
1186 return WERR_INTERNAL_ERROR;
1188 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1189 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1190 __func__, domain->name));
1191 old_fti = NULL;
1192 fetch_fti = true;
1193 result = NT_STATUS_OK;
1195 if (!NT_STATUS_IS_OK(result)) {
1196 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1197 __location__, __func__, domain->name, nt_errstr(result)));
1198 TALLOC_FREE(frame);
1199 return WERR_INTERNAL_ERROR;
1202 TALLOC_FREE(old_fti);
1205 reconnect:
1206 status = cm_connect_netlogon(domain, &netlogon_pipe);
1207 reset_cm_connection_on_error(domain, NULL, status);
1208 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1209 status = NT_STATUS_NO_LOGON_SERVERS;
1211 if (!NT_STATUS_IS_OK(status)) {
1212 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1213 nt_errstr(status)));
1214 check_result = ntstatus_to_werror(status);
1215 goto check_return;
1217 check_result = WERR_OK;
1218 b = netlogon_pipe->binding_handle;
1220 if (cur_nt_hash == NULL) {
1221 verify_result = WERR_NO_TRUST_LSA_SECRET;
1222 goto verify_return;
1225 if (fetch_fti) {
1226 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1227 b, frame,
1228 &new_fti);
1229 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1230 status = NT_STATUS_NOT_SUPPORTED;
1232 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1233 new_fti = NULL;
1234 status = NT_STATUS_OK;
1236 if (!NT_STATUS_IS_OK(status)) {
1237 if (!retry &&
1238 reset_cm_connection_on_error(domain, b, status))
1240 retry = true;
1241 goto reconnect;
1243 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1244 "failed: %s\n",
1245 domain->name, nt_errstr(status)));
1246 check_result = ntstatus_to_werror(status);
1247 goto check_return;
1251 if (new_fti != NULL) {
1252 struct lsa_ForestTrustInformation old_fti = {};
1253 struct lsa_ForestTrustInformation *merged_fti = NULL;
1254 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1256 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1257 &old_fti, new_fti,
1258 &merged_fti);
1259 if (!NT_STATUS_IS_OK(status)) {
1260 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1261 __location__, __func__,
1262 domain->name, nt_errstr(status)));
1263 TALLOC_FREE(frame);
1264 return ntstatus_to_werror(status);
1267 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1268 &local_lsa_policy,
1269 &trusted_domain_name_l,
1270 LSA_FOREST_TRUST_DOMAIN_INFO,
1271 merged_fti,
1272 0, /* check_only=0 => store it! */
1273 &collision_info,
1274 &result);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1277 __location__, __func__, domain->name, nt_errstr(status)));
1278 TALLOC_FREE(frame);
1279 return WERR_INTERNAL_ERROR;
1281 if (!NT_STATUS_IS_OK(result)) {
1282 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1283 __location__, __func__, domain->name, nt_errstr(result)));
1284 TALLOC_FREE(frame);
1285 return ntstatus_to_werror(result);
1289 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1290 b, frame,
1291 &new_owf_password,
1292 &old_owf_password,
1293 &trust_info);
1294 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1295 status = NT_STATUS_NOT_SUPPORTED;
1297 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1298 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1299 nt_errstr(status)));
1300 verify_result = WERR_OK;
1301 goto verify_return;
1303 if (!NT_STATUS_IS_OK(status)) {
1304 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1305 retry = true;
1306 goto reconnect;
1308 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1309 nt_errstr(status)));
1311 if (!dcerpc_binding_handle_is_connected(b)) {
1312 check_result = ntstatus_to_werror(status);
1313 goto check_return;
1314 } else {
1315 verify_result = ntstatus_to_werror(status);
1316 goto verify_return;
1320 if (trust_info != NULL && trust_info->count >= 1) {
1321 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1323 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1324 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1325 goto verify_return;
1329 cmp_new = memcmp(new_owf_password.hash,
1330 cur_nt_hash->hash,
1331 sizeof(cur_nt_hash->hash));
1332 cmp_old = memcmp(old_owf_password.hash,
1333 cur_nt_hash->hash,
1334 sizeof(cur_nt_hash->hash));
1335 if (cmp_new != 0 && cmp_old != 0) {
1336 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1337 "any password known to dcname[%s]\n",
1338 __func__, domain->name, domain->alt_name,
1339 domain->dcname));
1340 verify_result = WERR_WRONG_PASSWORD;
1341 goto verify_return;
1344 if (cmp_new != 0) {
1345 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1346 "against the old password known to dcname[%s]\n",
1347 __func__, domain->name, domain->alt_name,
1348 domain->dcname));
1351 verify_result = WERR_OK;
1352 goto verify_return;
1354 check_return:
1355 verify_result = check_result;
1356 verify_return:
1357 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1358 info2->pdc_connection_status = verify_result;
1359 if (domain->dcname != NULL) {
1360 info2->flags |= NETLOGON_HAS_IP;
1361 info2->flags |= NETLOGON_HAS_TIMESERV;
1362 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1363 domain->dcname);
1364 if (info2->trusted_dc_name == NULL) {
1365 TALLOC_FREE(frame);
1366 return WERR_NOT_ENOUGH_MEMORY;
1368 } else {
1369 info2->trusted_dc_name = talloc_strdup(info2, "");
1370 if (info2->trusted_dc_name == NULL) {
1371 TALLOC_FREE(frame);
1372 return WERR_NOT_ENOUGH_MEMORY;
1375 info2->tc_connection_status = check_result;
1377 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1378 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1379 "pdc_connection[%s] tc_connection[%s]\n",
1380 __func__, domain->name, domain->alt_name,
1381 domain->dcname,
1382 win_errstr(info2->pdc_connection_status),
1383 win_errstr(info2->tc_connection_status)));
1386 r->out.query->info2 = info2;
1388 DEBUG(5, ("%s: succeeded.\n", __func__));
1389 TALLOC_FREE(frame);
1390 return WERR_OK;
1393 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1394 struct winbindd_domain *domain,
1395 struct winbind_LogonControl *r)
1397 struct messaging_context *msg_ctx = server_messaging_context();
1398 NTSTATUS status;
1399 struct rpc_pipe_client *netlogon_pipe;
1400 struct cli_credentials *creds = NULL;
1401 struct samr_Password *cur_nt_hash = NULL;
1402 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1403 struct dcerpc_binding_handle *b;
1404 WERROR change_result = WERR_OK;
1405 bool retry = false;
1407 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1408 if (info1 == NULL) {
1409 return WERR_NOT_ENOUGH_MEMORY;
1412 if (domain->internal) {
1413 return WERR_NOT_SUPPORTED;
1416 status = pdb_get_trust_credentials(domain->name,
1417 domain->alt_name,
1418 p->mem_ctx,
1419 &creds);
1420 if (NT_STATUS_IS_OK(status)) {
1421 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1422 TALLOC_FREE(creds);
1425 reconnect:
1426 status = cm_connect_netlogon(domain, &netlogon_pipe);
1427 reset_cm_connection_on_error(domain, NULL, status);
1428 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1429 status = NT_STATUS_NO_LOGON_SERVERS;
1431 if (!NT_STATUS_IS_OK(status)) {
1432 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1433 __func__, domain->name, domain->alt_name,
1434 nt_errstr(status)));
1436 * Here we return a top level error!
1437 * This is different than TC_QUERY or TC_VERIFY.
1439 return ntstatus_to_werror(status);
1441 b = netlogon_pipe->binding_handle;
1443 if (cur_nt_hash == NULL) {
1444 change_result = WERR_NO_TRUST_LSA_SECRET;
1445 goto change_return;
1447 TALLOC_FREE(cur_nt_hash);
1449 status = trust_pw_change(domain->conn.netlogon_creds,
1450 msg_ctx, b, domain->name,
1451 domain->dcname,
1452 true); /* force */
1453 if (!NT_STATUS_IS_OK(status)) {
1454 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1455 retry = true;
1456 goto reconnect;
1459 DEBUG(1, ("trust_pw_change(%s): %s\n",
1460 domain->name, nt_errstr(status)));
1462 change_result = ntstatus_to_werror(status);
1463 goto change_return;
1466 change_result = WERR_OK;
1468 change_return:
1469 info1->pdc_connection_status = change_result;
1471 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1472 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1473 "pdc_connection[%s]\n",
1474 __func__, domain->name, domain->alt_name,
1475 domain->dcname,
1476 win_errstr(info1->pdc_connection_status)));
1479 r->out.query->info1 = info1;
1481 DEBUG(5, ("%s: succeeded.\n", __func__));
1482 return WERR_OK;
1485 WERROR _winbind_LogonControl(struct pipes_struct *p,
1486 struct winbind_LogonControl *r)
1488 struct winbindd_domain *domain;
1490 domain = wb_child_domain();
1491 if (domain == NULL) {
1492 return WERR_NO_SUCH_DOMAIN;
1495 switch (r->in.function_code) {
1496 case NETLOGON_CONTROL_REDISCOVER:
1497 if (r->in.level != 2) {
1498 return WERR_INVALID_PARAMETER;
1500 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1501 case NETLOGON_CONTROL_TC_QUERY:
1502 if (r->in.level != 2) {
1503 return WERR_INVALID_PARAMETER;
1505 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1506 case NETLOGON_CONTROL_TC_VERIFY:
1507 if (r->in.level != 2) {
1508 return WERR_INVALID_PARAMETER;
1510 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1511 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1512 if (r->in.level != 1) {
1513 return WERR_INVALID_PARAMETER;
1515 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1516 default:
1517 break;
1520 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1521 __func__, r->in.function_code));
1522 return WERR_NOT_SUPPORTED;
1525 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1526 struct winbind_GetForestTrustInformation *r)
1528 TALLOC_CTX *frame = talloc_stackframe();
1529 NTSTATUS status, result;
1530 struct winbindd_domain *domain;
1531 struct rpc_pipe_client *netlogon_pipe;
1532 struct dcerpc_binding_handle *b;
1533 bool retry = false;
1534 struct lsa_String trusted_domain_name = {};
1535 struct lsa_StringLarge trusted_domain_name_l = {};
1536 union lsa_TrustedDomainInfo *tdi = NULL;
1537 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1538 struct lsa_ForestTrustInformation _old_fti = {};
1539 struct lsa_ForestTrustInformation *old_fti = NULL;
1540 struct lsa_ForestTrustInformation *new_fti = NULL;
1541 struct lsa_ForestTrustInformation *merged_fti = NULL;
1542 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1543 bool update_fti = false;
1544 struct rpc_pipe_client *local_lsa_pipe;
1545 struct policy_handle local_lsa_policy;
1546 struct dcerpc_binding_handle *local_lsa = NULL;
1548 domain = wb_child_domain();
1549 if (domain == NULL) {
1550 TALLOC_FREE(frame);
1551 return WERR_NO_SUCH_DOMAIN;
1555 * checking for domain->internal and domain->primary
1556 * makes sure we only do some work when running as DC.
1559 if (domain->internal) {
1560 TALLOC_FREE(frame);
1561 return WERR_NO_SUCH_DOMAIN;
1564 if (domain->primary) {
1565 TALLOC_FREE(frame);
1566 return WERR_NO_SUCH_DOMAIN;
1569 trusted_domain_name.string = domain->name;
1570 trusted_domain_name_l.string = domain->name;
1572 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1573 &local_lsa_policy);
1574 if (!NT_STATUS_IS_OK(status)) {
1575 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1576 __location__, __func__, nt_errstr(status)));
1577 TALLOC_FREE(frame);
1578 return WERR_INTERNAL_ERROR;
1580 local_lsa = local_lsa_pipe->binding_handle;
1582 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1583 &local_lsa_policy,
1584 &trusted_domain_name,
1585 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1586 &tdi, &result);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1589 __location__, __func__, domain->name, nt_errstr(status)));
1590 TALLOC_FREE(frame);
1591 return WERR_INTERNAL_ERROR;
1593 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1594 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1595 __location__, __func__, domain->name));
1596 TALLOC_FREE(frame);
1597 return WERR_NO_SUCH_DOMAIN;
1599 if (!NT_STATUS_IS_OK(result)) {
1600 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1601 __location__, __func__, domain->name, nt_errstr(result)));
1602 TALLOC_FREE(frame);
1603 return WERR_INTERNAL_ERROR;
1605 if (tdi == NULL) {
1606 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1607 "returned no trusted domain information\n",
1608 __location__, __func__));
1609 TALLOC_FREE(frame);
1610 return WERR_INTERNAL_ERROR;
1613 tdo = &tdi->info_ex;
1615 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1616 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1617 __func__, tdo->netbios_name.string,
1618 tdo->domain_name.string,
1619 (unsigned)tdo->trust_attributes));
1620 TALLOC_FREE(frame);
1621 return WERR_NO_SUCH_DOMAIN;
1624 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1625 TALLOC_FREE(frame);
1626 return WERR_INVALID_FLAGS;
1629 reconnect:
1630 status = cm_connect_netlogon(domain, &netlogon_pipe);
1631 reset_cm_connection_on_error(domain, NULL, status);
1632 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1633 status = NT_STATUS_NO_LOGON_SERVERS;
1635 if (!NT_STATUS_IS_OK(status)) {
1636 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1637 nt_errstr(status)));
1638 TALLOC_FREE(frame);
1639 return ntstatus_to_werror(status);
1641 b = netlogon_pipe->binding_handle;
1643 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1644 b, p->mem_ctx,
1645 &new_fti);
1646 if (!NT_STATUS_IS_OK(status)) {
1647 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1648 retry = true;
1649 goto reconnect;
1651 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1652 domain->name, nt_errstr(status)));
1653 TALLOC_FREE(frame);
1654 return ntstatus_to_werror(status);
1657 *r->out.forest_trust_info = new_fti;
1659 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1660 update_fti = true;
1663 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1664 &local_lsa_policy,
1665 &trusted_domain_name,
1666 LSA_FOREST_TRUST_DOMAIN_INFO,
1667 &old_fti, &result);
1668 if (!NT_STATUS_IS_OK(status)) {
1669 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1670 __location__, __func__, domain->name, nt_errstr(status)));
1671 TALLOC_FREE(frame);
1672 return WERR_INTERNAL_ERROR;
1674 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1675 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1676 __func__, domain->name));
1677 update_fti = true;
1678 old_fti = &_old_fti;
1679 result = NT_STATUS_OK;
1681 if (!NT_STATUS_IS_OK(result)) {
1682 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1683 __location__, __func__, domain->name, nt_errstr(result)));
1684 TALLOC_FREE(frame);
1685 return WERR_INTERNAL_ERROR;
1688 if (old_fti == NULL) {
1689 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1690 "returned success without returning forest trust information\n",
1691 __location__, __func__));
1692 TALLOC_FREE(frame);
1693 return WERR_INTERNAL_ERROR;
1696 if (!update_fti) {
1697 goto done;
1700 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1701 &merged_fti);
1702 if (!NT_STATUS_IS_OK(status)) {
1703 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1704 __location__, __func__, domain->name, nt_errstr(status)));
1705 TALLOC_FREE(frame);
1706 return ntstatus_to_werror(status);
1709 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1710 &local_lsa_policy,
1711 &trusted_domain_name_l,
1712 LSA_FOREST_TRUST_DOMAIN_INFO,
1713 merged_fti,
1714 0, /* check_only=0 => store it! */
1715 &collision_info,
1716 &result);
1717 if (!NT_STATUS_IS_OK(status)) {
1718 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1719 __location__, __func__, domain->name, nt_errstr(status)));
1720 TALLOC_FREE(frame);
1721 return WERR_INTERNAL_ERROR;
1723 if (!NT_STATUS_IS_OK(result)) {
1724 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1725 __location__, __func__, domain->name, nt_errstr(result)));
1726 TALLOC_FREE(frame);
1727 return ntstatus_to_werror(result);
1730 done:
1731 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1732 TALLOC_FREE(frame);
1733 return WERR_OK;
1736 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1738 struct winbindd_domain *domain;
1739 NTSTATUS status;
1740 struct rpc_pipe_client *netlogon_pipe;
1741 struct dcerpc_binding_handle *b = NULL;
1742 bool retry = false;
1744 DEBUG(5, ("_winbind_SendToSam received\n"));
1745 domain = wb_child_domain();
1746 if (domain == NULL) {
1747 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1750 reconnect:
1751 status = cm_connect_netlogon(domain, &netlogon_pipe);
1752 if (!NT_STATUS_IS_OK(status)) {
1753 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1754 return status;
1757 b = netlogon_pipe->binding_handle;
1759 status = netlogon_creds_cli_SendToSam(domain->conn.netlogon_creds,
1760 netlogon_pipe->binding_handle,
1761 &r->in.message);
1762 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1763 retry = true;
1764 goto reconnect;
1767 return status;