s4:torture: FinderInfo conversion test with AppleDouble without xattr data
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob8cb05f06db6c0c3ceaecc8aacf3ebc0697c7c808
1 /*
2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "ntdomain.h"
28 #include "librpc/gen_ndr/srv_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
31 #include "idmap.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
34 #include "passdb.h"
35 #include "../source4/dsdb/samdb/samdb.h"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
38 #include "libsmb/dsgetdcname.h"
40 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
42 *r->out.out_data = r->in.in_data;
45 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
46 struct dcerpc_binding_handle *b,
47 NTSTATUS status)
49 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
50 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
51 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
52 invalidate_cm_connection(domain);
53 domain->conn.netlogon_force_reauth = true;
54 return true;
57 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
58 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
60 invalidate_cm_connection(domain);
61 /* We invalidated the connection. */
62 return true;
65 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
66 invalidate_cm_connection(domain);
67 return true;
70 return false;
73 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
75 struct winbindd_domain *domain = wb_child_domain();
76 char *dom_name;
77 char *name;
78 enum lsa_SidType type;
79 NTSTATUS status;
81 if (domain == NULL) {
82 return NT_STATUS_REQUEST_NOT_ACCEPTED;
85 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
86 &dom_name, &name, &type);
87 reset_cm_connection_on_error(domain, NULL, status);
88 if (!NT_STATUS_IS_OK(status)) {
89 return status;
92 *r->out.domain = dom_name;
93 *r->out.name = name;
94 *r->out.type = type;
95 return NT_STATUS_OK;
98 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
100 struct winbindd_domain *domain = wb_child_domain();
101 struct lsa_RefDomainList *domains = r->out.domains;
102 NTSTATUS status;
103 bool retry = false;
105 if (domain == NULL) {
106 return NT_STATUS_REQUEST_NOT_ACCEPTED;
110 * This breaks the winbindd_domain->methods abstraction: This
111 * is only called for remote domains, and both winbindd_msrpc
112 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
113 * done at the wbint RPC layer.
115 again:
116 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
117 &domains, &r->out.names);
119 if (domains != NULL) {
120 r->out.domains = domains;
123 if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
124 retry = true;
125 goto again;
128 return status;
131 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
133 struct winbindd_domain *domain = wb_child_domain();
134 NTSTATUS status;
136 if (domain == NULL) {
137 return NT_STATUS_REQUEST_NOT_ACCEPTED;
140 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
141 r->in.name, r->in.flags,
142 r->out.sid, r->out.type);
143 reset_cm_connection_on_error(domain, NULL, status);
144 return status;
147 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
148 struct wbint_Sids2UnixIDs *r)
150 uint32_t i;
152 struct lsa_DomainInfo *d;
153 struct wbint_TransID *ids;
154 uint32_t num_ids;
156 struct id_map **id_map_ptrs = NULL;
157 struct idmap_domain *dom;
158 NTSTATUS status = NT_STATUS_NO_MEMORY;
160 if (r->in.domains->count != 1) {
161 return NT_STATUS_INVALID_PARAMETER;
164 d = &r->in.domains->domains[0];
165 ids = r->in.ids->ids;
166 num_ids = r->in.ids->num_ids;
168 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
169 if (dom == NULL) {
170 DEBUG(10, ("idmap domain %s:%s not found\n",
171 d->name.string, sid_string_dbg(d->sid)));
173 for (i=0; i<num_ids; i++) {
175 ids[i].xid = (struct unixid) {
176 .id = UINT32_MAX,
177 .type = ID_TYPE_NOT_SPECIFIED
181 return NT_STATUS_OK;
184 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
185 if (id_map_ptrs == NULL) {
186 goto nomem;
190 * Convert the input data into a list of id_map structs
191 * suitable for handing in to the idmap sids_to_unixids
192 * method.
195 for (i=0; i<num_ids; i++) {
196 struct id_map *m = id_map_ptrs[i];
198 sid_compose(m->sid, d->sid, ids[i].rid);
199 m->status = ID_UNKNOWN;
200 m->xid = (struct unixid) { .type = ids[i].type };
203 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
205 if (!NT_STATUS_IS_OK(status)) {
206 DEBUG(10, ("sids_to_unixids returned %s\n",
207 nt_errstr(status)));
208 goto done;
212 * Extract the results for handing them back to the caller.
215 for (i=0; i<num_ids; i++) {
216 struct id_map *m = id_map_ptrs[i];
218 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
219 DBG_DEBUG("id %"PRIu32" is out of range "
220 "%"PRIu32"-%"PRIu32" for domain %s\n",
221 m->xid.id, dom->low_id, dom->high_id,
222 dom->name);
223 m->status = ID_UNMAPPED;
226 if (m->status == ID_MAPPED) {
227 ids[i].xid = m->xid;
228 } else {
229 ids[i].xid.id = UINT32_MAX;
230 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
234 goto done;
235 nomem:
236 status = NT_STATUS_NO_MEMORY;
237 done:
238 TALLOC_FREE(id_map_ptrs);
239 return status;
242 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
243 struct wbint_UnixIDs2Sids *r)
245 struct id_map **maps;
246 NTSTATUS status;
247 uint32_t i;
249 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
250 if (maps == NULL) {
251 return NT_STATUS_NO_MEMORY;
254 for (i=0; i<r->in.num_ids; i++) {
255 maps[i]->status = ID_UNKNOWN;
256 maps[i]->xid = r->in.xids[i];
259 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
260 r->in.domain_sid);
261 if (!NT_STATUS_IS_OK(status)) {
262 TALLOC_FREE(maps);
263 return status;
266 for (i=0; i<r->in.num_ids; i++) {
267 r->out.xids[i] = maps[i]->xid;
268 sid_copy(&r->out.sids[i], maps[i]->sid);
271 TALLOC_FREE(maps);
273 return NT_STATUS_OK;
276 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
278 struct unixid xid;
279 NTSTATUS status;
281 status = idmap_allocate_uid(&xid);
282 if (!NT_STATUS_IS_OK(status)) {
283 return status;
285 *r->out.uid = xid.id;
286 return NT_STATUS_OK;
289 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
291 struct unixid xid;
292 NTSTATUS status;
294 status = idmap_allocate_gid(&xid);
295 if (!NT_STATUS_IS_OK(status)) {
296 return status;
298 *r->out.gid = xid.id;
299 return NT_STATUS_OK;
302 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
304 struct idmap_domain *domain;
305 NTSTATUS status;
307 domain = idmap_find_domain(r->in.info->domain_name);
308 if ((domain == NULL) || (domain->query_user == NULL)) {
309 return NT_STATUS_REQUEST_NOT_ACCEPTED;
312 status = domain->query_user(domain, r->in.info);
313 return status;
316 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
317 struct wbint_LookupUserAliases *r)
319 struct winbindd_domain *domain = wb_child_domain();
320 NTSTATUS status;
322 if (domain == NULL) {
323 return NT_STATUS_REQUEST_NOT_ACCEPTED;
326 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
327 r->in.sids->num_sids,
328 r->in.sids->sids,
329 &r->out.rids->num_rids,
330 &r->out.rids->rids);
331 reset_cm_connection_on_error(domain, NULL, status);
332 return status;
335 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
336 struct wbint_LookupUserGroups *r)
338 struct winbindd_domain *domain = wb_child_domain();
339 NTSTATUS status;
341 if (domain == NULL) {
342 return NT_STATUS_REQUEST_NOT_ACCEPTED;
345 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
346 &r->out.sids->num_sids,
347 &r->out.sids->sids);
348 reset_cm_connection_on_error(domain, NULL, status);
349 return status;
352 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
353 struct wbint_QuerySequenceNumber *r)
355 struct winbindd_domain *domain = wb_child_domain();
356 NTSTATUS status;
358 if (domain == NULL) {
359 return NT_STATUS_REQUEST_NOT_ACCEPTED;
362 status = wb_cache_sequence_number(domain, r->out.sequence);
363 reset_cm_connection_on_error(domain, NULL, status);
364 return status;
367 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
368 struct wbint_LookupGroupMembers *r)
370 struct winbindd_domain *domain = wb_child_domain();
371 uint32_t i, num_names;
372 struct dom_sid *sid_mem;
373 char **names;
374 uint32_t *name_types;
375 NTSTATUS status;
377 if (domain == NULL) {
378 return NT_STATUS_REQUEST_NOT_ACCEPTED;
381 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
382 r->in.type, &num_names, &sid_mem,
383 &names, &name_types);
384 reset_cm_connection_on_error(domain, NULL, status);
385 if (!NT_STATUS_IS_OK(status)) {
386 return status;
389 r->out.members->num_principals = num_names;
390 r->out.members->principals = talloc_array(
391 r->out.members, struct wbint_Principal, num_names);
392 if (r->out.members->principals == NULL) {
393 return NT_STATUS_NO_MEMORY;
396 for (i=0; i<num_names; i++) {
397 struct wbint_Principal *m = &r->out.members->principals[i];
398 sid_copy(&m->sid, &sid_mem[i]);
399 m->name = talloc_move(r->out.members->principals, &names[i]);
400 m->type = (enum lsa_SidType)name_types[i];
403 return NT_STATUS_OK;
406 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
407 struct wbint_QueryGroupList *r)
409 TALLOC_CTX *frame = NULL;
410 struct winbindd_domain *domain = wb_child_domain();
411 uint32_t i;
412 uint32_t num_local_groups = 0;
413 struct wb_acct_info *local_groups = NULL;
414 uint32_t num_dom_groups = 0;
415 struct wb_acct_info *dom_groups = NULL;
416 uint32_t ti = 0;
417 uint64_t num_total = 0;
418 struct wbint_Principal *result;
419 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
420 bool include_local_groups = false;
422 if (domain == NULL) {
423 return NT_STATUS_REQUEST_NOT_ACCEPTED;
426 frame = talloc_stackframe();
428 switch (lp_server_role()) {
429 case ROLE_ACTIVE_DIRECTORY_DC:
430 if (domain->internal) {
432 * we want to include local groups
433 * for BUILTIN and WORKGROUP
435 include_local_groups = true;
437 break;
438 default:
440 * We might include local groups in more
441 * setups later, but that requires more work
442 * elsewhere.
444 break;
447 if (include_local_groups) {
448 status = wb_cache_enum_local_groups(domain, frame,
449 &num_local_groups,
450 &local_groups);
451 reset_cm_connection_on_error(domain, NULL, status);
452 if (!NT_STATUS_IS_OK(status)) {
453 goto out;
457 status = wb_cache_enum_dom_groups(domain, frame,
458 &num_dom_groups,
459 &dom_groups);
460 reset_cm_connection_on_error(domain, NULL, status);
461 if (!NT_STATUS_IS_OK(status)) {
462 goto out;
465 num_total = num_local_groups + num_dom_groups;
466 if (num_total > UINT32_MAX) {
467 status = NT_STATUS_INTERNAL_ERROR;
468 goto out;
471 result = talloc_array(frame, struct wbint_Principal, num_total);
472 if (result == NULL) {
473 status = NT_STATUS_NO_MEMORY;
474 goto out;
477 for (i = 0; i < num_local_groups; i++) {
478 struct wb_acct_info *lg = &local_groups[i];
479 struct wbint_Principal *rg = &result[ti++];
481 sid_compose(&rg->sid, &domain->sid, lg->rid);
482 rg->type = SID_NAME_ALIAS;
483 rg->name = talloc_strdup(result, lg->acct_name);
484 if (rg->name == NULL) {
485 status = NT_STATUS_NO_MEMORY;
486 goto out;
489 num_local_groups = 0;
491 for (i = 0; i < num_dom_groups; i++) {
492 struct wb_acct_info *dg = &dom_groups[i];
493 struct wbint_Principal *rg = &result[ti++];
495 sid_compose(&rg->sid, &domain->sid, dg->rid);
496 rg->type = SID_NAME_DOM_GRP;
497 rg->name = talloc_strdup(result, dg->acct_name);
498 if (rg->name == NULL) {
499 status = NT_STATUS_NO_MEMORY;
500 goto out;
503 num_dom_groups = 0;
505 r->out.groups->num_principals = ti;
506 r->out.groups->principals = talloc_move(r->out.groups, &result);
508 status = NT_STATUS_OK;
509 out:
510 TALLOC_FREE(frame);
511 return status;
514 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
515 struct wbint_QueryUserRidList *r)
517 struct winbindd_domain *domain = wb_child_domain();
518 NTSTATUS status;
520 if (domain == NULL) {
521 return NT_STATUS_REQUEST_NOT_ACCEPTED;
525 * Right now this is overkill. We should add a backend call
526 * just querying the rids.
529 status = wb_cache_query_user_list(domain, p->mem_ctx,
530 &r->out.rids->rids);
531 reset_cm_connection_on_error(domain, NULL, status);
533 if (!NT_STATUS_IS_OK(status)) {
534 return status;
537 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
539 return NT_STATUS_OK;
542 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
544 struct winbindd_domain *domain = wb_child_domain();
545 struct rpc_pipe_client *netlogon_pipe;
546 struct netr_DsRGetDCNameInfo *dc_info;
547 NTSTATUS status;
548 WERROR werr;
549 unsigned int orig_timeout;
550 struct dcerpc_binding_handle *b;
551 bool retry = false;
552 bool try_dsrgetdcname = false;
554 if (domain == NULL) {
555 return dsgetdcname(p->mem_ctx, server_messaging_context(),
556 r->in.domain_name, r->in.domain_guid,
557 r->in.site_name ? r->in.site_name : "",
558 r->in.flags,
559 r->out.dc_info);
562 if (domain->active_directory) {
563 try_dsrgetdcname = true;
566 reconnect:
567 status = cm_connect_netlogon(domain, &netlogon_pipe);
569 reset_cm_connection_on_error(domain, NULL, status);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
572 return status;
575 b = netlogon_pipe->binding_handle;
577 /* This call can take a long time - allow the server to time out.
578 35 seconds should do it. */
580 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
582 if (try_dsrgetdcname) {
583 status = dcerpc_netr_DsRGetDCName(b,
584 p->mem_ctx, domain->dcname,
585 r->in.domain_name, NULL, r->in.domain_guid,
586 r->in.flags, r->out.dc_info, &werr);
587 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
588 goto done;
590 if (!retry &&
591 reset_cm_connection_on_error(domain, NULL, status))
593 retry = true;
594 goto reconnect;
596 try_dsrgetdcname = false;
597 retry = false;
601 * Fallback to less capable methods
604 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
605 if (dc_info == NULL) {
606 status = NT_STATUS_NO_MEMORY;
607 goto done;
610 if (r->in.flags & DS_PDC_REQUIRED) {
611 status = dcerpc_netr_GetDcName(b,
612 p->mem_ctx, domain->dcname,
613 r->in.domain_name, &dc_info->dc_unc, &werr);
614 } else {
615 status = dcerpc_netr_GetAnyDCName(b,
616 p->mem_ctx, domain->dcname,
617 r->in.domain_name, &dc_info->dc_unc, &werr);
620 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
621 retry = true;
622 goto reconnect;
624 if (!NT_STATUS_IS_OK(status)) {
625 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
626 nt_errstr(status)));
627 goto done;
629 if (!W_ERROR_IS_OK(werr)) {
630 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
631 win_errstr(werr)));
632 status = werror_to_ntstatus(werr);
633 goto done;
636 *r->out.dc_info = dc_info;
637 status = NT_STATUS_OK;
639 done:
640 /* And restore our original timeout. */
641 rpccli_set_timeout(netlogon_pipe, orig_timeout);
643 return status;
646 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
648 struct winbindd_domain *domain = wb_child_domain();
649 char *domain_name;
650 char **names;
651 enum lsa_SidType *types;
652 struct wbint_Principal *result;
653 NTSTATUS status;
654 uint32_t i;
656 if (domain == NULL) {
657 return NT_STATUS_REQUEST_NOT_ACCEPTED;
660 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
661 r->in.rids->rids, r->in.rids->num_rids,
662 &domain_name, &names, &types);
663 reset_cm_connection_on_error(domain, NULL, status);
664 if (!NT_STATUS_IS_OK(status)) {
665 return status;
668 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
670 result = talloc_array(p->mem_ctx, struct wbint_Principal,
671 r->in.rids->num_rids);
672 if (result == NULL) {
673 return NT_STATUS_NO_MEMORY;
676 for (i=0; i<r->in.rids->num_rids; i++) {
677 sid_compose(&result[i].sid, r->in.domain_sid,
678 r->in.rids->rids[i]);
679 result[i].type = types[i];
680 result[i].name = talloc_move(result, &names[i]);
682 TALLOC_FREE(types);
683 TALLOC_FREE(names);
685 r->out.names->num_principals = r->in.rids->num_rids;
686 r->out.names->principals = result;
687 return NT_STATUS_OK;
690 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
691 struct wbint_CheckMachineAccount *r)
693 struct winbindd_domain *domain;
694 int num_retries = 0;
695 NTSTATUS status;
697 domain = wb_child_domain();
698 if (domain == NULL) {
699 return NT_STATUS_REQUEST_NOT_ACCEPTED;
702 again:
703 invalidate_cm_connection(domain);
704 domain->conn.netlogon_force_reauth = true;
707 struct rpc_pipe_client *netlogon_pipe = NULL;
708 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
709 status = cm_connect_netlogon_secure(domain,
710 &netlogon_pipe,
711 &netlogon_creds_ctx);
714 /* There is a race condition between fetching the trust account
715 password and the periodic machine password change. So it's
716 possible that the trust account password has been changed on us.
717 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
719 #define MAX_RETRIES 3
721 if ((num_retries < MAX_RETRIES)
722 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
723 num_retries++;
724 goto again;
727 if (!NT_STATUS_IS_OK(status)) {
728 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
729 goto done;
732 /* Pass back result code - zero for success, other values for
733 specific failures. */
735 DEBUG(3,("domain %s secret is %s\n", domain->name,
736 NT_STATUS_IS_OK(status) ? "good" : "bad"));
738 done:
739 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
740 ("Checking the trust account password for domain %s returned %s\n",
741 domain->name, nt_errstr(status)));
743 return status;
746 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
747 struct wbint_ChangeMachineAccount *r)
749 struct messaging_context *msg_ctx = server_messaging_context();
750 struct winbindd_domain *domain;
751 NTSTATUS status;
752 struct rpc_pipe_client *netlogon_pipe = NULL;
753 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
755 domain = wb_child_domain();
756 if (domain == NULL) {
757 return NT_STATUS_REQUEST_NOT_ACCEPTED;
760 status = cm_connect_netlogon_secure(domain,
761 &netlogon_pipe,
762 &netlogon_creds_ctx);
763 if (!NT_STATUS_IS_OK(status)) {
764 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
765 goto done;
768 status = trust_pw_change(netlogon_creds_ctx,
769 msg_ctx,
770 netlogon_pipe->binding_handle,
771 domain->name,
772 domain->dcname,
773 true); /* force */
775 /* Pass back result code - zero for success, other values for
776 specific failures. */
778 DEBUG(3,("domain %s secret %s\n", domain->name,
779 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
781 done:
782 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
783 ("Changing the trust account password for domain %s returned %s\n",
784 domain->name, nt_errstr(status)));
786 return status;
789 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
791 NTSTATUS status;
792 struct winbindd_domain *domain;
793 struct rpc_pipe_client *netlogon_pipe;
794 union netr_CONTROL_QUERY_INFORMATION info;
795 WERROR werr;
796 fstring logon_server;
797 struct dcerpc_binding_handle *b;
798 bool retry = false;
800 domain = wb_child_domain();
801 if (domain == NULL) {
802 return NT_STATUS_REQUEST_NOT_ACCEPTED;
805 reconnect:
806 status = cm_connect_netlogon(domain, &netlogon_pipe);
807 reset_cm_connection_on_error(domain, NULL, status);
808 if (!NT_STATUS_IS_OK(status)) {
809 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
810 nt_errstr(status)));
811 return status;
814 b = netlogon_pipe->binding_handle;
816 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
817 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
818 if (*r->out.dcname == NULL) {
819 DEBUG(2, ("Could not allocate memory\n"));
820 return NT_STATUS_NO_MEMORY;
824 * This provokes a WERR_NOT_SUPPORTED error message. This is
825 * documented in the wspp docs. I could not get a successful
826 * call to work, but the main point here is testing that the
827 * netlogon pipe works.
829 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
830 logon_server, NETLOGON_CONTROL_QUERY,
831 2, &info, &werr);
833 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
834 retry = true;
835 goto reconnect;
838 if (!NT_STATUS_IS_OK(status)) {
839 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
840 nt_errstr(status)));
841 return status;
844 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
845 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
846 "WERR_NOT_SUPPORTED\n",
847 win_errstr(werr)));
848 return werror_to_ntstatus(werr);
851 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
852 return NT_STATUS_OK;
855 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
856 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
858 struct winbindd_domain *domain;
859 NTSTATUS status;
860 struct rpc_pipe_client *netlogon_pipe = NULL;
861 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
862 struct dcerpc_binding_handle *b = NULL;
863 bool retry = false;
865 domain = wb_child_domain();
866 if (domain == NULL) {
867 return NT_STATUS_REQUEST_NOT_ACCEPTED;
870 reconnect:
871 status = cm_connect_netlogon_secure(domain,
872 &netlogon_pipe,
873 &netlogon_creds_ctx);
874 if (!NT_STATUS_IS_OK(status)) {
875 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
876 goto done;
879 b = netlogon_pipe->binding_handle;
881 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
882 netlogon_pipe->binding_handle,
883 r->in.site_name,
884 r->in.dns_ttl,
885 r->in.dns_names);
887 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
888 retry = true;
889 goto reconnect;
892 /* Pass back result code - zero for success, other values for
893 specific failures. */
895 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
896 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
898 done:
899 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
900 ("Update of DNS records via RW DC %s returned %s\n",
901 domain->name, nt_errstr(status)));
903 return status;
906 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
907 struct winbind_SamLogon *r)
909 struct winbindd_domain *domain;
910 NTSTATUS status;
911 struct netr_IdentityInfo *identity_info = NULL;
912 const uint8_t chal_zero[8] = {0, };
913 const uint8_t *challenge = chal_zero;
914 DATA_BLOB lm_response, nt_response;
915 uint32_t flags = 0;
916 uint16_t validation_level;
917 union netr_Validation *validation = NULL;
918 bool interactive = false;
920 domain = wb_child_domain();
921 if (domain == NULL) {
922 return NT_STATUS_REQUEST_NOT_ACCEPTED;
925 switch (r->in.validation_level) {
926 case 3:
927 case 6:
928 break;
929 default:
930 return NT_STATUS_REQUEST_NOT_ACCEPTED;
933 switch (r->in.logon_level) {
934 case NetlogonInteractiveInformation:
935 case NetlogonServiceInformation:
936 case NetlogonInteractiveTransitiveInformation:
937 case NetlogonServiceTransitiveInformation:
938 if (r->in.logon.password == NULL) {
939 return NT_STATUS_REQUEST_NOT_ACCEPTED;
942 interactive = true;
943 identity_info = &r->in.logon.password->identity_info;
945 challenge = chal_zero;
946 lm_response = data_blob_talloc(p->mem_ctx,
947 r->in.logon.password->lmpassword.hash,
948 sizeof(r->in.logon.password->lmpassword.hash));
949 nt_response = data_blob_talloc(p->mem_ctx,
950 r->in.logon.password->ntpassword.hash,
951 sizeof(r->in.logon.password->ntpassword.hash));
952 break;
954 case NetlogonNetworkInformation:
955 case NetlogonNetworkTransitiveInformation:
956 if (r->in.logon.network == NULL) {
957 return NT_STATUS_REQUEST_NOT_ACCEPTED;
960 interactive = false;
961 identity_info = &r->in.logon.network->identity_info;
963 challenge = r->in.logon.network->challenge;
964 lm_response = data_blob_talloc(p->mem_ctx,
965 r->in.logon.network->lm.data,
966 r->in.logon.network->lm.length);
967 nt_response = data_blob_talloc(p->mem_ctx,
968 r->in.logon.network->nt.data,
969 r->in.logon.network->nt.length);
970 break;
972 case NetlogonGenericInformation:
973 if (r->in.logon.generic == NULL) {
974 return NT_STATUS_REQUEST_NOT_ACCEPTED;
977 identity_info = &r->in.logon.generic->identity_info;
979 * Not implemented here...
981 return NT_STATUS_REQUEST_NOT_ACCEPTED;
983 default:
984 return NT_STATUS_REQUEST_NOT_ACCEPTED;
987 status = winbind_dual_SamLogon(domain, p->mem_ctx,
988 interactive,
989 identity_info->parameter_control,
990 identity_info->account_name.string,
991 identity_info->domain_name.string,
992 identity_info->workstation.string,
993 challenge,
994 lm_response, nt_response,
995 &r->out.authoritative,
996 true, /* skip_sam */
997 &flags,
998 &validation_level,
999 &validation);
1000 if (!NT_STATUS_IS_OK(status)) {
1001 return status;
1003 switch (r->in.validation_level) {
1004 case 3:
1005 status = map_validation_to_info3(p->mem_ctx,
1006 validation_level,
1007 validation,
1008 &r->out.validation.sam3);
1009 TALLOC_FREE(validation);
1010 if (!NT_STATUS_IS_OK(status)) {
1011 return status;
1013 return NT_STATUS_OK;
1014 case 6:
1015 status = map_validation_to_info6(p->mem_ctx,
1016 validation_level,
1017 validation,
1018 &r->out.validation.sam6);
1019 TALLOC_FREE(validation);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 return status;
1023 return NT_STATUS_OK;
1026 smb_panic(__location__);
1027 return NT_STATUS_INTERNAL_ERROR;
1030 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1031 struct winbindd_domain *domain,
1032 struct winbind_LogonControl *r)
1034 NTSTATUS status;
1035 struct rpc_pipe_client *netlogon_pipe = NULL;
1036 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1037 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1038 WERROR check_result = WERR_INTERNAL_ERROR;
1040 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1041 if (info2 == NULL) {
1042 return WERR_NOT_ENOUGH_MEMORY;
1045 if (domain->internal) {
1046 check_result = WERR_OK;
1047 goto check_return;
1051 * For now we just force a reconnect
1053 * TODO: take care of the optional '\dcname'
1055 invalidate_cm_connection(domain);
1056 domain->conn.netlogon_force_reauth = true;
1057 status = cm_connect_netlogon_secure(domain,
1058 &netlogon_pipe,
1059 &netlogon_creds_ctx);
1060 reset_cm_connection_on_error(domain, NULL, status);
1061 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1062 status = NT_STATUS_NO_LOGON_SERVERS;
1064 if (!NT_STATUS_IS_OK(status)) {
1065 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1066 __func__, domain->name, domain->alt_name,
1067 nt_errstr(status)));
1069 * Here we return a top level error!
1070 * This is different than TC_QUERY or TC_VERIFY.
1072 return ntstatus_to_werror(status);
1074 check_result = WERR_OK;
1076 check_return:
1077 info2->pdc_connection_status = WERR_OK;
1078 if (domain->dcname != NULL) {
1079 info2->flags |= NETLOGON_HAS_IP;
1080 info2->flags |= NETLOGON_HAS_TIMESERV;
1081 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1082 domain->dcname);
1083 if (info2->trusted_dc_name == NULL) {
1084 return WERR_NOT_ENOUGH_MEMORY;
1086 } else {
1087 info2->trusted_dc_name = talloc_strdup(info2, "");
1088 if (info2->trusted_dc_name == NULL) {
1089 return WERR_NOT_ENOUGH_MEMORY;
1092 info2->tc_connection_status = check_result;
1094 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1095 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1096 "pdc_connection[%s] tc_connection[%s]\n",
1097 __func__, domain->name, domain->alt_name,
1098 domain->dcname,
1099 win_errstr(info2->pdc_connection_status),
1100 win_errstr(info2->tc_connection_status)));
1103 r->out.query->info2 = info2;
1105 DEBUG(5, ("%s: succeeded.\n", __func__));
1106 return WERR_OK;
1109 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1110 struct winbindd_domain *domain,
1111 struct winbind_LogonControl *r)
1113 NTSTATUS status;
1114 struct rpc_pipe_client *netlogon_pipe = NULL;
1115 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1116 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1117 WERROR check_result = WERR_INTERNAL_ERROR;
1119 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1120 if (info2 == NULL) {
1121 return WERR_NOT_ENOUGH_MEMORY;
1124 if (domain->internal) {
1125 check_result = WERR_OK;
1126 goto check_return;
1129 status = cm_connect_netlogon_secure(domain,
1130 &netlogon_pipe,
1131 &netlogon_creds_ctx);
1132 reset_cm_connection_on_error(domain, NULL, status);
1133 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1134 status = NT_STATUS_NO_LOGON_SERVERS;
1136 if (!NT_STATUS_IS_OK(status)) {
1137 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1138 nt_errstr(status)));
1139 check_result = ntstatus_to_werror(status);
1140 goto check_return;
1142 check_result = WERR_OK;
1144 check_return:
1145 info2->pdc_connection_status = WERR_OK;
1146 if (domain->dcname != NULL) {
1147 info2->flags |= NETLOGON_HAS_IP;
1148 info2->flags |= NETLOGON_HAS_TIMESERV;
1149 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1150 domain->dcname);
1151 if (info2->trusted_dc_name == NULL) {
1152 return WERR_NOT_ENOUGH_MEMORY;
1154 } else {
1155 info2->trusted_dc_name = talloc_strdup(info2, "");
1156 if (info2->trusted_dc_name == NULL) {
1157 return WERR_NOT_ENOUGH_MEMORY;
1160 info2->tc_connection_status = check_result;
1162 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1163 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1164 "pdc_connection[%s] tc_connection[%s]\n",
1165 __func__, domain->name, domain->alt_name,
1166 domain->dcname,
1167 win_errstr(info2->pdc_connection_status),
1168 win_errstr(info2->tc_connection_status)));
1171 r->out.query->info2 = info2;
1173 DEBUG(5, ("%s: succeeded.\n", __func__));
1174 return WERR_OK;
1177 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1178 struct winbindd_domain *domain,
1179 struct winbind_LogonControl *r)
1181 TALLOC_CTX *frame = talloc_stackframe();
1182 NTSTATUS status;
1183 NTSTATUS result;
1184 struct lsa_String trusted_domain_name = {};
1185 struct lsa_StringLarge trusted_domain_name_l = {};
1186 struct rpc_pipe_client *local_lsa_pipe = NULL;
1187 struct policy_handle local_lsa_policy = {};
1188 struct dcerpc_binding_handle *local_lsa = NULL;
1189 struct rpc_pipe_client *netlogon_pipe = NULL;
1190 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1191 struct cli_credentials *creds = NULL;
1192 struct samr_Password *cur_nt_hash = NULL;
1193 uint32_t trust_attributes = 0;
1194 struct samr_Password new_owf_password = {};
1195 int cmp_new = -1;
1196 struct samr_Password old_owf_password = {};
1197 int cmp_old = -1;
1198 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1199 bool fetch_fti = false;
1200 struct lsa_ForestTrustInformation *new_fti = NULL;
1201 struct netr_TrustInfo *trust_info = NULL;
1202 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1203 struct dcerpc_binding_handle *b = NULL;
1204 WERROR check_result = WERR_INTERNAL_ERROR;
1205 WERROR verify_result = WERR_INTERNAL_ERROR;
1206 bool retry = false;
1208 trusted_domain_name.string = domain->name;
1209 trusted_domain_name_l.string = domain->name;
1211 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1212 if (info2 == NULL) {
1213 TALLOC_FREE(frame);
1214 return WERR_NOT_ENOUGH_MEMORY;
1217 if (domain->internal) {
1218 check_result = WERR_OK;
1219 goto check_return;
1222 status = pdb_get_trust_credentials(domain->name,
1223 domain->alt_name,
1224 frame,
1225 &creds);
1226 if (NT_STATUS_IS_OK(status)) {
1227 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1228 TALLOC_FREE(creds);
1231 if (!domain->primary) {
1232 union lsa_TrustedDomainInfo *tdi = NULL;
1234 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1235 &local_lsa_policy);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1238 __location__, __func__, nt_errstr(status)));
1239 TALLOC_FREE(frame);
1240 return WERR_INTERNAL_ERROR;
1242 local_lsa = local_lsa_pipe->binding_handle;
1244 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1245 &local_lsa_policy,
1246 &trusted_domain_name,
1247 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1248 &tdi, &result);
1249 if (!NT_STATUS_IS_OK(status)) {
1250 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1251 __location__, __func__, domain->name, nt_errstr(status)));
1252 TALLOC_FREE(frame);
1253 return WERR_INTERNAL_ERROR;
1255 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1256 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1257 __location__, __func__, domain->name));
1258 TALLOC_FREE(frame);
1259 return WERR_NO_SUCH_DOMAIN;
1261 if (!NT_STATUS_IS_OK(result)) {
1262 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1263 __location__, __func__, domain->name, nt_errstr(result)));
1264 TALLOC_FREE(frame);
1265 return WERR_INTERNAL_ERROR;
1267 if (tdi == NULL) {
1268 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1269 "returned no trusted domain information\n",
1270 __location__, __func__));
1271 TALLOC_FREE(frame);
1272 return WERR_INTERNAL_ERROR;
1275 local_tdo = &tdi->info_ex;
1276 trust_attributes = local_tdo->trust_attributes;
1279 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1280 struct lsa_ForestTrustInformation *old_fti = NULL;
1282 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1283 &local_lsa_policy,
1284 &trusted_domain_name,
1285 LSA_FOREST_TRUST_DOMAIN_INFO,
1286 &old_fti, &result);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1289 __location__, __func__, domain->name, nt_errstr(status)));
1290 TALLOC_FREE(frame);
1291 return WERR_INTERNAL_ERROR;
1293 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1294 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1295 __func__, domain->name));
1296 old_fti = NULL;
1297 fetch_fti = true;
1298 result = NT_STATUS_OK;
1300 if (!NT_STATUS_IS_OK(result)) {
1301 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1302 __location__, __func__, domain->name, nt_errstr(result)));
1303 TALLOC_FREE(frame);
1304 return WERR_INTERNAL_ERROR;
1307 TALLOC_FREE(old_fti);
1310 reconnect:
1311 status = cm_connect_netlogon_secure(domain,
1312 &netlogon_pipe,
1313 &netlogon_creds_ctx);
1314 reset_cm_connection_on_error(domain, NULL, status);
1315 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1316 status = NT_STATUS_NO_LOGON_SERVERS;
1318 if (!NT_STATUS_IS_OK(status)) {
1319 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1320 nt_errstr(status)));
1321 check_result = ntstatus_to_werror(status);
1322 goto check_return;
1324 check_result = WERR_OK;
1325 b = netlogon_pipe->binding_handle;
1327 if (cur_nt_hash == NULL) {
1328 verify_result = WERR_NO_TRUST_LSA_SECRET;
1329 goto verify_return;
1332 if (fetch_fti) {
1333 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1334 b, frame,
1335 &new_fti);
1336 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1337 status = NT_STATUS_NOT_SUPPORTED;
1339 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1340 new_fti = NULL;
1341 status = NT_STATUS_OK;
1343 if (!NT_STATUS_IS_OK(status)) {
1344 if (!retry &&
1345 reset_cm_connection_on_error(domain, b, status))
1347 retry = true;
1348 goto reconnect;
1350 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1351 "failed: %s\n",
1352 domain->name, nt_errstr(status)));
1353 check_result = ntstatus_to_werror(status);
1354 goto check_return;
1358 if (new_fti != NULL) {
1359 struct lsa_ForestTrustInformation old_fti = {};
1360 struct lsa_ForestTrustInformation *merged_fti = NULL;
1361 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1363 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1364 &old_fti, new_fti,
1365 &merged_fti);
1366 if (!NT_STATUS_IS_OK(status)) {
1367 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1368 __location__, __func__,
1369 domain->name, nt_errstr(status)));
1370 TALLOC_FREE(frame);
1371 return ntstatus_to_werror(status);
1374 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1375 &local_lsa_policy,
1376 &trusted_domain_name_l,
1377 LSA_FOREST_TRUST_DOMAIN_INFO,
1378 merged_fti,
1379 0, /* check_only=0 => store it! */
1380 &collision_info,
1381 &result);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1384 __location__, __func__, domain->name, nt_errstr(status)));
1385 TALLOC_FREE(frame);
1386 return WERR_INTERNAL_ERROR;
1388 if (!NT_STATUS_IS_OK(result)) {
1389 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1390 __location__, __func__, domain->name, nt_errstr(result)));
1391 TALLOC_FREE(frame);
1392 return ntstatus_to_werror(result);
1396 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1397 b, frame,
1398 &new_owf_password,
1399 &old_owf_password,
1400 &trust_info);
1401 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1402 status = NT_STATUS_NOT_SUPPORTED;
1404 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1405 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1406 nt_errstr(status)));
1407 verify_result = WERR_OK;
1408 goto verify_return;
1410 if (!NT_STATUS_IS_OK(status)) {
1411 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1412 retry = true;
1413 goto reconnect;
1415 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1416 nt_errstr(status)));
1418 if (!dcerpc_binding_handle_is_connected(b)) {
1419 check_result = ntstatus_to_werror(status);
1420 goto check_return;
1421 } else {
1422 verify_result = ntstatus_to_werror(status);
1423 goto verify_return;
1427 if (trust_info != NULL && trust_info->count >= 1) {
1428 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1430 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1431 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1432 goto verify_return;
1436 cmp_new = memcmp(new_owf_password.hash,
1437 cur_nt_hash->hash,
1438 sizeof(cur_nt_hash->hash));
1439 cmp_old = memcmp(old_owf_password.hash,
1440 cur_nt_hash->hash,
1441 sizeof(cur_nt_hash->hash));
1442 if (cmp_new != 0 && cmp_old != 0) {
1443 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1444 "any password known to dcname[%s]\n",
1445 __func__, domain->name, domain->alt_name,
1446 domain->dcname));
1447 verify_result = WERR_WRONG_PASSWORD;
1448 goto verify_return;
1451 if (cmp_new != 0) {
1452 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1453 "against the old password known to dcname[%s]\n",
1454 __func__, domain->name, domain->alt_name,
1455 domain->dcname));
1458 verify_result = WERR_OK;
1459 goto verify_return;
1461 check_return:
1462 verify_result = check_result;
1463 verify_return:
1464 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1465 info2->pdc_connection_status = verify_result;
1466 if (domain->dcname != NULL) {
1467 info2->flags |= NETLOGON_HAS_IP;
1468 info2->flags |= NETLOGON_HAS_TIMESERV;
1469 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1470 domain->dcname);
1471 if (info2->trusted_dc_name == NULL) {
1472 TALLOC_FREE(frame);
1473 return WERR_NOT_ENOUGH_MEMORY;
1475 } else {
1476 info2->trusted_dc_name = talloc_strdup(info2, "");
1477 if (info2->trusted_dc_name == NULL) {
1478 TALLOC_FREE(frame);
1479 return WERR_NOT_ENOUGH_MEMORY;
1482 info2->tc_connection_status = check_result;
1484 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1485 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1486 "pdc_connection[%s] tc_connection[%s]\n",
1487 __func__, domain->name, domain->alt_name,
1488 domain->dcname,
1489 win_errstr(info2->pdc_connection_status),
1490 win_errstr(info2->tc_connection_status)));
1493 r->out.query->info2 = info2;
1495 DEBUG(5, ("%s: succeeded.\n", __func__));
1496 TALLOC_FREE(frame);
1497 return WERR_OK;
1500 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1501 struct winbindd_domain *domain,
1502 struct winbind_LogonControl *r)
1504 struct messaging_context *msg_ctx = server_messaging_context();
1505 NTSTATUS status;
1506 struct rpc_pipe_client *netlogon_pipe = NULL;
1507 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1508 struct cli_credentials *creds = NULL;
1509 struct samr_Password *cur_nt_hash = NULL;
1510 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1511 struct dcerpc_binding_handle *b;
1512 WERROR change_result = WERR_OK;
1513 bool retry = false;
1515 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1516 if (info1 == NULL) {
1517 return WERR_NOT_ENOUGH_MEMORY;
1520 if (domain->internal) {
1521 return WERR_NOT_SUPPORTED;
1524 status = pdb_get_trust_credentials(domain->name,
1525 domain->alt_name,
1526 p->mem_ctx,
1527 &creds);
1528 if (NT_STATUS_IS_OK(status)) {
1529 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1530 TALLOC_FREE(creds);
1533 reconnect:
1534 status = cm_connect_netlogon_secure(domain,
1535 &netlogon_pipe,
1536 &netlogon_creds_ctx);
1537 reset_cm_connection_on_error(domain, NULL, status);
1538 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1539 status = NT_STATUS_NO_LOGON_SERVERS;
1541 if (!NT_STATUS_IS_OK(status)) {
1542 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1543 __func__, domain->name, domain->alt_name,
1544 nt_errstr(status)));
1546 * Here we return a top level error!
1547 * This is different than TC_QUERY or TC_VERIFY.
1549 return ntstatus_to_werror(status);
1551 b = netlogon_pipe->binding_handle;
1553 if (cur_nt_hash == NULL) {
1554 change_result = WERR_NO_TRUST_LSA_SECRET;
1555 goto change_return;
1557 TALLOC_FREE(cur_nt_hash);
1559 status = trust_pw_change(netlogon_creds_ctx,
1560 msg_ctx, b, domain->name,
1561 domain->dcname,
1562 true); /* force */
1563 if (!NT_STATUS_IS_OK(status)) {
1564 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1565 retry = true;
1566 goto reconnect;
1569 DEBUG(1, ("trust_pw_change(%s): %s\n",
1570 domain->name, nt_errstr(status)));
1572 change_result = ntstatus_to_werror(status);
1573 goto change_return;
1576 change_result = WERR_OK;
1578 change_return:
1579 info1->pdc_connection_status = change_result;
1581 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1582 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1583 "pdc_connection[%s]\n",
1584 __func__, domain->name, domain->alt_name,
1585 domain->dcname,
1586 win_errstr(info1->pdc_connection_status)));
1589 r->out.query->info1 = info1;
1591 DEBUG(5, ("%s: succeeded.\n", __func__));
1592 return WERR_OK;
1595 WERROR _winbind_LogonControl(struct pipes_struct *p,
1596 struct winbind_LogonControl *r)
1598 struct winbindd_domain *domain;
1600 domain = wb_child_domain();
1601 if (domain == NULL) {
1602 return WERR_NO_SUCH_DOMAIN;
1605 switch (r->in.function_code) {
1606 case NETLOGON_CONTROL_REDISCOVER:
1607 if (r->in.level != 2) {
1608 return WERR_INVALID_PARAMETER;
1610 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1611 case NETLOGON_CONTROL_TC_QUERY:
1612 if (r->in.level != 2) {
1613 return WERR_INVALID_PARAMETER;
1615 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1616 case NETLOGON_CONTROL_TC_VERIFY:
1617 if (r->in.level != 2) {
1618 return WERR_INVALID_PARAMETER;
1620 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1621 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1622 if (r->in.level != 1) {
1623 return WERR_INVALID_PARAMETER;
1625 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1626 default:
1627 break;
1630 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1631 __func__, r->in.function_code));
1632 return WERR_NOT_SUPPORTED;
1635 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1636 struct winbind_GetForestTrustInformation *r)
1638 TALLOC_CTX *frame = talloc_stackframe();
1639 NTSTATUS status, result;
1640 struct winbindd_domain *domain;
1641 struct rpc_pipe_client *netlogon_pipe = NULL;
1642 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1643 struct dcerpc_binding_handle *b;
1644 bool retry = false;
1645 struct lsa_String trusted_domain_name = {};
1646 struct lsa_StringLarge trusted_domain_name_l = {};
1647 union lsa_TrustedDomainInfo *tdi = NULL;
1648 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1649 struct lsa_ForestTrustInformation _old_fti = {};
1650 struct lsa_ForestTrustInformation *old_fti = NULL;
1651 struct lsa_ForestTrustInformation *new_fti = NULL;
1652 struct lsa_ForestTrustInformation *merged_fti = NULL;
1653 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1654 bool update_fti = false;
1655 struct rpc_pipe_client *local_lsa_pipe;
1656 struct policy_handle local_lsa_policy;
1657 struct dcerpc_binding_handle *local_lsa = NULL;
1659 domain = wb_child_domain();
1660 if (domain == NULL) {
1661 TALLOC_FREE(frame);
1662 return WERR_NO_SUCH_DOMAIN;
1666 * checking for domain->internal and domain->primary
1667 * makes sure we only do some work when running as DC.
1670 if (domain->internal) {
1671 TALLOC_FREE(frame);
1672 return WERR_NO_SUCH_DOMAIN;
1675 if (domain->primary) {
1676 TALLOC_FREE(frame);
1677 return WERR_NO_SUCH_DOMAIN;
1680 trusted_domain_name.string = domain->name;
1681 trusted_domain_name_l.string = domain->name;
1683 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1684 &local_lsa_policy);
1685 if (!NT_STATUS_IS_OK(status)) {
1686 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1687 __location__, __func__, nt_errstr(status)));
1688 TALLOC_FREE(frame);
1689 return WERR_INTERNAL_ERROR;
1691 local_lsa = local_lsa_pipe->binding_handle;
1693 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1694 &local_lsa_policy,
1695 &trusted_domain_name,
1696 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1697 &tdi, &result);
1698 if (!NT_STATUS_IS_OK(status)) {
1699 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1700 __location__, __func__, domain->name, nt_errstr(status)));
1701 TALLOC_FREE(frame);
1702 return WERR_INTERNAL_ERROR;
1704 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1705 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1706 __location__, __func__, domain->name));
1707 TALLOC_FREE(frame);
1708 return WERR_NO_SUCH_DOMAIN;
1710 if (!NT_STATUS_IS_OK(result)) {
1711 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1712 __location__, __func__, domain->name, nt_errstr(result)));
1713 TALLOC_FREE(frame);
1714 return WERR_INTERNAL_ERROR;
1716 if (tdi == NULL) {
1717 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1718 "returned no trusted domain information\n",
1719 __location__, __func__));
1720 TALLOC_FREE(frame);
1721 return WERR_INTERNAL_ERROR;
1724 tdo = &tdi->info_ex;
1726 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1727 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1728 __func__, tdo->netbios_name.string,
1729 tdo->domain_name.string,
1730 (unsigned)tdo->trust_attributes));
1731 TALLOC_FREE(frame);
1732 return WERR_NO_SUCH_DOMAIN;
1735 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1736 TALLOC_FREE(frame);
1737 return WERR_INVALID_FLAGS;
1740 reconnect:
1741 status = cm_connect_netlogon_secure(domain,
1742 &netlogon_pipe,
1743 &netlogon_creds_ctx);
1744 reset_cm_connection_on_error(domain, NULL, status);
1745 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1746 status = NT_STATUS_NO_LOGON_SERVERS;
1748 if (!NT_STATUS_IS_OK(status)) {
1749 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1750 nt_errstr(status)));
1751 TALLOC_FREE(frame);
1752 return ntstatus_to_werror(status);
1754 b = netlogon_pipe->binding_handle;
1756 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1757 b, p->mem_ctx,
1758 &new_fti);
1759 if (!NT_STATUS_IS_OK(status)) {
1760 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1761 retry = true;
1762 goto reconnect;
1764 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1765 domain->name, nt_errstr(status)));
1766 TALLOC_FREE(frame);
1767 return ntstatus_to_werror(status);
1770 *r->out.forest_trust_info = new_fti;
1772 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1773 update_fti = true;
1776 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1777 &local_lsa_policy,
1778 &trusted_domain_name,
1779 LSA_FOREST_TRUST_DOMAIN_INFO,
1780 &old_fti, &result);
1781 if (!NT_STATUS_IS_OK(status)) {
1782 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1783 __location__, __func__, domain->name, nt_errstr(status)));
1784 TALLOC_FREE(frame);
1785 return WERR_INTERNAL_ERROR;
1787 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1788 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1789 __func__, domain->name));
1790 update_fti = true;
1791 old_fti = &_old_fti;
1792 result = NT_STATUS_OK;
1794 if (!NT_STATUS_IS_OK(result)) {
1795 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1796 __location__, __func__, domain->name, nt_errstr(result)));
1797 TALLOC_FREE(frame);
1798 return WERR_INTERNAL_ERROR;
1801 if (old_fti == NULL) {
1802 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1803 "returned success without returning forest trust information\n",
1804 __location__, __func__));
1805 TALLOC_FREE(frame);
1806 return WERR_INTERNAL_ERROR;
1809 if (!update_fti) {
1810 goto done;
1813 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1814 &merged_fti);
1815 if (!NT_STATUS_IS_OK(status)) {
1816 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1817 __location__, __func__, domain->name, nt_errstr(status)));
1818 TALLOC_FREE(frame);
1819 return ntstatus_to_werror(status);
1822 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1823 &local_lsa_policy,
1824 &trusted_domain_name_l,
1825 LSA_FOREST_TRUST_DOMAIN_INFO,
1826 merged_fti,
1827 0, /* check_only=0 => store it! */
1828 &collision_info,
1829 &result);
1830 if (!NT_STATUS_IS_OK(status)) {
1831 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1832 __location__, __func__, domain->name, nt_errstr(status)));
1833 TALLOC_FREE(frame);
1834 return WERR_INTERNAL_ERROR;
1836 if (!NT_STATUS_IS_OK(result)) {
1837 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1838 __location__, __func__, domain->name, nt_errstr(result)));
1839 TALLOC_FREE(frame);
1840 return ntstatus_to_werror(result);
1843 done:
1844 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1845 TALLOC_FREE(frame);
1846 return WERR_OK;
1849 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1851 struct winbindd_domain *domain;
1852 NTSTATUS status;
1853 struct rpc_pipe_client *netlogon_pipe;
1854 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1855 struct dcerpc_binding_handle *b = NULL;
1856 bool retry = false;
1858 DEBUG(5, ("_winbind_SendToSam received\n"));
1859 domain = wb_child_domain();
1860 if (domain == NULL) {
1861 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1864 reconnect:
1865 status = cm_connect_netlogon_secure(domain,
1866 &netlogon_pipe,
1867 &netlogon_creds_ctx);
1868 reset_cm_connection_on_error(domain, NULL, status);
1869 if (!NT_STATUS_IS_OK(status)) {
1870 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1871 return status;
1874 b = netlogon_pipe->binding_handle;
1876 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1878 &r->in.message);
1879 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1880 retry = true;
1881 goto reconnect;
1884 return status;