winbind: Pass up args from winbind_dual_SamLogon
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob763ebb888403cde1ebb993cf500e17ebadc6cce6
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 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
43 NTSTATUS status)
45 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
46 invalidate_cm_connection(domain);
47 /* We invalidated the connection. */
48 return true;
50 return false;
53 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
55 struct winbindd_domain *domain = wb_child_domain();
56 char *dom_name;
57 char *name;
58 enum lsa_SidType type;
59 NTSTATUS status;
61 if (domain == NULL) {
62 return NT_STATUS_REQUEST_NOT_ACCEPTED;
65 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
66 &dom_name, &name, &type);
67 reset_cm_connection_on_error(domain, status);
68 if (!NT_STATUS_IS_OK(status)) {
69 return status;
72 *r->out.domain = dom_name;
73 *r->out.name = name;
74 *r->out.type = type;
75 return NT_STATUS_OK;
78 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
80 struct winbindd_domain *domain = wb_child_domain();
81 struct lsa_RefDomainList *domains = r->out.domains;
82 NTSTATUS status;
84 if (domain == NULL) {
85 return NT_STATUS_REQUEST_NOT_ACCEPTED;
89 * This breaks the winbindd_domain->methods abstraction: This
90 * is only called for remote domains, and both winbindd_msrpc
91 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
92 * done at the wbint RPC layer.
94 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
95 &domains, &r->out.names);
97 if (domains != NULL) {
98 r->out.domains = domains;
101 reset_cm_connection_on_error(domain, status);
102 return status;
105 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
107 struct winbindd_domain *domain = wb_child_domain();
108 NTSTATUS status;
110 if (domain == NULL) {
111 return NT_STATUS_REQUEST_NOT_ACCEPTED;
114 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
115 r->in.name, r->in.flags,
116 r->out.sid, r->out.type);
117 reset_cm_connection_on_error(domain, status);
118 return status;
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
124 uint32_t i;
126 struct lsa_DomainInfo *d;
127 struct wbint_TransID *ids;
128 uint32_t num_ids;
130 struct id_map **id_map_ptrs = NULL;
131 struct idmap_domain *dom;
132 NTSTATUS status = NT_STATUS_NO_MEMORY;
134 if (r->in.domains->count != 1) {
135 return NT_STATUS_INVALID_PARAMETER;
138 d = &r->in.domains->domains[0];
139 ids = r->in.ids->ids;
140 num_ids = r->in.ids->num_ids;
142 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
143 if (dom == NULL) {
144 DEBUG(10, ("idmap domain %s:%s not found\n",
145 d->name.string, sid_string_dbg(d->sid)));
147 for (i=0; i<num_ids; i++) {
149 ids[i].xid = (struct unixid) {
150 .id = UINT32_MAX,
151 .type = ID_TYPE_NOT_SPECIFIED
155 return NT_STATUS_OK;
158 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
159 if (id_map_ptrs == NULL) {
160 goto nomem;
164 * Convert the input data into a list of id_map structs
165 * suitable for handing in to the idmap sids_to_unixids
166 * method.
169 for (i=0; i<num_ids; i++) {
170 struct id_map *m = id_map_ptrs[i];
172 sid_compose(m->sid, d->sid, ids[i].rid);
173 m->status = ID_UNKNOWN;
174 m->xid = (struct unixid) { .type = ids[i].type };
177 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
179 if (!NT_STATUS_IS_OK(status)) {
180 DEBUG(10, ("sids_to_unixids returned %s\n",
181 nt_errstr(status)));
182 goto done;
186 * Extract the results for handing them back to the caller.
189 for (i=0; i<num_ids; i++) {
190 struct id_map *m = id_map_ptrs[i];
192 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
193 m->status = ID_UNMAPPED;
196 if (m->status == ID_MAPPED) {
197 ids[i].xid = m->xid;
198 } else {
199 ids[i].xid.id = UINT32_MAX;
200 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
204 goto done;
205 nomem:
206 status = NT_STATUS_NO_MEMORY;
207 done:
208 TALLOC_FREE(id_map_ptrs);
209 return status;
212 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
213 struct wbint_UnixIDs2Sids *r)
215 struct id_map **maps;
216 NTSTATUS status;
217 uint32_t i;
219 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
220 if (maps == NULL) {
221 return NT_STATUS_NO_MEMORY;
224 for (i=0; i<r->in.num_ids; i++) {
225 maps[i]->status = ID_UNKNOWN;
226 maps[i]->xid = r->in.xids[i];
229 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name);
230 if (!NT_STATUS_IS_OK(status)) {
231 TALLOC_FREE(maps);
232 return status;
235 for (i=0; i<r->in.num_ids; i++) {
236 r->out.xids[i] = maps[i]->xid;
237 sid_copy(&r->out.sids[i], maps[i]->sid);
240 TALLOC_FREE(maps);
242 return NT_STATUS_OK;
245 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
247 struct unixid xid;
248 NTSTATUS status;
250 status = idmap_allocate_uid(&xid);
251 if (!NT_STATUS_IS_OK(status)) {
252 return status;
254 *r->out.uid = xid.id;
255 return NT_STATUS_OK;
258 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
260 struct unixid xid;
261 NTSTATUS status;
263 status = idmap_allocate_gid(&xid);
264 if (!NT_STATUS_IS_OK(status)) {
265 return status;
267 *r->out.gid = xid.id;
268 return NT_STATUS_OK;
271 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
273 struct idmap_domain *domain;
274 NTSTATUS status;
276 domain = idmap_find_domain(r->in.info->domain_name);
277 if ((domain == NULL) || (domain->query_user == NULL)) {
278 return NT_STATUS_REQUEST_NOT_ACCEPTED;
281 status = domain->query_user(domain, r->in.info);
282 return status;
285 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
286 struct wbint_LookupUserAliases *r)
288 struct winbindd_domain *domain = wb_child_domain();
289 NTSTATUS status;
291 if (domain == NULL) {
292 return NT_STATUS_REQUEST_NOT_ACCEPTED;
295 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
296 r->in.sids->num_sids,
297 r->in.sids->sids,
298 &r->out.rids->num_rids,
299 &r->out.rids->rids);
300 reset_cm_connection_on_error(domain, status);
301 return status;
304 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
305 struct wbint_LookupUserGroups *r)
307 struct winbindd_domain *domain = wb_child_domain();
308 NTSTATUS status;
310 if (domain == NULL) {
311 return NT_STATUS_REQUEST_NOT_ACCEPTED;
314 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
315 &r->out.sids->num_sids,
316 &r->out.sids->sids);
317 reset_cm_connection_on_error(domain, status);
318 return status;
321 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
322 struct wbint_QuerySequenceNumber *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_sequence_number(domain, r->out.sequence);
332 reset_cm_connection_on_error(domain, status);
333 return status;
336 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
337 struct wbint_LookupGroupMembers *r)
339 struct winbindd_domain *domain = wb_child_domain();
340 uint32_t i, num_names;
341 struct dom_sid *sid_mem;
342 char **names;
343 uint32_t *name_types;
344 NTSTATUS status;
346 if (domain == NULL) {
347 return NT_STATUS_REQUEST_NOT_ACCEPTED;
350 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
351 r->in.type, &num_names, &sid_mem,
352 &names, &name_types);
353 reset_cm_connection_on_error(domain, status);
354 if (!NT_STATUS_IS_OK(status)) {
355 return status;
358 r->out.members->num_principals = num_names;
359 r->out.members->principals = talloc_array(
360 r->out.members, struct wbint_Principal, num_names);
361 if (r->out.members->principals == NULL) {
362 return NT_STATUS_NO_MEMORY;
365 for (i=0; i<num_names; i++) {
366 struct wbint_Principal *m = &r->out.members->principals[i];
367 sid_copy(&m->sid, &sid_mem[i]);
368 m->name = talloc_move(r->out.members->principals, &names[i]);
369 m->type = (enum lsa_SidType)name_types[i];
372 return NT_STATUS_OK;
375 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
376 struct wbint_QueryGroupList *r)
378 struct winbindd_domain *domain = wb_child_domain();
379 uint32_t i;
380 uint32_t num_local_groups = 0;
381 struct wb_acct_info *local_groups = NULL;
382 uint32_t num_dom_groups = 0;
383 struct wb_acct_info *dom_groups = NULL;
384 uint32_t ti = 0;
385 uint64_t num_total = 0;
386 struct wbint_Principal *result;
387 NTSTATUS status;
388 bool include_local_groups = false;
390 if (domain == NULL) {
391 return NT_STATUS_REQUEST_NOT_ACCEPTED;
394 switch (lp_server_role()) {
395 case ROLE_ACTIVE_DIRECTORY_DC:
396 if (domain->internal) {
398 * we want to include local groups
399 * for BUILTIN and WORKGROUP
401 include_local_groups = true;
403 break;
404 default:
406 * We might include local groups in more
407 * setups later, but that requires more work
408 * elsewhere.
410 break;
413 if (include_local_groups) {
414 status = wb_cache_enum_local_groups(domain, talloc_tos(),
415 &num_local_groups,
416 &local_groups);
417 reset_cm_connection_on_error(domain, status);
418 if (!NT_STATUS_IS_OK(status)) {
419 return status;
423 status = wb_cache_enum_dom_groups(domain, talloc_tos(),
424 &num_dom_groups,
425 &dom_groups);
426 reset_cm_connection_on_error(domain, status);
427 if (!NT_STATUS_IS_OK(status)) {
428 return status;
431 num_total = num_local_groups + num_dom_groups;
432 if (num_total > UINT32_MAX) {
433 return NT_STATUS_INTERNAL_ERROR;
436 result = talloc_array(r->out.groups, struct wbint_Principal,
437 num_total);
438 if (result == NULL) {
439 return NT_STATUS_NO_MEMORY;
442 for (i = 0; i < num_local_groups; i++) {
443 struct wb_acct_info *lg = &local_groups[i];
444 struct wbint_Principal *rg = &result[ti++];
446 sid_compose(&rg->sid, &domain->sid, lg->rid);
447 rg->type = SID_NAME_ALIAS;
448 rg->name = talloc_strdup(result, lg->acct_name);
449 if (rg->name == NULL) {
450 TALLOC_FREE(result);
451 TALLOC_FREE(dom_groups);
452 TALLOC_FREE(local_groups);
453 return NT_STATUS_NO_MEMORY;
456 num_local_groups = 0;
457 TALLOC_FREE(local_groups);
459 for (i = 0; i < num_dom_groups; i++) {
460 struct wb_acct_info *dg = &dom_groups[i];
461 struct wbint_Principal *rg = &result[ti++];
463 sid_compose(&rg->sid, &domain->sid, dg->rid);
464 rg->type = SID_NAME_DOM_GRP;
465 rg->name = talloc_strdup(result, dg->acct_name);
466 if (rg->name == NULL) {
467 TALLOC_FREE(result);
468 TALLOC_FREE(dom_groups);
469 TALLOC_FREE(local_groups);
470 return NT_STATUS_NO_MEMORY;
473 num_dom_groups = 0;
474 TALLOC_FREE(dom_groups);
476 r->out.groups->num_principals = ti;
477 r->out.groups->principals = result;
479 return NT_STATUS_OK;
482 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
483 struct wbint_QueryUserRidList *r)
485 struct winbindd_domain *domain = wb_child_domain();
486 NTSTATUS status;
488 if (domain == NULL) {
489 return NT_STATUS_REQUEST_NOT_ACCEPTED;
493 * Right now this is overkill. We should add a backend call
494 * just querying the rids.
497 status = wb_cache_query_user_list(domain, p->mem_ctx,
498 &r->out.rids->rids);
499 reset_cm_connection_on_error(domain, status);
501 if (!NT_STATUS_IS_OK(status)) {
502 return status;
505 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
507 return NT_STATUS_OK;
510 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
512 struct winbindd_domain *domain = wb_child_domain();
513 struct rpc_pipe_client *netlogon_pipe;
514 struct netr_DsRGetDCNameInfo *dc_info;
515 NTSTATUS status;
516 WERROR werr;
517 unsigned int orig_timeout;
518 struct dcerpc_binding_handle *b;
520 if (domain == NULL) {
521 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
522 r->in.domain_name, r->in.domain_guid,
523 r->in.site_name ? r->in.site_name : "",
524 r->in.flags,
525 r->out.dc_info);
528 status = cm_connect_netlogon(domain, &netlogon_pipe);
530 reset_cm_connection_on_error(domain, status);
531 if (!NT_STATUS_IS_OK(status)) {
532 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
533 return status;
536 b = netlogon_pipe->binding_handle;
538 /* This call can take a long time - allow the server to time out.
539 35 seconds should do it. */
541 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
543 if (domain->active_directory) {
544 status = dcerpc_netr_DsRGetDCName(b,
545 p->mem_ctx, domain->dcname,
546 r->in.domain_name, NULL, r->in.domain_guid,
547 r->in.flags, r->out.dc_info, &werr);
548 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
549 goto done;
551 if (reset_cm_connection_on_error(domain, status)) {
552 /* Re-initialize. */
553 status = cm_connect_netlogon(domain, &netlogon_pipe);
555 reset_cm_connection_on_error(domain, status);
556 if (!NT_STATUS_IS_OK(status)) {
557 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
558 return status;
561 b = netlogon_pipe->binding_handle;
563 /* This call can take a long time - allow the server to time out.
564 35 seconds should do it. */
566 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
571 * Fallback to less capable methods
574 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
575 if (dc_info == NULL) {
576 status = NT_STATUS_NO_MEMORY;
577 goto done;
580 if (r->in.flags & DS_PDC_REQUIRED) {
581 status = dcerpc_netr_GetDcName(b,
582 p->mem_ctx, domain->dcname,
583 r->in.domain_name, &dc_info->dc_unc, &werr);
584 } else {
585 status = dcerpc_netr_GetAnyDCName(b,
586 p->mem_ctx, domain->dcname,
587 r->in.domain_name, &dc_info->dc_unc, &werr);
590 reset_cm_connection_on_error(domain, status);
591 if (!NT_STATUS_IS_OK(status)) {
592 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
593 nt_errstr(status)));
594 goto done;
596 if (!W_ERROR_IS_OK(werr)) {
597 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
598 win_errstr(werr)));
599 status = werror_to_ntstatus(werr);
600 goto done;
603 *r->out.dc_info = dc_info;
604 status = NT_STATUS_OK;
606 done:
607 /* And restore our original timeout. */
608 rpccli_set_timeout(netlogon_pipe, orig_timeout);
610 return status;
613 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
615 struct winbindd_domain *domain = wb_child_domain();
616 char *domain_name;
617 char **names;
618 enum lsa_SidType *types;
619 struct wbint_Principal *result;
620 NTSTATUS status;
621 uint32_t i;
623 if (domain == NULL) {
624 return NT_STATUS_REQUEST_NOT_ACCEPTED;
627 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
628 r->in.rids->rids, r->in.rids->num_rids,
629 &domain_name, &names, &types);
630 reset_cm_connection_on_error(domain, status);
631 if (!NT_STATUS_IS_OK(status)) {
632 return status;
635 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
637 result = talloc_array(p->mem_ctx, struct wbint_Principal,
638 r->in.rids->num_rids);
639 if (result == NULL) {
640 return NT_STATUS_NO_MEMORY;
643 for (i=0; i<r->in.rids->num_rids; i++) {
644 sid_compose(&result[i].sid, r->in.domain_sid,
645 r->in.rids->rids[i]);
646 result[i].type = types[i];
647 result[i].name = talloc_move(result, &names[i]);
649 TALLOC_FREE(types);
650 TALLOC_FREE(names);
652 r->out.names->num_principals = r->in.rids->num_rids;
653 r->out.names->principals = result;
654 return NT_STATUS_OK;
657 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
658 struct wbint_CheckMachineAccount *r)
660 struct winbindd_domain *domain;
661 int num_retries = 0;
662 NTSTATUS status;
664 domain = wb_child_domain();
665 if (domain == NULL) {
666 return NT_STATUS_REQUEST_NOT_ACCEPTED;
669 again:
670 invalidate_cm_connection(domain);
671 domain->conn.netlogon_force_reauth = true;
674 struct rpc_pipe_client *netlogon_pipe;
675 status = cm_connect_netlogon(domain, &netlogon_pipe);
678 /* There is a race condition between fetching the trust account
679 password and the periodic machine password change. So it's
680 possible that the trust account password has been changed on us.
681 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
683 #define MAX_RETRIES 3
685 if ((num_retries < MAX_RETRIES)
686 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
687 num_retries++;
688 goto again;
691 if (!NT_STATUS_IS_OK(status)) {
692 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
693 goto done;
696 /* Pass back result code - zero for success, other values for
697 specific failures. */
699 DEBUG(3,("domain %s secret is %s\n", domain->name,
700 NT_STATUS_IS_OK(status) ? "good" : "bad"));
702 done:
703 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
704 ("Checking the trust account password for domain %s returned %s\n",
705 domain->name, nt_errstr(status)));
707 return status;
710 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
711 struct wbint_ChangeMachineAccount *r)
713 struct messaging_context *msg_ctx = winbind_messaging_context();
714 struct winbindd_domain *domain;
715 NTSTATUS status;
716 struct rpc_pipe_client *netlogon_pipe;
718 domain = wb_child_domain();
719 if (domain == NULL) {
720 return NT_STATUS_REQUEST_NOT_ACCEPTED;
723 status = cm_connect_netlogon(domain, &netlogon_pipe);
724 if (!NT_STATUS_IS_OK(status)) {
725 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
726 goto done;
729 status = trust_pw_change(domain->conn.netlogon_creds,
730 msg_ctx,
731 netlogon_pipe->binding_handle,
732 domain->name,
733 true); /* force */
735 /* Pass back result code - zero for success, other values for
736 specific failures. */
738 DEBUG(3,("domain %s secret %s\n", domain->name,
739 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
741 done:
742 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
743 ("Changing the trust account password for domain %s returned %s\n",
744 domain->name, nt_errstr(status)));
746 return status;
749 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
751 NTSTATUS status;
752 struct winbindd_domain *domain;
753 struct rpc_pipe_client *netlogon_pipe;
754 union netr_CONTROL_QUERY_INFORMATION info;
755 WERROR werr;
756 fstring logon_server;
757 struct dcerpc_binding_handle *b;
758 bool retry = false;
760 domain = wb_child_domain();
761 if (domain == NULL) {
762 return NT_STATUS_REQUEST_NOT_ACCEPTED;
765 reconnect:
766 status = cm_connect_netlogon(domain, &netlogon_pipe);
767 reset_cm_connection_on_error(domain, status);
768 if (!NT_STATUS_IS_OK(status)) {
769 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
770 nt_errstr(status)));
771 return status;
774 b = netlogon_pipe->binding_handle;
776 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
777 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
778 if (*r->out.dcname == NULL) {
779 DEBUG(2, ("Could not allocate memory\n"));
780 return NT_STATUS_NO_MEMORY;
784 * This provokes a WERR_NOT_SUPPORTED error message. This is
785 * documented in the wspp docs. I could not get a successful
786 * call to work, but the main point here is testing that the
787 * netlogon pipe works.
789 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
790 logon_server, NETLOGON_CONTROL_QUERY,
791 2, &info, &werr);
793 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
794 DEBUG(10, ("Session might have expired. "
795 "Reconnect and retry once.\n"));
796 invalidate_cm_connection(domain);
797 retry = true;
798 goto reconnect;
801 reset_cm_connection_on_error(domain, status);
802 if (!NT_STATUS_IS_OK(status)) {
803 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
804 nt_errstr(status)));
805 return status;
808 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
809 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
810 "WERR_NOT_SUPPORTED\n",
811 win_errstr(werr)));
812 return werror_to_ntstatus(werr);
815 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
816 return NT_STATUS_OK;
819 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
820 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
822 struct winbindd_domain *domain;
823 NTSTATUS status;
824 struct rpc_pipe_client *netlogon_pipe;
826 domain = wb_child_domain();
827 if (domain == NULL) {
828 return NT_STATUS_REQUEST_NOT_ACCEPTED;
831 status = cm_connect_netlogon(domain, &netlogon_pipe);
832 if (!NT_STATUS_IS_OK(status)) {
833 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
834 goto done;
837 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
838 netlogon_pipe->binding_handle,
839 r->in.site_name,
840 r->in.dns_ttl,
841 r->in.dns_names);
843 /* Pass back result code - zero for success, other values for
844 specific failures. */
846 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
847 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
849 done:
850 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
851 ("Update of DNS records via RW DC %s returned %s\n",
852 domain->name, nt_errstr(status)));
854 return status;
857 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
858 struct winbind_SamLogon *r)
860 struct winbindd_domain *domain;
861 NTSTATUS status;
862 DATA_BLOB lm_response, nt_response;
863 uint32_t flags;
865 domain = wb_child_domain();
866 if (domain == NULL) {
867 return NT_STATUS_REQUEST_NOT_ACCEPTED;
870 /* TODO: Handle interactive logons here */
871 if (r->in.validation_level != 3 ||
872 r->in.logon.network == NULL ||
873 (r->in.logon_level != NetlogonNetworkInformation
874 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
875 return NT_STATUS_REQUEST_NOT_ACCEPTED;
879 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
880 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
882 status = winbind_dual_SamLogon(domain, p->mem_ctx,
883 r->in.logon.network->identity_info.parameter_control,
884 r->in.logon.network->identity_info.account_name.string,
885 r->in.logon.network->identity_info.domain_name.string,
886 r->in.logon.network->identity_info.workstation.string,
887 r->in.logon.network->challenge,
888 lm_response, nt_response,
889 &r->out.authoritative, &flags,
890 &r->out.validation.sam3);
891 return status;
894 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
895 struct winbindd_domain *domain,
896 struct winbind_LogonControl *r)
898 NTSTATUS status;
899 struct rpc_pipe_client *netlogon_pipe = NULL;
900 struct netr_NETLOGON_INFO_2 *info2 = NULL;
901 WERROR check_result = WERR_INTERNAL_ERROR;
903 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
904 if (info2 == NULL) {
905 return WERR_NOT_ENOUGH_MEMORY;
908 if (domain->internal) {
909 check_result = WERR_OK;
910 goto check_return;
914 * For now we just force a reconnect
916 * TODO: take care of the optional '\dcname'
918 invalidate_cm_connection(domain);
919 domain->conn.netlogon_force_reauth = true;
920 status = cm_connect_netlogon(domain, &netlogon_pipe);
921 reset_cm_connection_on_error(domain, status);
922 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
923 status = NT_STATUS_NO_LOGON_SERVERS;
925 if (!NT_STATUS_IS_OK(status)) {
926 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
927 __func__, domain->name, domain->alt_name,
928 nt_errstr(status)));
930 * Here we return a top level error!
931 * This is different than TC_QUERY or TC_VERIFY.
933 return ntstatus_to_werror(status);
935 check_result = WERR_OK;
937 check_return:
938 info2->pdc_connection_status = WERR_OK;
939 if (domain->dcname != NULL) {
940 info2->flags |= NETLOGON_HAS_IP;
941 info2->flags |= NETLOGON_HAS_TIMESERV;
942 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
943 domain->dcname);
944 if (info2->trusted_dc_name == NULL) {
945 return WERR_NOT_ENOUGH_MEMORY;
947 } else {
948 info2->trusted_dc_name = talloc_strdup(info2, "");
949 if (info2->trusted_dc_name == NULL) {
950 return WERR_NOT_ENOUGH_MEMORY;
953 info2->tc_connection_status = check_result;
955 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
956 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
957 "pdc_connection[%s] tc_connection[%s]\n",
958 __func__, domain->name, domain->alt_name,
959 domain->dcname,
960 win_errstr(info2->pdc_connection_status),
961 win_errstr(info2->tc_connection_status)));
964 r->out.query->info2 = info2;
966 DEBUG(5, ("%s: succeeded.\n", __func__));
967 return WERR_OK;
970 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
971 struct winbindd_domain *domain,
972 struct winbind_LogonControl *r)
974 NTSTATUS status;
975 struct rpc_pipe_client *netlogon_pipe = NULL;
976 struct netr_NETLOGON_INFO_2 *info2 = NULL;
977 WERROR check_result = WERR_INTERNAL_ERROR;
979 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
980 if (info2 == NULL) {
981 return WERR_NOT_ENOUGH_MEMORY;
984 if (domain->internal) {
985 check_result = WERR_OK;
986 goto check_return;
989 status = cm_connect_netlogon(domain, &netlogon_pipe);
990 reset_cm_connection_on_error(domain, status);
991 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
992 status = NT_STATUS_NO_LOGON_SERVERS;
994 if (!NT_STATUS_IS_OK(status)) {
995 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
996 nt_errstr(status)));
997 check_result = ntstatus_to_werror(status);
998 goto check_return;
1000 check_result = WERR_OK;
1002 check_return:
1003 info2->pdc_connection_status = WERR_OK;
1004 if (domain->dcname != NULL) {
1005 info2->flags |= NETLOGON_HAS_IP;
1006 info2->flags |= NETLOGON_HAS_TIMESERV;
1007 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1008 domain->dcname);
1009 if (info2->trusted_dc_name == NULL) {
1010 return WERR_NOT_ENOUGH_MEMORY;
1012 } else {
1013 info2->trusted_dc_name = talloc_strdup(info2, "");
1014 if (info2->trusted_dc_name == NULL) {
1015 return WERR_NOT_ENOUGH_MEMORY;
1018 info2->tc_connection_status = check_result;
1020 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1021 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1022 "pdc_connection[%s] tc_connection[%s]\n",
1023 __func__, domain->name, domain->alt_name,
1024 domain->dcname,
1025 win_errstr(info2->pdc_connection_status),
1026 win_errstr(info2->tc_connection_status)));
1029 r->out.query->info2 = info2;
1031 DEBUG(5, ("%s: succeeded.\n", __func__));
1032 return WERR_OK;
1035 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1036 struct winbindd_domain *domain,
1037 struct winbind_LogonControl *r)
1039 TALLOC_CTX *frame = talloc_stackframe();
1040 NTSTATUS status;
1041 NTSTATUS result;
1042 struct lsa_String trusted_domain_name = {};
1043 struct lsa_StringLarge trusted_domain_name_l = {};
1044 struct rpc_pipe_client *local_lsa_pipe = NULL;
1045 struct policy_handle local_lsa_policy = {};
1046 struct dcerpc_binding_handle *local_lsa = NULL;
1047 struct rpc_pipe_client *netlogon_pipe = NULL;
1048 struct cli_credentials *creds = NULL;
1049 struct samr_Password *cur_nt_hash = NULL;
1050 uint32_t trust_attributes = 0;
1051 struct samr_Password new_owf_password = {};
1052 int cmp_new = -1;
1053 struct samr_Password old_owf_password = {};
1054 int cmp_old = -1;
1055 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1056 bool fetch_fti = false;
1057 struct lsa_ForestTrustInformation *new_fti = NULL;
1058 struct netr_TrustInfo *trust_info = NULL;
1059 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1060 struct dcerpc_binding_handle *b = NULL;
1061 WERROR check_result = WERR_INTERNAL_ERROR;
1062 WERROR verify_result = WERR_INTERNAL_ERROR;
1063 bool retry = false;
1065 trusted_domain_name.string = domain->name;
1066 trusted_domain_name_l.string = domain->name;
1068 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1069 if (info2 == NULL) {
1070 TALLOC_FREE(frame);
1071 return WERR_NOT_ENOUGH_MEMORY;
1074 if (domain->internal) {
1075 check_result = WERR_OK;
1076 goto check_return;
1079 status = pdb_get_trust_credentials(domain->name,
1080 domain->alt_name,
1081 frame,
1082 &creds);
1083 if (NT_STATUS_IS_OK(status)) {
1084 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1085 TALLOC_FREE(creds);
1088 if (!domain->primary) {
1089 union lsa_TrustedDomainInfo *tdi = NULL;
1091 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1092 &local_lsa_policy);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1095 __location__, __func__, nt_errstr(status)));
1096 TALLOC_FREE(frame);
1097 return WERR_INTERNAL_ERROR;
1099 local_lsa = local_lsa_pipe->binding_handle;
1101 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1102 &local_lsa_policy,
1103 &trusted_domain_name,
1104 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1105 &tdi, &result);
1106 if (!NT_STATUS_IS_OK(status)) {
1107 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1108 __location__, __func__, domain->name, nt_errstr(status)));
1109 TALLOC_FREE(frame);
1110 return WERR_INTERNAL_ERROR;
1112 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1113 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1114 __location__, __func__, domain->name));
1115 TALLOC_FREE(frame);
1116 return WERR_NO_SUCH_DOMAIN;
1118 if (!NT_STATUS_IS_OK(result)) {
1119 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1120 __location__, __func__, domain->name, nt_errstr(result)));
1121 TALLOC_FREE(frame);
1122 return WERR_INTERNAL_ERROR;
1124 if (tdi == NULL) {
1125 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1126 "returned no trusted domain information\n",
1127 __location__, __func__));
1128 TALLOC_FREE(frame);
1129 return WERR_INTERNAL_ERROR;
1132 local_tdo = &tdi->info_ex;
1133 trust_attributes = local_tdo->trust_attributes;
1136 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1137 struct lsa_ForestTrustInformation *old_fti = NULL;
1139 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1140 &local_lsa_policy,
1141 &trusted_domain_name,
1142 LSA_FOREST_TRUST_DOMAIN_INFO,
1143 &old_fti, &result);
1144 if (!NT_STATUS_IS_OK(status)) {
1145 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%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_NOT_FOUND)) {
1151 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1152 __func__, domain->name));
1153 old_fti = NULL;
1154 fetch_fti = true;
1155 result = NT_STATUS_OK;
1157 if (!NT_STATUS_IS_OK(result)) {
1158 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1159 __location__, __func__, domain->name, nt_errstr(result)));
1160 TALLOC_FREE(frame);
1161 return WERR_INTERNAL_ERROR;
1164 TALLOC_FREE(old_fti);
1167 reconnect:
1168 status = cm_connect_netlogon(domain, &netlogon_pipe);
1169 reset_cm_connection_on_error(domain, status);
1170 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1171 status = NT_STATUS_NO_LOGON_SERVERS;
1173 if (!NT_STATUS_IS_OK(status)) {
1174 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1175 nt_errstr(status)));
1176 check_result = ntstatus_to_werror(status);
1177 goto check_return;
1179 check_result = WERR_OK;
1180 b = netlogon_pipe->binding_handle;
1182 if (cur_nt_hash == NULL) {
1183 verify_result = WERR_NO_TRUST_LSA_SECRET;
1184 goto verify_return;
1187 if (fetch_fti) {
1188 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1189 b, frame,
1190 &new_fti);
1191 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1192 status = NT_STATUS_NOT_SUPPORTED;
1194 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1195 new_fti = NULL;
1196 status = NT_STATUS_OK;
1198 if (!NT_STATUS_IS_OK(status)) {
1199 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1200 invalidate_cm_connection(domain);
1201 retry = true;
1202 goto reconnect;
1204 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1205 "failed: %s\n",
1206 domain->name, nt_errstr(status)));
1207 check_result = ntstatus_to_werror(status);
1208 goto check_return;
1212 if (new_fti != NULL) {
1213 struct lsa_ForestTrustInformation old_fti = {};
1214 struct lsa_ForestTrustInformation *merged_fti = NULL;
1215 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1217 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1218 &old_fti, new_fti,
1219 &merged_fti);
1220 if (!NT_STATUS_IS_OK(status)) {
1221 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1222 __location__, __func__,
1223 domain->name, nt_errstr(status)));
1224 TALLOC_FREE(frame);
1225 return ntstatus_to_werror(status);
1228 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1229 &local_lsa_policy,
1230 &trusted_domain_name_l,
1231 LSA_FOREST_TRUST_DOMAIN_INFO,
1232 merged_fti,
1233 0, /* check_only=0 => store it! */
1234 &collision_info,
1235 &result);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1238 __location__, __func__, domain->name, nt_errstr(status)));
1239 TALLOC_FREE(frame);
1240 return WERR_INTERNAL_ERROR;
1242 if (!NT_STATUS_IS_OK(result)) {
1243 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1244 __location__, __func__, domain->name, nt_errstr(result)));
1245 TALLOC_FREE(frame);
1246 return ntstatus_to_werror(result);
1250 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1251 b, frame,
1252 &new_owf_password,
1253 &old_owf_password,
1254 &trust_info);
1255 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1256 status = NT_STATUS_NOT_SUPPORTED;
1258 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1259 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1260 nt_errstr(status)));
1261 verify_result = WERR_OK;
1262 goto verify_return;
1264 if (!NT_STATUS_IS_OK(status)) {
1265 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1266 invalidate_cm_connection(domain);
1267 retry = true;
1268 goto reconnect;
1270 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1271 nt_errstr(status)));
1273 if (!dcerpc_binding_handle_is_connected(b)) {
1274 check_result = ntstatus_to_werror(status);
1275 goto check_return;
1276 } else {
1277 verify_result = ntstatus_to_werror(status);
1278 goto verify_return;
1282 if (trust_info != NULL && trust_info->count >= 1) {
1283 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1285 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1286 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1287 goto verify_return;
1291 cmp_new = memcmp(new_owf_password.hash,
1292 cur_nt_hash->hash,
1293 sizeof(cur_nt_hash->hash));
1294 cmp_old = memcmp(old_owf_password.hash,
1295 cur_nt_hash->hash,
1296 sizeof(cur_nt_hash->hash));
1297 if (cmp_new != 0 && cmp_old != 0) {
1298 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1299 "any password known to dcname[%s]\n",
1300 __func__, domain->name, domain->alt_name,
1301 domain->dcname));
1302 verify_result = WERR_WRONG_PASSWORD;
1303 goto verify_return;
1306 if (cmp_new != 0) {
1307 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1308 "against the old password known to dcname[%s]\n",
1309 __func__, domain->name, domain->alt_name,
1310 domain->dcname));
1313 verify_result = WERR_OK;
1314 goto verify_return;
1316 check_return:
1317 verify_result = check_result;
1318 verify_return:
1319 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1320 info2->pdc_connection_status = verify_result;
1321 if (domain->dcname != NULL) {
1322 info2->flags |= NETLOGON_HAS_IP;
1323 info2->flags |= NETLOGON_HAS_TIMESERV;
1324 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1325 domain->dcname);
1326 if (info2->trusted_dc_name == NULL) {
1327 TALLOC_FREE(frame);
1328 return WERR_NOT_ENOUGH_MEMORY;
1330 } else {
1331 info2->trusted_dc_name = talloc_strdup(info2, "");
1332 if (info2->trusted_dc_name == NULL) {
1333 TALLOC_FREE(frame);
1334 return WERR_NOT_ENOUGH_MEMORY;
1337 info2->tc_connection_status = check_result;
1339 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1340 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1341 "pdc_connection[%s] tc_connection[%s]\n",
1342 __func__, domain->name, domain->alt_name,
1343 domain->dcname,
1344 win_errstr(info2->pdc_connection_status),
1345 win_errstr(info2->tc_connection_status)));
1348 r->out.query->info2 = info2;
1350 DEBUG(5, ("%s: succeeded.\n", __func__));
1351 TALLOC_FREE(frame);
1352 return WERR_OK;
1355 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1356 struct winbindd_domain *domain,
1357 struct winbind_LogonControl *r)
1359 struct messaging_context *msg_ctx = winbind_messaging_context();
1360 NTSTATUS status;
1361 struct rpc_pipe_client *netlogon_pipe;
1362 struct cli_credentials *creds = NULL;
1363 struct samr_Password *cur_nt_hash = NULL;
1364 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1365 struct dcerpc_binding_handle *b;
1366 WERROR change_result = WERR_OK;
1367 bool retry = false;
1369 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1370 if (info1 == NULL) {
1371 return WERR_NOT_ENOUGH_MEMORY;
1374 if (domain->internal) {
1375 return WERR_NOT_SUPPORTED;
1378 status = pdb_get_trust_credentials(domain->name,
1379 domain->alt_name,
1380 p->mem_ctx,
1381 &creds);
1382 if (NT_STATUS_IS_OK(status)) {
1383 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1384 TALLOC_FREE(creds);
1387 reconnect:
1388 status = cm_connect_netlogon(domain, &netlogon_pipe);
1389 reset_cm_connection_on_error(domain, status);
1390 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1391 status = NT_STATUS_NO_LOGON_SERVERS;
1393 if (!NT_STATUS_IS_OK(status)) {
1394 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1395 __func__, domain->name, domain->alt_name,
1396 nt_errstr(status)));
1398 * Here we return a top level error!
1399 * This is different than TC_QUERY or TC_VERIFY.
1401 return ntstatus_to_werror(status);
1403 b = netlogon_pipe->binding_handle;
1405 if (cur_nt_hash == NULL) {
1406 change_result = WERR_NO_TRUST_LSA_SECRET;
1407 goto change_return;
1409 TALLOC_FREE(cur_nt_hash);
1411 status = trust_pw_change(domain->conn.netlogon_creds,
1412 msg_ctx, b, domain->name,
1413 true); /* force */
1414 if (!NT_STATUS_IS_OK(status)) {
1415 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1416 invalidate_cm_connection(domain);
1417 retry = true;
1418 goto reconnect;
1421 DEBUG(1, ("trust_pw_change(%s): %s\n",
1422 domain->name, nt_errstr(status)));
1424 change_result = ntstatus_to_werror(status);
1425 goto change_return;
1428 change_result = WERR_OK;
1430 change_return:
1431 info1->pdc_connection_status = change_result;
1433 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1434 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1435 "pdc_connection[%s]\n",
1436 __func__, domain->name, domain->alt_name,
1437 domain->dcname,
1438 win_errstr(info1->pdc_connection_status)));
1441 r->out.query->info1 = info1;
1443 DEBUG(5, ("%s: succeeded.\n", __func__));
1444 return WERR_OK;
1447 WERROR _winbind_LogonControl(struct pipes_struct *p,
1448 struct winbind_LogonControl *r)
1450 struct winbindd_domain *domain;
1452 domain = wb_child_domain();
1453 if (domain == NULL) {
1454 return WERR_NO_SUCH_DOMAIN;
1457 switch (r->in.function_code) {
1458 case NETLOGON_CONTROL_REDISCOVER:
1459 if (r->in.level != 2) {
1460 return WERR_INVALID_PARAMETER;
1462 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1463 case NETLOGON_CONTROL_TC_QUERY:
1464 if (r->in.level != 2) {
1465 return WERR_INVALID_PARAMETER;
1467 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1468 case NETLOGON_CONTROL_TC_VERIFY:
1469 if (r->in.level != 2) {
1470 return WERR_INVALID_PARAMETER;
1472 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1473 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1474 if (r->in.level != 1) {
1475 return WERR_INVALID_PARAMETER;
1477 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1478 default:
1479 break;
1482 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1483 __func__, r->in.function_code));
1484 return WERR_NOT_SUPPORTED;
1487 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1488 struct winbind_GetForestTrustInformation *r)
1490 TALLOC_CTX *frame = talloc_stackframe();
1491 NTSTATUS status, result;
1492 struct winbindd_domain *domain;
1493 struct rpc_pipe_client *netlogon_pipe;
1494 struct dcerpc_binding_handle *b;
1495 bool retry = false;
1496 struct lsa_String trusted_domain_name = {};
1497 struct lsa_StringLarge trusted_domain_name_l = {};
1498 union lsa_TrustedDomainInfo *tdi = NULL;
1499 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1500 struct lsa_ForestTrustInformation _old_fti = {};
1501 struct lsa_ForestTrustInformation *old_fti = NULL;
1502 struct lsa_ForestTrustInformation *new_fti = NULL;
1503 struct lsa_ForestTrustInformation *merged_fti = NULL;
1504 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1505 bool update_fti = false;
1506 struct rpc_pipe_client *local_lsa_pipe;
1507 struct policy_handle local_lsa_policy;
1508 struct dcerpc_binding_handle *local_lsa = NULL;
1510 domain = wb_child_domain();
1511 if (domain == NULL) {
1512 TALLOC_FREE(frame);
1513 return WERR_NO_SUCH_DOMAIN;
1517 * checking for domain->internal and domain->primary
1518 * makes sure we only do some work when running as DC.
1521 if (domain->internal) {
1522 TALLOC_FREE(frame);
1523 return WERR_NO_SUCH_DOMAIN;
1526 if (domain->primary) {
1527 TALLOC_FREE(frame);
1528 return WERR_NO_SUCH_DOMAIN;
1531 trusted_domain_name.string = domain->name;
1532 trusted_domain_name_l.string = domain->name;
1534 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1535 &local_lsa_policy);
1536 if (!NT_STATUS_IS_OK(status)) {
1537 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1538 __location__, __func__, nt_errstr(status)));
1539 TALLOC_FREE(frame);
1540 return WERR_INTERNAL_ERROR;
1542 local_lsa = local_lsa_pipe->binding_handle;
1544 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1545 &local_lsa_policy,
1546 &trusted_domain_name,
1547 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1548 &tdi, &result);
1549 if (!NT_STATUS_IS_OK(status)) {
1550 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1551 __location__, __func__, domain->name, nt_errstr(status)));
1552 TALLOC_FREE(frame);
1553 return WERR_INTERNAL_ERROR;
1555 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1556 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1557 __location__, __func__, domain->name));
1558 TALLOC_FREE(frame);
1559 return WERR_NO_SUCH_DOMAIN;
1561 if (!NT_STATUS_IS_OK(result)) {
1562 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1563 __location__, __func__, domain->name, nt_errstr(result)));
1564 TALLOC_FREE(frame);
1565 return WERR_INTERNAL_ERROR;
1567 if (tdi == NULL) {
1568 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1569 "returned no trusted domain information\n",
1570 __location__, __func__));
1571 TALLOC_FREE(frame);
1572 return WERR_INTERNAL_ERROR;
1575 tdo = &tdi->info_ex;
1577 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1578 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1579 __func__, tdo->netbios_name.string,
1580 tdo->domain_name.string,
1581 (unsigned)tdo->trust_attributes));
1582 TALLOC_FREE(frame);
1583 return WERR_NO_SUCH_DOMAIN;
1586 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1587 TALLOC_FREE(frame);
1588 return WERR_INVALID_FLAGS;
1591 reconnect:
1592 status = cm_connect_netlogon(domain, &netlogon_pipe);
1593 reset_cm_connection_on_error(domain, status);
1594 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1595 status = NT_STATUS_NO_LOGON_SERVERS;
1597 if (!NT_STATUS_IS_OK(status)) {
1598 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1599 nt_errstr(status)));
1600 TALLOC_FREE(frame);
1601 return ntstatus_to_werror(status);
1603 b = netlogon_pipe->binding_handle;
1605 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1606 b, p->mem_ctx,
1607 &new_fti);
1608 if (!NT_STATUS_IS_OK(status)) {
1609 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1610 invalidate_cm_connection(domain);
1611 retry = true;
1612 goto reconnect;
1614 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1615 domain->name, nt_errstr(status)));
1616 TALLOC_FREE(frame);
1617 return ntstatus_to_werror(status);
1620 *r->out.forest_trust_info = new_fti;
1622 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1623 update_fti = true;
1626 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1627 &local_lsa_policy,
1628 &trusted_domain_name,
1629 LSA_FOREST_TRUST_DOMAIN_INFO,
1630 &old_fti, &result);
1631 if (!NT_STATUS_IS_OK(status)) {
1632 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1633 __location__, __func__, domain->name, nt_errstr(status)));
1634 TALLOC_FREE(frame);
1635 return WERR_INTERNAL_ERROR;
1637 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1638 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1639 __func__, domain->name));
1640 update_fti = true;
1641 old_fti = &_old_fti;
1642 result = NT_STATUS_OK;
1644 if (!NT_STATUS_IS_OK(result)) {
1645 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1646 __location__, __func__, domain->name, nt_errstr(result)));
1647 TALLOC_FREE(frame);
1648 return WERR_INTERNAL_ERROR;
1651 if (old_fti == NULL) {
1652 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1653 "returned success without returning forest trust information\n",
1654 __location__, __func__));
1655 TALLOC_FREE(frame);
1656 return WERR_INTERNAL_ERROR;
1659 if (!update_fti) {
1660 goto done;
1663 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1664 &merged_fti);
1665 if (!NT_STATUS_IS_OK(status)) {
1666 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1667 __location__, __func__, domain->name, nt_errstr(status)));
1668 TALLOC_FREE(frame);
1669 return ntstatus_to_werror(status);
1672 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1673 &local_lsa_policy,
1674 &trusted_domain_name_l,
1675 LSA_FOREST_TRUST_DOMAIN_INFO,
1676 merged_fti,
1677 0, /* check_only=0 => store it! */
1678 &collision_info,
1679 &result);
1680 if (!NT_STATUS_IS_OK(status)) {
1681 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1682 __location__, __func__, domain->name, nt_errstr(status)));
1683 TALLOC_FREE(frame);
1684 return WERR_INTERNAL_ERROR;
1686 if (!NT_STATUS_IS_OK(result)) {
1687 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1688 __location__, __func__, domain->name, nt_errstr(result)));
1689 TALLOC_FREE(frame);
1690 return ntstatus_to_werror(result);
1693 done:
1694 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1695 TALLOC_FREE(frame);
1696 return WERR_OK;