dbwrap: add parse_record_send/recv to struct db_context
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob02b1adb2117feeccfd22a1c4e427d7f5d40bf9e9
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 DBG_DEBUG("id %"PRIu32" is out of range "
194 "%"PRIu32"-%"PRIu32" for domain %s\n",
195 m->xid.id, dom->low_id, dom->high_id,
196 dom->name);
197 m->status = ID_UNMAPPED;
200 if (m->status == ID_MAPPED) {
201 ids[i].xid = m->xid;
202 } else {
203 ids[i].xid.id = UINT32_MAX;
204 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
208 goto done;
209 nomem:
210 status = NT_STATUS_NO_MEMORY;
211 done:
212 TALLOC_FREE(id_map_ptrs);
213 return status;
216 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
217 struct wbint_UnixIDs2Sids *r)
219 struct id_map **maps;
220 NTSTATUS status;
221 uint32_t i;
223 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
224 if (maps == NULL) {
225 return NT_STATUS_NO_MEMORY;
228 for (i=0; i<r->in.num_ids; i++) {
229 maps[i]->status = ID_UNKNOWN;
230 maps[i]->xid = r->in.xids[i];
233 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name);
234 if (!NT_STATUS_IS_OK(status)) {
235 TALLOC_FREE(maps);
236 return status;
239 for (i=0; i<r->in.num_ids; i++) {
240 r->out.xids[i] = maps[i]->xid;
241 sid_copy(&r->out.sids[i], maps[i]->sid);
244 TALLOC_FREE(maps);
246 return NT_STATUS_OK;
249 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
251 struct unixid xid;
252 NTSTATUS status;
254 status = idmap_allocate_uid(&xid);
255 if (!NT_STATUS_IS_OK(status)) {
256 return status;
258 *r->out.uid = xid.id;
259 return NT_STATUS_OK;
262 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
264 struct unixid xid;
265 NTSTATUS status;
267 status = idmap_allocate_gid(&xid);
268 if (!NT_STATUS_IS_OK(status)) {
269 return status;
271 *r->out.gid = xid.id;
272 return NT_STATUS_OK;
275 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
277 struct idmap_domain *domain;
278 NTSTATUS status;
280 domain = idmap_find_domain(r->in.info->domain_name);
281 if ((domain == NULL) || (domain->query_user == NULL)) {
282 return NT_STATUS_REQUEST_NOT_ACCEPTED;
285 status = domain->query_user(domain, r->in.info);
286 return status;
289 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
290 struct wbint_LookupUserAliases *r)
292 struct winbindd_domain *domain = wb_child_domain();
293 NTSTATUS status;
295 if (domain == NULL) {
296 return NT_STATUS_REQUEST_NOT_ACCEPTED;
299 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
300 r->in.sids->num_sids,
301 r->in.sids->sids,
302 &r->out.rids->num_rids,
303 &r->out.rids->rids);
304 reset_cm_connection_on_error(domain, status);
305 return status;
308 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
309 struct wbint_LookupUserGroups *r)
311 struct winbindd_domain *domain = wb_child_domain();
312 NTSTATUS status;
314 if (domain == NULL) {
315 return NT_STATUS_REQUEST_NOT_ACCEPTED;
318 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
319 &r->out.sids->num_sids,
320 &r->out.sids->sids);
321 reset_cm_connection_on_error(domain, status);
322 return status;
325 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
326 struct wbint_QuerySequenceNumber *r)
328 struct winbindd_domain *domain = wb_child_domain();
329 NTSTATUS status;
331 if (domain == NULL) {
332 return NT_STATUS_REQUEST_NOT_ACCEPTED;
335 status = wb_cache_sequence_number(domain, r->out.sequence);
336 reset_cm_connection_on_error(domain, status);
337 return status;
340 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
341 struct wbint_LookupGroupMembers *r)
343 struct winbindd_domain *domain = wb_child_domain();
344 uint32_t i, num_names;
345 struct dom_sid *sid_mem;
346 char **names;
347 uint32_t *name_types;
348 NTSTATUS status;
350 if (domain == NULL) {
351 return NT_STATUS_REQUEST_NOT_ACCEPTED;
354 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
355 r->in.type, &num_names, &sid_mem,
356 &names, &name_types);
357 reset_cm_connection_on_error(domain, status);
358 if (!NT_STATUS_IS_OK(status)) {
359 return status;
362 r->out.members->num_principals = num_names;
363 r->out.members->principals = talloc_array(
364 r->out.members, struct wbint_Principal, num_names);
365 if (r->out.members->principals == NULL) {
366 return NT_STATUS_NO_MEMORY;
369 for (i=0; i<num_names; i++) {
370 struct wbint_Principal *m = &r->out.members->principals[i];
371 sid_copy(&m->sid, &sid_mem[i]);
372 m->name = talloc_move(r->out.members->principals, &names[i]);
373 m->type = (enum lsa_SidType)name_types[i];
376 return NT_STATUS_OK;
379 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
380 struct wbint_QueryGroupList *r)
382 struct winbindd_domain *domain = wb_child_domain();
383 uint32_t i;
384 uint32_t num_local_groups = 0;
385 struct wb_acct_info *local_groups = NULL;
386 uint32_t num_dom_groups = 0;
387 struct wb_acct_info *dom_groups = NULL;
388 uint32_t ti = 0;
389 uint64_t num_total = 0;
390 struct wbint_Principal *result;
391 NTSTATUS status;
392 bool include_local_groups = false;
394 if (domain == NULL) {
395 return NT_STATUS_REQUEST_NOT_ACCEPTED;
398 switch (lp_server_role()) {
399 case ROLE_ACTIVE_DIRECTORY_DC:
400 if (domain->internal) {
402 * we want to include local groups
403 * for BUILTIN and WORKGROUP
405 include_local_groups = true;
407 break;
408 default:
410 * We might include local groups in more
411 * setups later, but that requires more work
412 * elsewhere.
414 break;
417 if (include_local_groups) {
418 status = wb_cache_enum_local_groups(domain, talloc_tos(),
419 &num_local_groups,
420 &local_groups);
421 reset_cm_connection_on_error(domain, status);
422 if (!NT_STATUS_IS_OK(status)) {
423 return status;
427 status = wb_cache_enum_dom_groups(domain, talloc_tos(),
428 &num_dom_groups,
429 &dom_groups);
430 reset_cm_connection_on_error(domain, status);
431 if (!NT_STATUS_IS_OK(status)) {
432 return status;
435 num_total = num_local_groups + num_dom_groups;
436 if (num_total > UINT32_MAX) {
437 return NT_STATUS_INTERNAL_ERROR;
440 result = talloc_array(r->out.groups, struct wbint_Principal,
441 num_total);
442 if (result == NULL) {
443 return NT_STATUS_NO_MEMORY;
446 for (i = 0; i < num_local_groups; i++) {
447 struct wb_acct_info *lg = &local_groups[i];
448 struct wbint_Principal *rg = &result[ti++];
450 sid_compose(&rg->sid, &domain->sid, lg->rid);
451 rg->type = SID_NAME_ALIAS;
452 rg->name = talloc_strdup(result, lg->acct_name);
453 if (rg->name == NULL) {
454 TALLOC_FREE(result);
455 TALLOC_FREE(dom_groups);
456 TALLOC_FREE(local_groups);
457 return NT_STATUS_NO_MEMORY;
460 num_local_groups = 0;
461 TALLOC_FREE(local_groups);
463 for (i = 0; i < num_dom_groups; i++) {
464 struct wb_acct_info *dg = &dom_groups[i];
465 struct wbint_Principal *rg = &result[ti++];
467 sid_compose(&rg->sid, &domain->sid, dg->rid);
468 rg->type = SID_NAME_DOM_GRP;
469 rg->name = talloc_strdup(result, dg->acct_name);
470 if (rg->name == NULL) {
471 TALLOC_FREE(result);
472 TALLOC_FREE(dom_groups);
473 TALLOC_FREE(local_groups);
474 return NT_STATUS_NO_MEMORY;
477 num_dom_groups = 0;
478 TALLOC_FREE(dom_groups);
480 r->out.groups->num_principals = ti;
481 r->out.groups->principals = result;
483 return NT_STATUS_OK;
486 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
487 struct wbint_QueryUserRidList *r)
489 struct winbindd_domain *domain = wb_child_domain();
490 NTSTATUS status;
492 if (domain == NULL) {
493 return NT_STATUS_REQUEST_NOT_ACCEPTED;
497 * Right now this is overkill. We should add a backend call
498 * just querying the rids.
501 status = wb_cache_query_user_list(domain, p->mem_ctx,
502 &r->out.rids->rids);
503 reset_cm_connection_on_error(domain, status);
505 if (!NT_STATUS_IS_OK(status)) {
506 return status;
509 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
511 return NT_STATUS_OK;
514 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
516 struct winbindd_domain *domain = wb_child_domain();
517 struct rpc_pipe_client *netlogon_pipe;
518 struct netr_DsRGetDCNameInfo *dc_info;
519 NTSTATUS status;
520 WERROR werr;
521 unsigned int orig_timeout;
522 struct dcerpc_binding_handle *b;
524 if (domain == NULL) {
525 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
526 r->in.domain_name, r->in.domain_guid,
527 r->in.site_name ? r->in.site_name : "",
528 r->in.flags,
529 r->out.dc_info);
532 status = cm_connect_netlogon(domain, &netlogon_pipe);
534 reset_cm_connection_on_error(domain, status);
535 if (!NT_STATUS_IS_OK(status)) {
536 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
537 return status;
540 b = netlogon_pipe->binding_handle;
542 /* This call can take a long time - allow the server to time out.
543 35 seconds should do it. */
545 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
547 if (domain->active_directory) {
548 status = dcerpc_netr_DsRGetDCName(b,
549 p->mem_ctx, domain->dcname,
550 r->in.domain_name, NULL, r->in.domain_guid,
551 r->in.flags, r->out.dc_info, &werr);
552 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
553 goto done;
555 if (reset_cm_connection_on_error(domain, status)) {
556 /* Re-initialize. */
557 status = cm_connect_netlogon(domain, &netlogon_pipe);
559 reset_cm_connection_on_error(domain, status);
560 if (!NT_STATUS_IS_OK(status)) {
561 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
562 return status;
565 b = netlogon_pipe->binding_handle;
567 /* This call can take a long time - allow the server to time out.
568 35 seconds should do it. */
570 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
575 * Fallback to less capable methods
578 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
579 if (dc_info == NULL) {
580 status = NT_STATUS_NO_MEMORY;
581 goto done;
584 if (r->in.flags & DS_PDC_REQUIRED) {
585 status = dcerpc_netr_GetDcName(b,
586 p->mem_ctx, domain->dcname,
587 r->in.domain_name, &dc_info->dc_unc, &werr);
588 } else {
589 status = dcerpc_netr_GetAnyDCName(b,
590 p->mem_ctx, domain->dcname,
591 r->in.domain_name, &dc_info->dc_unc, &werr);
594 reset_cm_connection_on_error(domain, status);
595 if (!NT_STATUS_IS_OK(status)) {
596 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
597 nt_errstr(status)));
598 goto done;
600 if (!W_ERROR_IS_OK(werr)) {
601 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
602 win_errstr(werr)));
603 status = werror_to_ntstatus(werr);
604 goto done;
607 *r->out.dc_info = dc_info;
608 status = NT_STATUS_OK;
610 done:
611 /* And restore our original timeout. */
612 rpccli_set_timeout(netlogon_pipe, orig_timeout);
614 return status;
617 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
619 struct winbindd_domain *domain = wb_child_domain();
620 char *domain_name;
621 char **names;
622 enum lsa_SidType *types;
623 struct wbint_Principal *result;
624 NTSTATUS status;
625 uint32_t i;
627 if (domain == NULL) {
628 return NT_STATUS_REQUEST_NOT_ACCEPTED;
631 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
632 r->in.rids->rids, r->in.rids->num_rids,
633 &domain_name, &names, &types);
634 reset_cm_connection_on_error(domain, status);
635 if (!NT_STATUS_IS_OK(status)) {
636 return status;
639 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
641 result = talloc_array(p->mem_ctx, struct wbint_Principal,
642 r->in.rids->num_rids);
643 if (result == NULL) {
644 return NT_STATUS_NO_MEMORY;
647 for (i=0; i<r->in.rids->num_rids; i++) {
648 sid_compose(&result[i].sid, r->in.domain_sid,
649 r->in.rids->rids[i]);
650 result[i].type = types[i];
651 result[i].name = talloc_move(result, &names[i]);
653 TALLOC_FREE(types);
654 TALLOC_FREE(names);
656 r->out.names->num_principals = r->in.rids->num_rids;
657 r->out.names->principals = result;
658 return NT_STATUS_OK;
661 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
662 struct wbint_CheckMachineAccount *r)
664 struct winbindd_domain *domain;
665 int num_retries = 0;
666 NTSTATUS status;
668 domain = wb_child_domain();
669 if (domain == NULL) {
670 return NT_STATUS_REQUEST_NOT_ACCEPTED;
673 again:
674 invalidate_cm_connection(domain);
675 domain->conn.netlogon_force_reauth = true;
678 struct rpc_pipe_client *netlogon_pipe;
679 status = cm_connect_netlogon(domain, &netlogon_pipe);
682 /* There is a race condition between fetching the trust account
683 password and the periodic machine password change. So it's
684 possible that the trust account password has been changed on us.
685 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
687 #define MAX_RETRIES 3
689 if ((num_retries < MAX_RETRIES)
690 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
691 num_retries++;
692 goto again;
695 if (!NT_STATUS_IS_OK(status)) {
696 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
697 goto done;
700 /* Pass back result code - zero for success, other values for
701 specific failures. */
703 DEBUG(3,("domain %s secret is %s\n", domain->name,
704 NT_STATUS_IS_OK(status) ? "good" : "bad"));
706 done:
707 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
708 ("Checking the trust account password for domain %s returned %s\n",
709 domain->name, nt_errstr(status)));
711 return status;
714 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
715 struct wbint_ChangeMachineAccount *r)
717 struct messaging_context *msg_ctx = winbind_messaging_context();
718 struct winbindd_domain *domain;
719 NTSTATUS status;
720 struct rpc_pipe_client *netlogon_pipe;
722 domain = wb_child_domain();
723 if (domain == NULL) {
724 return NT_STATUS_REQUEST_NOT_ACCEPTED;
727 status = cm_connect_netlogon(domain, &netlogon_pipe);
728 if (!NT_STATUS_IS_OK(status)) {
729 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
730 goto done;
733 status = trust_pw_change(domain->conn.netlogon_creds,
734 msg_ctx,
735 netlogon_pipe->binding_handle,
736 domain->name,
737 true); /* force */
739 /* Pass back result code - zero for success, other values for
740 specific failures. */
742 DEBUG(3,("domain %s secret %s\n", domain->name,
743 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
745 done:
746 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
747 ("Changing the trust account password for domain %s returned %s\n",
748 domain->name, nt_errstr(status)));
750 return status;
753 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
755 NTSTATUS status;
756 struct winbindd_domain *domain;
757 struct rpc_pipe_client *netlogon_pipe;
758 union netr_CONTROL_QUERY_INFORMATION info;
759 WERROR werr;
760 fstring logon_server;
761 struct dcerpc_binding_handle *b;
762 bool retry = false;
764 domain = wb_child_domain();
765 if (domain == NULL) {
766 return NT_STATUS_REQUEST_NOT_ACCEPTED;
769 reconnect:
770 status = cm_connect_netlogon(domain, &netlogon_pipe);
771 reset_cm_connection_on_error(domain, status);
772 if (!NT_STATUS_IS_OK(status)) {
773 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
774 nt_errstr(status)));
775 return status;
778 b = netlogon_pipe->binding_handle;
780 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
781 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
782 if (*r->out.dcname == NULL) {
783 DEBUG(2, ("Could not allocate memory\n"));
784 return NT_STATUS_NO_MEMORY;
788 * This provokes a WERR_NOT_SUPPORTED error message. This is
789 * documented in the wspp docs. I could not get a successful
790 * call to work, but the main point here is testing that the
791 * netlogon pipe works.
793 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
794 logon_server, NETLOGON_CONTROL_QUERY,
795 2, &info, &werr);
797 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
798 DEBUG(10, ("Session might have expired. "
799 "Reconnect and retry once.\n"));
800 invalidate_cm_connection(domain);
801 retry = true;
802 goto reconnect;
805 reset_cm_connection_on_error(domain, status);
806 if (!NT_STATUS_IS_OK(status)) {
807 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
808 nt_errstr(status)));
809 return status;
812 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
813 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
814 "WERR_NOT_SUPPORTED\n",
815 win_errstr(werr)));
816 return werror_to_ntstatus(werr);
819 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
820 return NT_STATUS_OK;
823 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
824 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
826 struct winbindd_domain *domain;
827 NTSTATUS status;
828 struct rpc_pipe_client *netlogon_pipe;
830 domain = wb_child_domain();
831 if (domain == NULL) {
832 return NT_STATUS_REQUEST_NOT_ACCEPTED;
835 status = cm_connect_netlogon(domain, &netlogon_pipe);
836 if (!NT_STATUS_IS_OK(status)) {
837 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
838 goto done;
841 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
842 netlogon_pipe->binding_handle,
843 r->in.site_name,
844 r->in.dns_ttl,
845 r->in.dns_names);
847 /* Pass back result code - zero for success, other values for
848 specific failures. */
850 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
851 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
853 done:
854 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
855 ("Update of DNS records via RW DC %s returned %s\n",
856 domain->name, nt_errstr(status)));
858 return status;
861 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
862 struct winbind_SamLogon *r)
864 struct winbindd_domain *domain;
865 NTSTATUS status;
866 DATA_BLOB lm_response, nt_response;
867 uint32_t flags;
869 domain = wb_child_domain();
870 if (domain == NULL) {
871 return NT_STATUS_REQUEST_NOT_ACCEPTED;
874 /* TODO: Handle interactive logons here */
875 if (r->in.validation_level != 3 ||
876 r->in.logon.network == NULL ||
877 (r->in.logon_level != NetlogonNetworkInformation
878 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
879 return NT_STATUS_REQUEST_NOT_ACCEPTED;
883 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
884 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
886 status = winbind_dual_SamLogon(domain, p->mem_ctx,
887 r->in.logon.network->identity_info.parameter_control,
888 r->in.logon.network->identity_info.account_name.string,
889 r->in.logon.network->identity_info.domain_name.string,
890 r->in.logon.network->identity_info.workstation.string,
891 r->in.logon.network->challenge,
892 lm_response, nt_response,
893 &r->out.authoritative, &flags,
894 &r->out.validation.sam3);
895 return status;
898 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
899 struct winbindd_domain *domain,
900 struct winbind_LogonControl *r)
902 NTSTATUS status;
903 struct rpc_pipe_client *netlogon_pipe = NULL;
904 struct netr_NETLOGON_INFO_2 *info2 = NULL;
905 WERROR check_result = WERR_INTERNAL_ERROR;
907 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
908 if (info2 == NULL) {
909 return WERR_NOT_ENOUGH_MEMORY;
912 if (domain->internal) {
913 check_result = WERR_OK;
914 goto check_return;
918 * For now we just force a reconnect
920 * TODO: take care of the optional '\dcname'
922 invalidate_cm_connection(domain);
923 domain->conn.netlogon_force_reauth = true;
924 status = cm_connect_netlogon(domain, &netlogon_pipe);
925 reset_cm_connection_on_error(domain, status);
926 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
927 status = NT_STATUS_NO_LOGON_SERVERS;
929 if (!NT_STATUS_IS_OK(status)) {
930 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
931 __func__, domain->name, domain->alt_name,
932 nt_errstr(status)));
934 * Here we return a top level error!
935 * This is different than TC_QUERY or TC_VERIFY.
937 return ntstatus_to_werror(status);
939 check_result = WERR_OK;
941 check_return:
942 info2->pdc_connection_status = WERR_OK;
943 if (domain->dcname != NULL) {
944 info2->flags |= NETLOGON_HAS_IP;
945 info2->flags |= NETLOGON_HAS_TIMESERV;
946 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
947 domain->dcname);
948 if (info2->trusted_dc_name == NULL) {
949 return WERR_NOT_ENOUGH_MEMORY;
951 } else {
952 info2->trusted_dc_name = talloc_strdup(info2, "");
953 if (info2->trusted_dc_name == NULL) {
954 return WERR_NOT_ENOUGH_MEMORY;
957 info2->tc_connection_status = check_result;
959 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
960 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
961 "pdc_connection[%s] tc_connection[%s]\n",
962 __func__, domain->name, domain->alt_name,
963 domain->dcname,
964 win_errstr(info2->pdc_connection_status),
965 win_errstr(info2->tc_connection_status)));
968 r->out.query->info2 = info2;
970 DEBUG(5, ("%s: succeeded.\n", __func__));
971 return WERR_OK;
974 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
975 struct winbindd_domain *domain,
976 struct winbind_LogonControl *r)
978 NTSTATUS status;
979 struct rpc_pipe_client *netlogon_pipe = NULL;
980 struct netr_NETLOGON_INFO_2 *info2 = NULL;
981 WERROR check_result = WERR_INTERNAL_ERROR;
983 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
984 if (info2 == NULL) {
985 return WERR_NOT_ENOUGH_MEMORY;
988 if (domain->internal) {
989 check_result = WERR_OK;
990 goto check_return;
993 status = cm_connect_netlogon(domain, &netlogon_pipe);
994 reset_cm_connection_on_error(domain, status);
995 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
996 status = NT_STATUS_NO_LOGON_SERVERS;
998 if (!NT_STATUS_IS_OK(status)) {
999 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1000 nt_errstr(status)));
1001 check_result = ntstatus_to_werror(status);
1002 goto check_return;
1004 check_result = WERR_OK;
1006 check_return:
1007 info2->pdc_connection_status = WERR_OK;
1008 if (domain->dcname != NULL) {
1009 info2->flags |= NETLOGON_HAS_IP;
1010 info2->flags |= NETLOGON_HAS_TIMESERV;
1011 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1012 domain->dcname);
1013 if (info2->trusted_dc_name == NULL) {
1014 return WERR_NOT_ENOUGH_MEMORY;
1016 } else {
1017 info2->trusted_dc_name = talloc_strdup(info2, "");
1018 if (info2->trusted_dc_name == NULL) {
1019 return WERR_NOT_ENOUGH_MEMORY;
1022 info2->tc_connection_status = check_result;
1024 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1025 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1026 "pdc_connection[%s] tc_connection[%s]\n",
1027 __func__, domain->name, domain->alt_name,
1028 domain->dcname,
1029 win_errstr(info2->pdc_connection_status),
1030 win_errstr(info2->tc_connection_status)));
1033 r->out.query->info2 = info2;
1035 DEBUG(5, ("%s: succeeded.\n", __func__));
1036 return WERR_OK;
1039 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1040 struct winbindd_domain *domain,
1041 struct winbind_LogonControl *r)
1043 TALLOC_CTX *frame = talloc_stackframe();
1044 NTSTATUS status;
1045 NTSTATUS result;
1046 struct lsa_String trusted_domain_name = {};
1047 struct lsa_StringLarge trusted_domain_name_l = {};
1048 struct rpc_pipe_client *local_lsa_pipe = NULL;
1049 struct policy_handle local_lsa_policy = {};
1050 struct dcerpc_binding_handle *local_lsa = NULL;
1051 struct rpc_pipe_client *netlogon_pipe = NULL;
1052 struct cli_credentials *creds = NULL;
1053 struct samr_Password *cur_nt_hash = NULL;
1054 uint32_t trust_attributes = 0;
1055 struct samr_Password new_owf_password = {};
1056 int cmp_new = -1;
1057 struct samr_Password old_owf_password = {};
1058 int cmp_old = -1;
1059 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1060 bool fetch_fti = false;
1061 struct lsa_ForestTrustInformation *new_fti = NULL;
1062 struct netr_TrustInfo *trust_info = NULL;
1063 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1064 struct dcerpc_binding_handle *b = NULL;
1065 WERROR check_result = WERR_INTERNAL_ERROR;
1066 WERROR verify_result = WERR_INTERNAL_ERROR;
1067 bool retry = false;
1069 trusted_domain_name.string = domain->name;
1070 trusted_domain_name_l.string = domain->name;
1072 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1073 if (info2 == NULL) {
1074 TALLOC_FREE(frame);
1075 return WERR_NOT_ENOUGH_MEMORY;
1078 if (domain->internal) {
1079 check_result = WERR_OK;
1080 goto check_return;
1083 status = pdb_get_trust_credentials(domain->name,
1084 domain->alt_name,
1085 frame,
1086 &creds);
1087 if (NT_STATUS_IS_OK(status)) {
1088 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1089 TALLOC_FREE(creds);
1092 if (!domain->primary) {
1093 union lsa_TrustedDomainInfo *tdi = NULL;
1095 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1096 &local_lsa_policy);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1099 __location__, __func__, nt_errstr(status)));
1100 TALLOC_FREE(frame);
1101 return WERR_INTERNAL_ERROR;
1103 local_lsa = local_lsa_pipe->binding_handle;
1105 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1106 &local_lsa_policy,
1107 &trusted_domain_name,
1108 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1109 &tdi, &result);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1112 __location__, __func__, domain->name, nt_errstr(status)));
1113 TALLOC_FREE(frame);
1114 return WERR_INTERNAL_ERROR;
1116 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1117 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1118 __location__, __func__, domain->name));
1119 TALLOC_FREE(frame);
1120 return WERR_NO_SUCH_DOMAIN;
1122 if (!NT_STATUS_IS_OK(result)) {
1123 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1124 __location__, __func__, domain->name, nt_errstr(result)));
1125 TALLOC_FREE(frame);
1126 return WERR_INTERNAL_ERROR;
1128 if (tdi == NULL) {
1129 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1130 "returned no trusted domain information\n",
1131 __location__, __func__));
1132 TALLOC_FREE(frame);
1133 return WERR_INTERNAL_ERROR;
1136 local_tdo = &tdi->info_ex;
1137 trust_attributes = local_tdo->trust_attributes;
1140 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1141 struct lsa_ForestTrustInformation *old_fti = NULL;
1143 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1144 &local_lsa_policy,
1145 &trusted_domain_name,
1146 LSA_FOREST_TRUST_DOMAIN_INFO,
1147 &old_fti, &result);
1148 if (!NT_STATUS_IS_OK(status)) {
1149 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1150 __location__, __func__, domain->name, nt_errstr(status)));
1151 TALLOC_FREE(frame);
1152 return WERR_INTERNAL_ERROR;
1154 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1155 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1156 __func__, domain->name));
1157 old_fti = NULL;
1158 fetch_fti = true;
1159 result = NT_STATUS_OK;
1161 if (!NT_STATUS_IS_OK(result)) {
1162 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1163 __location__, __func__, domain->name, nt_errstr(result)));
1164 TALLOC_FREE(frame);
1165 return WERR_INTERNAL_ERROR;
1168 TALLOC_FREE(old_fti);
1171 reconnect:
1172 status = cm_connect_netlogon(domain, &netlogon_pipe);
1173 reset_cm_connection_on_error(domain, status);
1174 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1175 status = NT_STATUS_NO_LOGON_SERVERS;
1177 if (!NT_STATUS_IS_OK(status)) {
1178 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1179 nt_errstr(status)));
1180 check_result = ntstatus_to_werror(status);
1181 goto check_return;
1183 check_result = WERR_OK;
1184 b = netlogon_pipe->binding_handle;
1186 if (cur_nt_hash == NULL) {
1187 verify_result = WERR_NO_TRUST_LSA_SECRET;
1188 goto verify_return;
1191 if (fetch_fti) {
1192 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1193 b, frame,
1194 &new_fti);
1195 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1196 status = NT_STATUS_NOT_SUPPORTED;
1198 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1199 new_fti = NULL;
1200 status = NT_STATUS_OK;
1202 if (!NT_STATUS_IS_OK(status)) {
1203 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1204 invalidate_cm_connection(domain);
1205 retry = true;
1206 goto reconnect;
1208 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1209 "failed: %s\n",
1210 domain->name, nt_errstr(status)));
1211 check_result = ntstatus_to_werror(status);
1212 goto check_return;
1216 if (new_fti != NULL) {
1217 struct lsa_ForestTrustInformation old_fti = {};
1218 struct lsa_ForestTrustInformation *merged_fti = NULL;
1219 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1221 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1222 &old_fti, new_fti,
1223 &merged_fti);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1226 __location__, __func__,
1227 domain->name, nt_errstr(status)));
1228 TALLOC_FREE(frame);
1229 return ntstatus_to_werror(status);
1232 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1233 &local_lsa_policy,
1234 &trusted_domain_name_l,
1235 LSA_FOREST_TRUST_DOMAIN_INFO,
1236 merged_fti,
1237 0, /* check_only=0 => store it! */
1238 &collision_info,
1239 &result);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1242 __location__, __func__, domain->name, nt_errstr(status)));
1243 TALLOC_FREE(frame);
1244 return WERR_INTERNAL_ERROR;
1246 if (!NT_STATUS_IS_OK(result)) {
1247 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1248 __location__, __func__, domain->name, nt_errstr(result)));
1249 TALLOC_FREE(frame);
1250 return ntstatus_to_werror(result);
1254 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1255 b, frame,
1256 &new_owf_password,
1257 &old_owf_password,
1258 &trust_info);
1259 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1260 status = NT_STATUS_NOT_SUPPORTED;
1262 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1263 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1264 nt_errstr(status)));
1265 verify_result = WERR_OK;
1266 goto verify_return;
1268 if (!NT_STATUS_IS_OK(status)) {
1269 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1270 invalidate_cm_connection(domain);
1271 retry = true;
1272 goto reconnect;
1274 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1275 nt_errstr(status)));
1277 if (!dcerpc_binding_handle_is_connected(b)) {
1278 check_result = ntstatus_to_werror(status);
1279 goto check_return;
1280 } else {
1281 verify_result = ntstatus_to_werror(status);
1282 goto verify_return;
1286 if (trust_info != NULL && trust_info->count >= 1) {
1287 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1289 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1290 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1291 goto verify_return;
1295 cmp_new = memcmp(new_owf_password.hash,
1296 cur_nt_hash->hash,
1297 sizeof(cur_nt_hash->hash));
1298 cmp_old = memcmp(old_owf_password.hash,
1299 cur_nt_hash->hash,
1300 sizeof(cur_nt_hash->hash));
1301 if (cmp_new != 0 && cmp_old != 0) {
1302 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1303 "any password known to dcname[%s]\n",
1304 __func__, domain->name, domain->alt_name,
1305 domain->dcname));
1306 verify_result = WERR_WRONG_PASSWORD;
1307 goto verify_return;
1310 if (cmp_new != 0) {
1311 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1312 "against the old password known to dcname[%s]\n",
1313 __func__, domain->name, domain->alt_name,
1314 domain->dcname));
1317 verify_result = WERR_OK;
1318 goto verify_return;
1320 check_return:
1321 verify_result = check_result;
1322 verify_return:
1323 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1324 info2->pdc_connection_status = verify_result;
1325 if (domain->dcname != NULL) {
1326 info2->flags |= NETLOGON_HAS_IP;
1327 info2->flags |= NETLOGON_HAS_TIMESERV;
1328 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1329 domain->dcname);
1330 if (info2->trusted_dc_name == NULL) {
1331 TALLOC_FREE(frame);
1332 return WERR_NOT_ENOUGH_MEMORY;
1334 } else {
1335 info2->trusted_dc_name = talloc_strdup(info2, "");
1336 if (info2->trusted_dc_name == NULL) {
1337 TALLOC_FREE(frame);
1338 return WERR_NOT_ENOUGH_MEMORY;
1341 info2->tc_connection_status = check_result;
1343 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1344 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1345 "pdc_connection[%s] tc_connection[%s]\n",
1346 __func__, domain->name, domain->alt_name,
1347 domain->dcname,
1348 win_errstr(info2->pdc_connection_status),
1349 win_errstr(info2->tc_connection_status)));
1352 r->out.query->info2 = info2;
1354 DEBUG(5, ("%s: succeeded.\n", __func__));
1355 TALLOC_FREE(frame);
1356 return WERR_OK;
1359 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1360 struct winbindd_domain *domain,
1361 struct winbind_LogonControl *r)
1363 struct messaging_context *msg_ctx = winbind_messaging_context();
1364 NTSTATUS status;
1365 struct rpc_pipe_client *netlogon_pipe;
1366 struct cli_credentials *creds = NULL;
1367 struct samr_Password *cur_nt_hash = NULL;
1368 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1369 struct dcerpc_binding_handle *b;
1370 WERROR change_result = WERR_OK;
1371 bool retry = false;
1373 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1374 if (info1 == NULL) {
1375 return WERR_NOT_ENOUGH_MEMORY;
1378 if (domain->internal) {
1379 return WERR_NOT_SUPPORTED;
1382 status = pdb_get_trust_credentials(domain->name,
1383 domain->alt_name,
1384 p->mem_ctx,
1385 &creds);
1386 if (NT_STATUS_IS_OK(status)) {
1387 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1388 TALLOC_FREE(creds);
1391 reconnect:
1392 status = cm_connect_netlogon(domain, &netlogon_pipe);
1393 reset_cm_connection_on_error(domain, status);
1394 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1395 status = NT_STATUS_NO_LOGON_SERVERS;
1397 if (!NT_STATUS_IS_OK(status)) {
1398 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1399 __func__, domain->name, domain->alt_name,
1400 nt_errstr(status)));
1402 * Here we return a top level error!
1403 * This is different than TC_QUERY or TC_VERIFY.
1405 return ntstatus_to_werror(status);
1407 b = netlogon_pipe->binding_handle;
1409 if (cur_nt_hash == NULL) {
1410 change_result = WERR_NO_TRUST_LSA_SECRET;
1411 goto change_return;
1413 TALLOC_FREE(cur_nt_hash);
1415 status = trust_pw_change(domain->conn.netlogon_creds,
1416 msg_ctx, b, domain->name,
1417 true); /* force */
1418 if (!NT_STATUS_IS_OK(status)) {
1419 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1420 invalidate_cm_connection(domain);
1421 retry = true;
1422 goto reconnect;
1425 DEBUG(1, ("trust_pw_change(%s): %s\n",
1426 domain->name, nt_errstr(status)));
1428 change_result = ntstatus_to_werror(status);
1429 goto change_return;
1432 change_result = WERR_OK;
1434 change_return:
1435 info1->pdc_connection_status = change_result;
1437 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1438 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1439 "pdc_connection[%s]\n",
1440 __func__, domain->name, domain->alt_name,
1441 domain->dcname,
1442 win_errstr(info1->pdc_connection_status)));
1445 r->out.query->info1 = info1;
1447 DEBUG(5, ("%s: succeeded.\n", __func__));
1448 return WERR_OK;
1451 WERROR _winbind_LogonControl(struct pipes_struct *p,
1452 struct winbind_LogonControl *r)
1454 struct winbindd_domain *domain;
1456 domain = wb_child_domain();
1457 if (domain == NULL) {
1458 return WERR_NO_SUCH_DOMAIN;
1461 switch (r->in.function_code) {
1462 case NETLOGON_CONTROL_REDISCOVER:
1463 if (r->in.level != 2) {
1464 return WERR_INVALID_PARAMETER;
1466 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1467 case NETLOGON_CONTROL_TC_QUERY:
1468 if (r->in.level != 2) {
1469 return WERR_INVALID_PARAMETER;
1471 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1472 case NETLOGON_CONTROL_TC_VERIFY:
1473 if (r->in.level != 2) {
1474 return WERR_INVALID_PARAMETER;
1476 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1477 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1478 if (r->in.level != 1) {
1479 return WERR_INVALID_PARAMETER;
1481 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1482 default:
1483 break;
1486 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1487 __func__, r->in.function_code));
1488 return WERR_NOT_SUPPORTED;
1491 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1492 struct winbind_GetForestTrustInformation *r)
1494 TALLOC_CTX *frame = talloc_stackframe();
1495 NTSTATUS status, result;
1496 struct winbindd_domain *domain;
1497 struct rpc_pipe_client *netlogon_pipe;
1498 struct dcerpc_binding_handle *b;
1499 bool retry = false;
1500 struct lsa_String trusted_domain_name = {};
1501 struct lsa_StringLarge trusted_domain_name_l = {};
1502 union lsa_TrustedDomainInfo *tdi = NULL;
1503 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1504 struct lsa_ForestTrustInformation _old_fti = {};
1505 struct lsa_ForestTrustInformation *old_fti = NULL;
1506 struct lsa_ForestTrustInformation *new_fti = NULL;
1507 struct lsa_ForestTrustInformation *merged_fti = NULL;
1508 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1509 bool update_fti = false;
1510 struct rpc_pipe_client *local_lsa_pipe;
1511 struct policy_handle local_lsa_policy;
1512 struct dcerpc_binding_handle *local_lsa = NULL;
1514 domain = wb_child_domain();
1515 if (domain == NULL) {
1516 TALLOC_FREE(frame);
1517 return WERR_NO_SUCH_DOMAIN;
1521 * checking for domain->internal and domain->primary
1522 * makes sure we only do some work when running as DC.
1525 if (domain->internal) {
1526 TALLOC_FREE(frame);
1527 return WERR_NO_SUCH_DOMAIN;
1530 if (domain->primary) {
1531 TALLOC_FREE(frame);
1532 return WERR_NO_SUCH_DOMAIN;
1535 trusted_domain_name.string = domain->name;
1536 trusted_domain_name_l.string = domain->name;
1538 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1539 &local_lsa_policy);
1540 if (!NT_STATUS_IS_OK(status)) {
1541 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1542 __location__, __func__, nt_errstr(status)));
1543 TALLOC_FREE(frame);
1544 return WERR_INTERNAL_ERROR;
1546 local_lsa = local_lsa_pipe->binding_handle;
1548 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1549 &local_lsa_policy,
1550 &trusted_domain_name,
1551 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1552 &tdi, &result);
1553 if (!NT_STATUS_IS_OK(status)) {
1554 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1555 __location__, __func__, domain->name, nt_errstr(status)));
1556 TALLOC_FREE(frame);
1557 return WERR_INTERNAL_ERROR;
1559 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1560 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1561 __location__, __func__, domain->name));
1562 TALLOC_FREE(frame);
1563 return WERR_NO_SUCH_DOMAIN;
1565 if (!NT_STATUS_IS_OK(result)) {
1566 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1567 __location__, __func__, domain->name, nt_errstr(result)));
1568 TALLOC_FREE(frame);
1569 return WERR_INTERNAL_ERROR;
1571 if (tdi == NULL) {
1572 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1573 "returned no trusted domain information\n",
1574 __location__, __func__));
1575 TALLOC_FREE(frame);
1576 return WERR_INTERNAL_ERROR;
1579 tdo = &tdi->info_ex;
1581 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1582 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1583 __func__, tdo->netbios_name.string,
1584 tdo->domain_name.string,
1585 (unsigned)tdo->trust_attributes));
1586 TALLOC_FREE(frame);
1587 return WERR_NO_SUCH_DOMAIN;
1590 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1591 TALLOC_FREE(frame);
1592 return WERR_INVALID_FLAGS;
1595 reconnect:
1596 status = cm_connect_netlogon(domain, &netlogon_pipe);
1597 reset_cm_connection_on_error(domain, status);
1598 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1599 status = NT_STATUS_NO_LOGON_SERVERS;
1601 if (!NT_STATUS_IS_OK(status)) {
1602 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1603 nt_errstr(status)));
1604 TALLOC_FREE(frame);
1605 return ntstatus_to_werror(status);
1607 b = netlogon_pipe->binding_handle;
1609 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1610 b, p->mem_ctx,
1611 &new_fti);
1612 if (!NT_STATUS_IS_OK(status)) {
1613 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1614 invalidate_cm_connection(domain);
1615 retry = true;
1616 goto reconnect;
1618 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1619 domain->name, nt_errstr(status)));
1620 TALLOC_FREE(frame);
1621 return ntstatus_to_werror(status);
1624 *r->out.forest_trust_info = new_fti;
1626 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1627 update_fti = true;
1630 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1631 &local_lsa_policy,
1632 &trusted_domain_name,
1633 LSA_FOREST_TRUST_DOMAIN_INFO,
1634 &old_fti, &result);
1635 if (!NT_STATUS_IS_OK(status)) {
1636 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1637 __location__, __func__, domain->name, nt_errstr(status)));
1638 TALLOC_FREE(frame);
1639 return WERR_INTERNAL_ERROR;
1641 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1642 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1643 __func__, domain->name));
1644 update_fti = true;
1645 old_fti = &_old_fti;
1646 result = NT_STATUS_OK;
1648 if (!NT_STATUS_IS_OK(result)) {
1649 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1650 __location__, __func__, domain->name, nt_errstr(result)));
1651 TALLOC_FREE(frame);
1652 return WERR_INTERNAL_ERROR;
1655 if (old_fti == NULL) {
1656 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1657 "returned success without returning forest trust information\n",
1658 __location__, __func__));
1659 TALLOC_FREE(frame);
1660 return WERR_INTERNAL_ERROR;
1663 if (!update_fti) {
1664 goto done;
1667 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1668 &merged_fti);
1669 if (!NT_STATUS_IS_OK(status)) {
1670 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1671 __location__, __func__, domain->name, nt_errstr(status)));
1672 TALLOC_FREE(frame);
1673 return ntstatus_to_werror(status);
1676 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1677 &local_lsa_policy,
1678 &trusted_domain_name_l,
1679 LSA_FOREST_TRUST_DOMAIN_INFO,
1680 merged_fti,
1681 0, /* check_only=0 => store it! */
1682 &collision_info,
1683 &result);
1684 if (!NT_STATUS_IS_OK(status)) {
1685 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1686 __location__, __func__, domain->name, nt_errstr(status)));
1687 TALLOC_FREE(frame);
1688 return WERR_INTERNAL_ERROR;
1690 if (!NT_STATUS_IS_OK(result)) {
1691 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1692 __location__, __func__, domain->name, nt_errstr(result)));
1693 TALLOC_FREE(frame);
1694 return ntstatus_to_werror(result);
1697 done:
1698 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1699 TALLOC_FREE(frame);
1700 return WERR_OK;