ctdb-failover: Split statd_callout add-client/del-client
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob0c7e9dd54916a17f6b8c057deec33a964fe3167b
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/rpc/dcesrv_core.h"
29 #include "librpc/gen_ndr/ndr_winbind.h"
30 #include "librpc/gen_ndr/ndr_winbind_scompat.h"
31 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
32 #include "../librpc/gen_ndr/ndr_lsa_c.h"
33 #include "idmap.h"
34 #include "../libcli/security/security.h"
35 #include "../libcli/auth/netlogon_creds_cli.h"
36 #include "passdb.h"
37 #include "../source4/dsdb/samdb/samdb.h"
38 #include "rpc_client/cli_netlogon.h"
39 #include "rpc_client/util_netlogon.h"
40 #include "libsmb/dsgetdcname.h"
41 #include "lib/global_contexts.h"
43 NTSTATUS _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
45 *r->out.out_data = r->in.in_data;
46 return NT_STATUS_OK;
49 NTSTATUS _wbint_InitConnection(struct pipes_struct *p,
50 struct wbint_InitConnection *r)
52 struct winbindd_domain *domain = wb_child_domain();
54 if (r->in.dcname != NULL && strlen(r->in.dcname) > 0) {
55 TALLOC_FREE(domain->dcname);
56 domain->dcname = talloc_strdup(domain, r->in.dcname);
57 if (domain->dcname == NULL) {
58 return NT_STATUS_NO_MEMORY;
62 init_dc_connection(domain, false);
64 if (!domain->initialized) {
66 * If we return error here we can't do any cached
67 * authentication, but we may be in disconnected mode and can't
68 * initialize correctly. Do what the previous code did and just
69 * return without initialization, once we go online we'll
70 * re-initialize.
72 DBG_INFO("%s returning without initialization online = %d\n",
73 domain->name, (int)domain->online);
76 *r->out.name = talloc_strdup(p->mem_ctx, domain->name);
77 if (*r->out.name == NULL) {
78 return NT_STATUS_NO_MEMORY;
81 if (domain->alt_name != NULL) {
82 *r->out.alt_name = talloc_strdup(p->mem_ctx, domain->alt_name);
83 if (*r->out.alt_name == NULL) {
84 return NT_STATUS_NO_MEMORY;
88 r->out.sid = dom_sid_dup(p->mem_ctx, &domain->sid);
89 if (r->out.sid == NULL) {
90 return NT_STATUS_NO_MEMORY;
93 *r->out.flags = 0;
94 if (domain->native_mode) {
95 *r->out.flags |= WB_DOMINFO_DOMAIN_NATIVE;
97 if (domain->active_directory) {
98 *r->out.flags |= WB_DOMINFO_DOMAIN_AD;
100 if (domain->primary) {
101 *r->out.flags |= WB_DOMINFO_DOMAIN_PRIMARY;
104 return NT_STATUS_OK;
107 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
108 struct dcerpc_binding_handle *b,
109 NTSTATUS status)
111 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
112 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
113 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
114 invalidate_cm_connection(domain);
115 domain->conn.netlogon_force_reauth = true;
116 return true;
119 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
120 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
122 invalidate_cm_connection(domain);
123 /* We invalidated the connection. */
124 return true;
127 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
128 invalidate_cm_connection(domain);
129 return true;
132 return false;
135 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
137 struct winbindd_domain *domain = wb_child_domain();
138 char *dom_name;
139 char *name;
140 enum lsa_SidType type;
141 NTSTATUS status;
143 if (domain == NULL) {
144 return NT_STATUS_REQUEST_NOT_ACCEPTED;
147 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
148 &dom_name, &name, &type);
149 reset_cm_connection_on_error(domain, NULL, status);
150 if (!NT_STATUS_IS_OK(status)) {
151 return status;
154 *r->out.domain = dom_name;
155 *r->out.name = name;
156 *r->out.type = type;
157 return NT_STATUS_OK;
160 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
162 struct winbindd_domain *domain = wb_child_domain();
163 struct lsa_RefDomainList *domains = r->out.domains;
164 NTSTATUS status;
165 bool retry = false;
167 if (domain == NULL) {
168 return NT_STATUS_REQUEST_NOT_ACCEPTED;
172 * This breaks the winbindd_domain->methods abstraction: This
173 * is only called for remote domains, and both winbindd_msrpc
174 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
175 * done at the wbint RPC layer.
177 again:
178 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
179 &domains, &r->out.names);
181 if (domains != NULL) {
182 r->out.domains = domains;
185 if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
186 retry = true;
187 goto again;
190 return status;
193 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
195 struct winbindd_domain *domain = wb_child_domain();
196 NTSTATUS status;
198 if (domain == NULL) {
199 return NT_STATUS_REQUEST_NOT_ACCEPTED;
202 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
203 r->in.name, r->in.flags,
204 r->out.sid, r->out.type);
205 reset_cm_connection_on_error(domain, NULL, status);
206 return status;
209 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
210 struct wbint_Sids2UnixIDs *r)
212 uint32_t i;
214 struct lsa_DomainInfo *d;
215 struct wbint_TransID *ids;
216 uint32_t num_ids;
218 struct id_map **id_map_ptrs = NULL;
219 struct idmap_domain *dom;
220 NTSTATUS status = NT_STATUS_NO_MEMORY;
222 if (r->in.domains->count != 1) {
223 return NT_STATUS_INVALID_PARAMETER;
226 d = &r->in.domains->domains[0];
227 ids = r->in.ids->ids;
228 num_ids = r->in.ids->num_ids;
230 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
231 if (dom == NULL) {
232 struct dom_sid_buf buf;
233 DEBUG(10, ("idmap domain %s:%s not found\n",
234 d->name.string,
235 dom_sid_str_buf(d->sid, &buf)));
237 for (i=0; i<num_ids; i++) {
239 ids[i].xid = (struct unixid) {
240 .id = UINT32_MAX,
241 .type = ID_TYPE_NOT_SPECIFIED
245 return NT_STATUS_OK;
248 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
249 if (id_map_ptrs == NULL) {
250 goto nomem;
254 * Convert the input data into a list of id_map structs
255 * suitable for handing in to the idmap sids_to_unixids
256 * method.
259 for (i=0; i<num_ids; i++) {
260 struct id_map *m = id_map_ptrs[i];
262 sid_compose(m->sid, d->sid, ids[i].rid);
263 m->status = ID_UNKNOWN;
264 m->xid = (struct unixid) { .type = ids[i].type_hint };
267 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
269 if (NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
271 * This is okay. We need to transfer the mapped ones
272 * up to our caller. The individual mappings carry the
273 * information whether they are mapped or not.
275 status = NT_STATUS_OK;
278 if (!NT_STATUS_IS_OK(status)) {
279 DEBUG(10, ("sids_to_unixids returned %s\n",
280 nt_errstr(status)));
281 goto done;
285 * Extract the results for handing them back to the caller.
288 for (i=0; i<num_ids; i++) {
289 struct id_map *m = id_map_ptrs[i];
291 if (m->status == ID_REQUIRE_TYPE) {
292 ids[i].xid.id = UINT32_MAX;
293 ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE;
294 continue;
297 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
298 DBG_DEBUG("id %"PRIu32" is out of range "
299 "%"PRIu32"-%"PRIu32" for domain %s\n",
300 m->xid.id, dom->low_id, dom->high_id,
301 dom->name);
302 m->status = ID_UNMAPPED;
305 if (m->status == ID_MAPPED) {
306 ids[i].xid = m->xid;
307 } else {
308 ids[i].xid.id = UINT32_MAX;
309 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
313 goto done;
314 nomem:
315 status = NT_STATUS_NO_MEMORY;
316 done:
317 TALLOC_FREE(id_map_ptrs);
318 return status;
321 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
322 struct wbint_UnixIDs2Sids *r)
324 struct id_map **maps;
325 NTSTATUS status;
326 uint32_t i;
328 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
329 if (maps == NULL) {
330 return NT_STATUS_NO_MEMORY;
333 for (i=0; i<r->in.num_ids; i++) {
334 maps[i]->status = ID_UNKNOWN;
335 maps[i]->xid = r->in.xids[i];
338 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
339 r->in.domain_sid);
340 if (!NT_STATUS_IS_OK(status)) {
341 TALLOC_FREE(maps);
342 return status;
345 for (i=0; i<r->in.num_ids; i++) {
346 if (maps[i]->status == ID_MAPPED) {
347 r->out.xids[i] = maps[i]->xid;
348 sid_copy(&r->out.sids[i], maps[i]->sid);
349 } else {
350 r->out.sids[i] = (struct dom_sid) { 0 };
354 TALLOC_FREE(maps);
356 return NT_STATUS_OK;
359 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
361 struct unixid xid;
362 NTSTATUS status;
364 status = idmap_allocate_uid(&xid);
365 if (!NT_STATUS_IS_OK(status)) {
366 return status;
368 *r->out.uid = xid.id;
369 return NT_STATUS_OK;
372 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
374 struct unixid xid;
375 NTSTATUS status;
377 status = idmap_allocate_gid(&xid);
378 if (!NT_STATUS_IS_OK(status)) {
379 return status;
381 *r->out.gid = xid.id;
382 return NT_STATUS_OK;
385 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
387 struct idmap_domain *domain;
388 NTSTATUS status;
390 domain = idmap_find_domain(r->in.info->domain_name);
391 if ((domain == NULL) || (domain->query_user == NULL)) {
392 return NT_STATUS_REQUEST_NOT_ACCEPTED;
395 status = domain->query_user(domain, r->in.info);
396 return status;
399 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
400 struct wbint_LookupUserAliases *r)
402 struct winbindd_domain *domain = wb_child_domain();
403 NTSTATUS status;
405 if (domain == NULL) {
406 return NT_STATUS_REQUEST_NOT_ACCEPTED;
409 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
410 r->in.sids->num_sids,
411 r->in.sids->sids,
412 &r->out.rids->num_rids,
413 &r->out.rids->rids);
414 reset_cm_connection_on_error(domain, NULL, status);
415 return status;
418 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
419 struct wbint_LookupUserGroups *r)
421 struct winbindd_domain *domain = wb_child_domain();
422 NTSTATUS status;
424 if (domain == NULL) {
425 return NT_STATUS_REQUEST_NOT_ACCEPTED;
428 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
429 &r->out.sids->num_sids,
430 &r->out.sids->sids);
431 reset_cm_connection_on_error(domain, NULL, status);
432 return status;
435 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
436 struct wbint_QuerySequenceNumber *r)
438 struct winbindd_domain *domain = wb_child_domain();
439 NTSTATUS status;
441 if (domain == NULL) {
442 return NT_STATUS_REQUEST_NOT_ACCEPTED;
445 status = wb_cache_sequence_number(domain, r->out.sequence);
446 reset_cm_connection_on_error(domain, NULL, status);
447 return status;
450 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
451 struct wbint_LookupGroupMembers *r)
453 struct winbindd_domain *domain = wb_child_domain();
454 uint32_t i, num_names;
455 struct dom_sid *sid_mem;
456 char **names;
457 uint32_t *name_types;
458 NTSTATUS status;
460 if (domain == NULL) {
461 return NT_STATUS_REQUEST_NOT_ACCEPTED;
464 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
465 r->in.type, &num_names, &sid_mem,
466 &names, &name_types);
467 reset_cm_connection_on_error(domain, NULL, status);
468 if (!NT_STATUS_IS_OK(status)) {
469 return status;
472 r->out.members->num_principals = num_names;
473 r->out.members->principals = talloc_array(
474 r->out.members, struct wbint_Principal, num_names);
475 if (r->out.members->principals == NULL) {
476 return NT_STATUS_NO_MEMORY;
479 for (i=0; i<num_names; i++) {
480 struct wbint_Principal *m = &r->out.members->principals[i];
481 sid_copy(&m->sid, &sid_mem[i]);
482 m->name = talloc_move(r->out.members->principals, &names[i]);
483 m->type = (enum lsa_SidType)name_types[i];
486 return NT_STATUS_OK;
489 NTSTATUS _wbint_LookupAliasMembers(struct pipes_struct *p,
490 struct wbint_LookupAliasMembers *r)
492 struct winbindd_domain *domain = wb_child_domain();
493 NTSTATUS status;
495 if (domain == NULL) {
496 return NT_STATUS_REQUEST_NOT_ACCEPTED;
498 status = wb_cache_lookup_aliasmem(domain,
499 p->mem_ctx,
500 r->in.sid,
501 r->in.type,
502 &r->out.sids->num_sids,
503 &r->out.sids->sids);
504 reset_cm_connection_on_error(domain, NULL, status);
505 if (!NT_STATUS_IS_OK(status)) {
506 return status;
509 return NT_STATUS_OK;
512 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
513 struct wbint_QueryGroupList *r)
515 TALLOC_CTX *frame = NULL;
516 struct winbindd_domain *domain = wb_child_domain();
517 uint32_t i;
518 uint32_t num_local_groups = 0;
519 struct wb_acct_info *local_groups = NULL;
520 uint32_t num_dom_groups = 0;
521 struct wb_acct_info *dom_groups = NULL;
522 uint32_t ti = 0;
523 uint64_t num_total = 0;
524 struct wbint_Principal *result;
525 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
526 bool include_local_groups = false;
528 if (domain == NULL) {
529 return NT_STATUS_REQUEST_NOT_ACCEPTED;
532 frame = talloc_stackframe();
534 switch (lp_server_role()) {
535 case ROLE_ACTIVE_DIRECTORY_DC:
536 if (domain->internal) {
538 * we want to include local groups
539 * for BUILTIN and WORKGROUP
541 include_local_groups = true;
543 break;
544 case ROLE_DOMAIN_MEMBER:
546 * This is needed for GETGRENT to show also e.g. BUILTIN/users.
547 * Otherwise the test_membership_user (smbtorture
548 * local.nss.membership) would fail (getgrouplist() would
549 * reports BUILTIN/users).
551 if (domain->internal) {
553 * we want to include local groups
554 * for BUILTIN and LOCALSAM
556 include_local_groups = true;
558 break;
559 default:
561 * We might include local groups in more
562 * setups later, but that requires more work
563 * elsewhere.
565 break;
568 if (include_local_groups) {
569 status = wb_cache_enum_local_groups(domain, frame,
570 &num_local_groups,
571 &local_groups);
572 reset_cm_connection_on_error(domain, NULL, status);
573 if (!NT_STATUS_IS_OK(status)) {
574 goto out;
578 status = wb_cache_enum_dom_groups(domain, frame,
579 &num_dom_groups,
580 &dom_groups);
581 reset_cm_connection_on_error(domain, NULL, status);
582 if (!NT_STATUS_IS_OK(status)) {
583 goto out;
586 num_total = num_local_groups + num_dom_groups;
587 if (num_total > UINT32_MAX) {
588 status = NT_STATUS_INTERNAL_ERROR;
589 goto out;
592 result = talloc_array(frame, struct wbint_Principal, num_total);
593 if (result == NULL) {
594 status = NT_STATUS_NO_MEMORY;
595 goto out;
598 for (i = 0; i < num_local_groups; i++) {
599 struct wb_acct_info *lg = &local_groups[i];
600 struct wbint_Principal *rg = &result[ti++];
602 sid_compose(&rg->sid, &domain->sid, lg->rid);
603 rg->type = SID_NAME_ALIAS;
604 rg->name = talloc_strdup(result, lg->acct_name);
605 if (rg->name == NULL) {
606 status = NT_STATUS_NO_MEMORY;
607 goto out;
610 num_local_groups = 0;
612 for (i = 0; i < num_dom_groups; i++) {
613 struct wb_acct_info *dg = &dom_groups[i];
614 struct wbint_Principal *rg = &result[ti++];
616 sid_compose(&rg->sid, &domain->sid, dg->rid);
617 rg->type = SID_NAME_DOM_GRP;
618 rg->name = talloc_strdup(result, dg->acct_name);
619 if (rg->name == NULL) {
620 status = NT_STATUS_NO_MEMORY;
621 goto out;
624 num_dom_groups = 0;
626 r->out.groups->num_principals = ti;
627 r->out.groups->principals = talloc_move(r->out.groups, &result);
629 status = NT_STATUS_OK;
630 out:
631 TALLOC_FREE(frame);
632 return status;
635 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
636 struct wbint_QueryUserRidList *r)
638 struct winbindd_domain *domain = wb_child_domain();
639 NTSTATUS status;
641 if (domain == NULL) {
642 return NT_STATUS_REQUEST_NOT_ACCEPTED;
646 * Right now this is overkill. We should add a backend call
647 * just querying the rids.
650 status = wb_cache_query_user_list(domain, p->mem_ctx,
651 &r->out.rids->rids);
652 reset_cm_connection_on_error(domain, NULL, status);
654 if (!NT_STATUS_IS_OK(status)) {
655 return status;
658 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
660 return NT_STATUS_OK;
663 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
665 struct winbindd_domain *domain = wb_child_domain();
666 struct rpc_pipe_client *netlogon_pipe;
667 struct netr_DsRGetDCNameInfo *dc_info;
668 NTSTATUS status;
669 WERROR werr;
670 unsigned int orig_timeout;
671 struct dcerpc_binding_handle *b;
672 bool retry = false;
673 bool try_dsrgetdcname = false;
675 if (domain == NULL) {
676 return dsgetdcname(p->mem_ctx, global_messaging_context(),
677 r->in.domain_name, r->in.domain_guid,
678 r->in.site_name ? r->in.site_name : "",
679 r->in.flags,
680 r->out.dc_info);
683 if (domain->active_directory) {
684 try_dsrgetdcname = true;
687 reconnect:
688 status = cm_connect_netlogon(domain, &netlogon_pipe);
690 reset_cm_connection_on_error(domain, NULL, status);
691 if (!NT_STATUS_IS_OK(status)) {
692 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
693 return status;
696 b = netlogon_pipe->binding_handle;
698 /* This call can take a long time - allow the server to time out.
699 35 seconds should do it. */
701 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
703 if (try_dsrgetdcname) {
704 status = dcerpc_netr_DsRGetDCName(b,
705 p->mem_ctx, domain->dcname,
706 r->in.domain_name, NULL, r->in.domain_guid,
707 r->in.flags, r->out.dc_info, &werr);
708 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
709 goto done;
711 if (!retry &&
712 reset_cm_connection_on_error(domain, NULL, status))
714 retry = true;
715 goto reconnect;
717 try_dsrgetdcname = false;
718 retry = false;
722 * Fallback to less capable methods
725 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
726 if (dc_info == NULL) {
727 status = NT_STATUS_NO_MEMORY;
728 goto done;
731 if (r->in.flags & DS_PDC_REQUIRED) {
732 status = dcerpc_netr_GetDcName(b,
733 p->mem_ctx, domain->dcname,
734 r->in.domain_name, &dc_info->dc_unc, &werr);
735 } else {
736 status = dcerpc_netr_GetAnyDCName(b,
737 p->mem_ctx, domain->dcname,
738 r->in.domain_name, &dc_info->dc_unc, &werr);
741 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
742 retry = true;
743 goto reconnect;
745 if (!NT_STATUS_IS_OK(status)) {
746 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
747 nt_errstr(status)));
748 goto done;
750 if (!W_ERROR_IS_OK(werr)) {
751 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
752 win_errstr(werr)));
753 status = werror_to_ntstatus(werr);
754 goto done;
757 *r->out.dc_info = dc_info;
758 status = NT_STATUS_OK;
760 done:
761 /* And restore our original timeout. */
762 rpccli_set_timeout(netlogon_pipe, orig_timeout);
764 return status;
767 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
769 struct winbindd_domain *domain = wb_child_domain();
770 char *domain_name;
771 char **names;
772 enum lsa_SidType *types;
773 struct wbint_Principal *result;
774 NTSTATUS status;
775 uint32_t i;
777 if (domain == NULL) {
778 return NT_STATUS_REQUEST_NOT_ACCEPTED;
781 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
782 r->in.rids->rids, r->in.rids->num_rids,
783 &domain_name, &names, &types);
784 reset_cm_connection_on_error(domain, NULL, status);
785 if (!NT_STATUS_IS_OK(status) &&
786 !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
787 return status;
790 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
792 result = talloc_array(p->mem_ctx, struct wbint_Principal,
793 r->in.rids->num_rids);
794 if (result == NULL) {
795 return NT_STATUS_NO_MEMORY;
798 for (i=0; i<r->in.rids->num_rids; i++) {
799 sid_compose(&result[i].sid, r->in.domain_sid,
800 r->in.rids->rids[i]);
801 result[i].type = types[i];
802 result[i].name = talloc_move(result, &names[i]);
804 TALLOC_FREE(types);
805 TALLOC_FREE(names);
807 r->out.names->num_principals = r->in.rids->num_rids;
808 r->out.names->principals = result;
809 return NT_STATUS_OK;
812 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
813 struct wbint_CheckMachineAccount *r)
815 struct winbindd_domain *domain;
816 int num_retries = 0;
817 NTSTATUS status;
819 domain = wb_child_domain();
820 if (domain == NULL) {
821 return NT_STATUS_REQUEST_NOT_ACCEPTED;
824 again:
825 invalidate_cm_connection(domain);
826 domain->conn.netlogon_force_reauth = true;
829 struct rpc_pipe_client *netlogon_pipe = NULL;
830 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
831 status = cm_connect_netlogon_secure(domain,
832 &netlogon_pipe,
833 &netlogon_creds_ctx);
836 /* There is a race condition between fetching the trust account
837 password and the periodic machine password change. So it's
838 possible that the trust account password has been changed on us.
839 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
841 #define MAX_RETRIES 3
843 if ((num_retries < MAX_RETRIES)
844 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
845 num_retries++;
846 goto again;
849 if (!NT_STATUS_IS_OK(status)) {
850 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
851 goto done;
854 /* Pass back result code - zero for success, other values for
855 specific failures. */
857 DEBUG(3,("domain %s secret is %s\n", domain->name,
858 NT_STATUS_IS_OK(status) ? "good" : "bad"));
860 done:
861 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
862 ("Checking the trust account password for domain %s returned %s\n",
863 domain->name, nt_errstr(status)));
865 return status;
868 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
869 struct wbint_ChangeMachineAccount *r)
871 struct messaging_context *msg_ctx = global_messaging_context();
872 struct winbindd_domain *domain;
873 NTSTATUS status;
874 struct rpc_pipe_client *netlogon_pipe = NULL;
875 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
877 domain = wb_child_domain();
878 if (domain == NULL) {
879 return NT_STATUS_REQUEST_NOT_ACCEPTED;
882 if (r->in.dcname != NULL && r->in.dcname[0] != '\0') {
883 invalidate_cm_connection(domain);
884 TALLOC_FREE(domain->dcname);
886 domain->dcname = talloc_strdup(domain, r->in.dcname);
887 if (domain->dcname == NULL) {
888 status = NT_STATUS_NO_MEMORY;
889 goto done;
891 domain->force_dc = true;
893 DBG_NOTICE("attempt connection to change trust account "
894 "password for %s at %s\n",
895 domain->name, domain->dcname);
898 status = cm_connect_netlogon_secure(domain,
899 &netlogon_pipe,
900 &netlogon_creds_ctx);
901 if (!NT_STATUS_IS_OK(status)) {
902 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
903 goto done;
906 status = trust_pw_change(netlogon_creds_ctx,
907 msg_ctx,
908 netlogon_pipe->binding_handle,
909 domain->name,
910 domain->dcname,
911 true); /* force */
913 /* Pass back result code - zero for success, other values for
914 specific failures. */
916 DEBUG(3,("domain %s secret %s\n", domain->name,
917 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
919 done:
920 DEBUG(NT_STATUS_IS_OK(status) ? 5 :
921 domain->force_dc ? 0 : 2,
922 ("Changing the trust account password for domain %s at %s "
923 "(forced: %s) returned %s\n",
924 domain->name, domain->dcname, domain->force_dc ? "yes" : "no",
925 nt_errstr(status)));
926 domain->force_dc = false;
928 return status;
931 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
933 NTSTATUS status;
934 struct winbindd_domain *domain;
935 struct rpc_pipe_client *netlogon_pipe;
936 union netr_CONTROL_QUERY_INFORMATION info;
937 WERROR werr;
938 fstring logon_server;
939 struct dcerpc_binding_handle *b;
940 bool retry = false;
942 domain = wb_child_domain();
943 if (domain == NULL) {
944 return NT_STATUS_REQUEST_NOT_ACCEPTED;
947 reconnect:
948 status = cm_connect_netlogon(domain, &netlogon_pipe);
949 reset_cm_connection_on_error(domain, NULL, status);
950 if (!NT_STATUS_IS_OK(status)) {
951 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
952 nt_errstr(status)));
953 return status;
956 b = netlogon_pipe->binding_handle;
958 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
959 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
960 if (*r->out.dcname == NULL) {
961 DEBUG(2, ("Could not allocate memory\n"));
962 return NT_STATUS_NO_MEMORY;
966 * This provokes a WERR_NOT_SUPPORTED error message. This is
967 * documented in the wspp docs. I could not get a successful
968 * call to work, but the main point here is testing that the
969 * netlogon pipe works.
971 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
972 logon_server, NETLOGON_CONTROL_QUERY,
973 2, &info, &werr);
975 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
976 retry = true;
977 goto reconnect;
980 if (!NT_STATUS_IS_OK(status)) {
981 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
982 nt_errstr(status)));
983 return status;
986 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
987 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
988 "WERR_NOT_SUPPORTED\n",
989 win_errstr(werr)));
990 return werror_to_ntstatus(werr);
993 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
994 return NT_STATUS_OK;
997 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
998 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
1000 struct winbindd_domain *domain;
1001 NTSTATUS status;
1002 struct rpc_pipe_client *netlogon_pipe = NULL;
1003 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1004 struct dcerpc_binding_handle *b = NULL;
1005 bool retry = false;
1007 domain = wb_child_domain();
1008 if (domain == NULL) {
1009 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1012 reconnect:
1013 status = cm_connect_netlogon_secure(domain,
1014 &netlogon_pipe,
1015 &netlogon_creds_ctx);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1018 goto done;
1021 b = netlogon_pipe->binding_handle;
1023 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
1024 netlogon_pipe->binding_handle,
1025 r->in.site_name,
1026 r->in.dns_ttl,
1027 r->in.dns_names);
1029 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1030 retry = true;
1031 goto reconnect;
1034 /* Pass back result code - zero for success, other values for
1035 specific failures. */
1037 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
1038 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
1040 done:
1041 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
1042 ("Update of DNS records via RW DC %s returned %s\n",
1043 domain->name, nt_errstr(status)));
1045 return status;
1048 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
1049 struct winbind_SamLogon *r)
1051 struct dcesrv_call_state *dce_call = p->dce_call;
1052 struct dcesrv_connection *dcesrv_conn = dce_call->conn;
1053 const struct tsocket_address *local_address =
1054 dcesrv_connection_get_local_address(dcesrv_conn);
1055 const struct tsocket_address *remote_address =
1056 dcesrv_connection_get_remote_address(dcesrv_conn);
1057 struct winbindd_domain *domain;
1058 NTSTATUS status;
1059 struct netr_IdentityInfo *identity_info = NULL;
1060 DATA_BLOB lm_response, nt_response;
1061 DATA_BLOB challenge = data_blob_null;
1062 uint32_t flags = 0;
1063 uint16_t validation_level;
1064 union netr_Validation *validation = NULL;
1065 bool interactive = false;
1068 * Make sure we start with authoritative=true,
1069 * it will only set to false if we don't know the
1070 * domain.
1072 r->out.authoritative = true;
1074 domain = wb_child_domain();
1075 if (domain == NULL) {
1076 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1079 switch (r->in.validation_level) {
1080 case 3:
1081 case 6:
1082 break;
1083 default:
1084 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1087 switch (r->in.logon_level) {
1088 case NetlogonInteractiveInformation:
1089 case NetlogonServiceInformation:
1090 case NetlogonInteractiveTransitiveInformation:
1091 case NetlogonServiceTransitiveInformation:
1092 if (r->in.logon.password == NULL) {
1093 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1096 interactive = true;
1097 identity_info = &r->in.logon.password->identity_info;
1099 challenge = data_blob_null;
1100 lm_response = data_blob_talloc(p->mem_ctx,
1101 r->in.logon.password->lmpassword.hash,
1102 sizeof(r->in.logon.password->lmpassword.hash));
1103 nt_response = data_blob_talloc(p->mem_ctx,
1104 r->in.logon.password->ntpassword.hash,
1105 sizeof(r->in.logon.password->ntpassword.hash));
1106 break;
1108 case NetlogonNetworkInformation:
1109 case NetlogonNetworkTransitiveInformation:
1110 if (r->in.logon.network == NULL) {
1111 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1114 interactive = false;
1115 identity_info = &r->in.logon.network->identity_info;
1117 challenge = data_blob_talloc(p->mem_ctx,
1118 r->in.logon.network->challenge,
1120 lm_response = data_blob_talloc(p->mem_ctx,
1121 r->in.logon.network->lm.data,
1122 r->in.logon.network->lm.length);
1123 nt_response = data_blob_talloc(p->mem_ctx,
1124 r->in.logon.network->nt.data,
1125 r->in.logon.network->nt.length);
1126 break;
1128 case NetlogonGenericInformation:
1129 if (r->in.logon.generic == NULL) {
1130 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1133 identity_info = &r->in.logon.generic->identity_info;
1135 * Not implemented here...
1137 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1139 default:
1140 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1143 status = winbind_dual_SamLogon(domain, p->mem_ctx,
1144 interactive,
1145 identity_info->parameter_control,
1146 identity_info->account_name.string,
1147 identity_info->domain_name.string,
1148 identity_info->workstation.string,
1149 identity_info->logon_id,
1150 "SamLogon",
1152 challenge,
1153 lm_response, nt_response,
1154 remote_address,
1155 local_address,
1156 &r->out.authoritative,
1157 true, /* skip_sam */
1158 &flags,
1159 &validation_level,
1160 &validation);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 return status;
1164 switch (r->in.validation_level) {
1165 case 3:
1166 status = map_validation_to_info3(p->mem_ctx,
1167 validation_level,
1168 validation,
1169 &r->out.validation.sam3);
1170 TALLOC_FREE(validation);
1171 if (!NT_STATUS_IS_OK(status)) {
1172 return status;
1174 return NT_STATUS_OK;
1175 case 6:
1176 status = map_validation_to_info6(p->mem_ctx,
1177 validation_level,
1178 validation,
1179 &r->out.validation.sam6);
1180 TALLOC_FREE(validation);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 return status;
1184 return NT_STATUS_OK;
1187 smb_panic(__location__);
1188 return NT_STATUS_INTERNAL_ERROR;
1191 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1192 struct winbindd_domain *domain,
1193 struct winbind_LogonControl *r)
1195 NTSTATUS status;
1196 struct rpc_pipe_client *netlogon_pipe = NULL;
1197 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1198 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1199 WERROR check_result = WERR_INTERNAL_ERROR;
1201 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1202 if (info2 == NULL) {
1203 return WERR_NOT_ENOUGH_MEMORY;
1206 if (domain->internal) {
1207 check_result = WERR_OK;
1208 goto check_return;
1212 * For now we just force a reconnect
1214 * TODO: take care of the optional '\dcname'
1216 invalidate_cm_connection(domain);
1217 domain->conn.netlogon_force_reauth = true;
1218 status = cm_connect_netlogon_secure(domain,
1219 &netlogon_pipe,
1220 &netlogon_creds_ctx);
1221 reset_cm_connection_on_error(domain, NULL, status);
1222 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1223 status = NT_STATUS_NO_LOGON_SERVERS;
1225 if (!NT_STATUS_IS_OK(status)) {
1226 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1227 __func__, domain->name, domain->alt_name,
1228 nt_errstr(status)));
1230 * Here we return a top level error!
1231 * This is different than TC_QUERY or TC_VERIFY.
1233 return ntstatus_to_werror(status);
1235 check_result = WERR_OK;
1237 check_return:
1238 info2->pdc_connection_status = WERR_OK;
1239 if (domain->dcname != NULL) {
1240 info2->flags |= NETLOGON_HAS_IP;
1241 info2->flags |= NETLOGON_HAS_TIMESERV;
1242 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1243 domain->dcname);
1244 if (info2->trusted_dc_name == NULL) {
1245 return WERR_NOT_ENOUGH_MEMORY;
1247 } else {
1248 info2->trusted_dc_name = talloc_strdup(info2, "");
1249 if (info2->trusted_dc_name == NULL) {
1250 return WERR_NOT_ENOUGH_MEMORY;
1253 info2->tc_connection_status = check_result;
1255 if (!W_ERROR_IS_OK(info2->pdc_connection_status) ||
1256 !W_ERROR_IS_OK(info2->tc_connection_status))
1258 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1259 "pdc_connection[%s] tc_connection[%s]\n",
1260 __func__, domain->name, domain->alt_name,
1261 domain->dcname,
1262 win_errstr(info2->pdc_connection_status),
1263 win_errstr(info2->tc_connection_status)));
1266 r->out.query->info2 = info2;
1268 DEBUG(5, ("%s: succeeded.\n", __func__));
1269 return WERR_OK;
1272 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1273 struct winbindd_domain *domain,
1274 struct winbind_LogonControl *r)
1276 NTSTATUS status;
1277 struct rpc_pipe_client *netlogon_pipe = NULL;
1278 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1279 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1280 WERROR check_result = WERR_INTERNAL_ERROR;
1282 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1283 if (info2 == NULL) {
1284 return WERR_NOT_ENOUGH_MEMORY;
1287 if (domain->internal) {
1288 check_result = WERR_OK;
1289 goto check_return;
1292 status = cm_connect_netlogon_secure(domain,
1293 &netlogon_pipe,
1294 &netlogon_creds_ctx);
1295 reset_cm_connection_on_error(domain, NULL, status);
1296 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1297 status = NT_STATUS_NO_LOGON_SERVERS;
1299 if (!NT_STATUS_IS_OK(status)) {
1300 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1301 nt_errstr(status)));
1302 check_result = ntstatus_to_werror(status);
1303 goto check_return;
1305 check_result = WERR_OK;
1307 check_return:
1308 info2->pdc_connection_status = WERR_OK;
1309 if (domain->dcname != NULL) {
1310 info2->flags |= NETLOGON_HAS_IP;
1311 info2->flags |= NETLOGON_HAS_TIMESERV;
1312 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1313 domain->dcname);
1314 if (info2->trusted_dc_name == NULL) {
1315 return WERR_NOT_ENOUGH_MEMORY;
1317 } else {
1318 info2->trusted_dc_name = talloc_strdup(info2, "");
1319 if (info2->trusted_dc_name == NULL) {
1320 return WERR_NOT_ENOUGH_MEMORY;
1323 info2->tc_connection_status = check_result;
1325 if (!W_ERROR_IS_OK(info2->pdc_connection_status) ||
1326 !W_ERROR_IS_OK(info2->tc_connection_status))
1328 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1329 "pdc_connection[%s] tc_connection[%s]\n",
1330 __func__, domain->name, domain->alt_name,
1331 domain->dcname,
1332 win_errstr(info2->pdc_connection_status),
1333 win_errstr(info2->tc_connection_status)));
1336 r->out.query->info2 = info2;
1338 DEBUG(5, ("%s: succeeded.\n", __func__));
1339 return WERR_OK;
1342 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1343 struct winbindd_domain *domain,
1344 struct winbind_LogonControl *r)
1346 TALLOC_CTX *frame = talloc_stackframe();
1347 NTSTATUS status;
1348 NTSTATUS result;
1349 struct lsa_String trusted_domain_name = {};
1350 struct lsa_StringLarge trusted_domain_name_l = {};
1351 struct rpc_pipe_client *local_lsa_pipe = NULL;
1352 struct policy_handle local_lsa_policy = {};
1353 struct dcerpc_binding_handle *local_lsa = NULL;
1354 struct rpc_pipe_client *netlogon_pipe = NULL;
1355 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1356 struct cli_credentials *creds = NULL;
1357 struct samr_Password *cur_nt_hash = NULL;
1358 uint32_t trust_attributes = 0;
1359 struct samr_Password new_owf_password = {};
1360 bool cmp_new = false;
1361 struct samr_Password old_owf_password = {};
1362 bool cmp_old = false;
1363 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1364 bool fetch_fti = false;
1365 struct lsa_ForestTrustInformation *new_fti = NULL;
1366 struct netr_TrustInfo *trust_info = NULL;
1367 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1368 struct dcerpc_binding_handle *b = NULL;
1369 WERROR check_result = WERR_INTERNAL_ERROR;
1370 WERROR verify_result = WERR_INTERNAL_ERROR;
1371 bool retry = false;
1373 trusted_domain_name.string = domain->name;
1374 trusted_domain_name_l.string = domain->name;
1376 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1377 if (info2 == NULL) {
1378 TALLOC_FREE(frame);
1379 return WERR_NOT_ENOUGH_MEMORY;
1382 if (domain->internal) {
1383 check_result = WERR_OK;
1384 goto check_return;
1387 if (!domain->primary) {
1388 union lsa_TrustedDomainInfo *tdi = NULL;
1390 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1391 &local_lsa_policy);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1394 __location__, __func__, nt_errstr(status)));
1395 TALLOC_FREE(frame);
1396 return WERR_INTERNAL_ERROR;
1398 local_lsa = local_lsa_pipe->binding_handle;
1400 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1401 &local_lsa_policy,
1402 &trusted_domain_name,
1403 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1404 &tdi, &result);
1405 if (!NT_STATUS_IS_OK(status)) {
1406 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1407 __location__, __func__, domain->name, nt_errstr(status)));
1408 TALLOC_FREE(frame);
1409 return WERR_INTERNAL_ERROR;
1411 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1412 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1413 __location__, __func__, domain->name));
1414 TALLOC_FREE(frame);
1415 return WERR_NO_SUCH_DOMAIN;
1417 if (!NT_STATUS_IS_OK(result)) {
1418 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1419 __location__, __func__, domain->name, nt_errstr(result)));
1420 TALLOC_FREE(frame);
1421 return WERR_INTERNAL_ERROR;
1423 if (tdi == NULL) {
1424 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1425 "returned no trusted domain information\n",
1426 __location__, __func__));
1427 TALLOC_FREE(frame);
1428 return WERR_INTERNAL_ERROR;
1431 local_tdo = &tdi->info_ex;
1432 trust_attributes = local_tdo->trust_attributes;
1435 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1436 struct lsa_ForestTrustInformation *old_fti = NULL;
1438 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1439 &local_lsa_policy,
1440 &trusted_domain_name,
1441 LSA_FOREST_TRUST_DOMAIN_INFO,
1442 &old_fti, &result);
1443 if (!NT_STATUS_IS_OK(status)) {
1444 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1445 __location__, __func__, domain->name, nt_errstr(status)));
1446 TALLOC_FREE(frame);
1447 return WERR_INTERNAL_ERROR;
1449 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1450 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1451 __func__, domain->name));
1452 old_fti = NULL;
1453 fetch_fti = true;
1454 result = NT_STATUS_OK;
1456 if (!NT_STATUS_IS_OK(result)) {
1457 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1458 __location__, __func__, domain->name, nt_errstr(result)));
1459 TALLOC_FREE(frame);
1460 return WERR_INTERNAL_ERROR;
1463 TALLOC_FREE(old_fti);
1466 reconnect:
1467 status = cm_connect_netlogon_secure(domain,
1468 &netlogon_pipe,
1469 &netlogon_creds_ctx);
1470 reset_cm_connection_on_error(domain, NULL, status);
1471 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1472 status = NT_STATUS_NO_LOGON_SERVERS;
1474 if (!NT_STATUS_IS_OK(status)) {
1475 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1476 nt_errstr(status)));
1477 check_result = ntstatus_to_werror(status);
1478 goto check_return;
1480 check_result = WERR_OK;
1481 b = netlogon_pipe->binding_handle;
1483 status = winbindd_get_trust_credentials(domain,
1484 frame,
1485 true, /* netlogon */
1486 false, /* ipc_fallback */
1487 &creds);
1488 if (NT_STATUS_IS_OK(status)) {
1489 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1490 TALLOC_FREE(creds);
1492 if (cur_nt_hash == NULL) {
1493 verify_result = WERR_NO_TRUST_LSA_SECRET;
1494 goto verify_return;
1497 if (fetch_fti) {
1498 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1499 b, frame,
1500 &new_fti);
1501 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1502 status = NT_STATUS_NOT_SUPPORTED;
1504 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1505 new_fti = NULL;
1506 status = NT_STATUS_OK;
1508 if (!NT_STATUS_IS_OK(status)) {
1509 if (!retry &&
1510 reset_cm_connection_on_error(domain, b, status))
1512 retry = true;
1513 goto reconnect;
1515 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1516 "failed: %s\n",
1517 domain->name, nt_errstr(status)));
1518 check_result = ntstatus_to_werror(status);
1519 goto check_return;
1523 if (new_fti != NULL) {
1524 struct lsa_ForestTrustInformation old_fti = {};
1525 struct lsa_ForestTrustInformation *merged_fti = NULL;
1526 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1528 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1529 &old_fti, new_fti,
1530 &merged_fti);
1531 if (!NT_STATUS_IS_OK(status)) {
1532 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1533 __location__, __func__,
1534 domain->name, nt_errstr(status)));
1535 TALLOC_FREE(frame);
1536 return ntstatus_to_werror(status);
1539 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1540 &local_lsa_policy,
1541 &trusted_domain_name_l,
1542 LSA_FOREST_TRUST_DOMAIN_INFO,
1543 merged_fti,
1544 0, /* check_only=0 => store it! */
1545 &collision_info,
1546 &result);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1549 __location__, __func__, domain->name, nt_errstr(status)));
1550 TALLOC_FREE(frame);
1551 return WERR_INTERNAL_ERROR;
1553 if (!NT_STATUS_IS_OK(result)) {
1554 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1555 __location__, __func__, domain->name, nt_errstr(result)));
1556 TALLOC_FREE(frame);
1557 return ntstatus_to_werror(result);
1561 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1562 b, frame,
1563 &new_owf_password,
1564 &old_owf_password,
1565 &trust_info);
1566 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1567 status = NT_STATUS_NOT_SUPPORTED;
1569 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1570 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1571 nt_errstr(status)));
1572 verify_result = WERR_OK;
1573 goto verify_return;
1575 if (!NT_STATUS_IS_OK(status)) {
1576 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1577 retry = true;
1578 goto reconnect;
1580 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1581 nt_errstr(status)));
1583 if (!dcerpc_binding_handle_is_connected(b)) {
1584 check_result = ntstatus_to_werror(status);
1585 goto check_return;
1586 } else {
1587 verify_result = ntstatus_to_werror(status);
1588 goto verify_return;
1592 if (trust_info != NULL && trust_info->count >= 1) {
1593 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1595 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1596 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1597 goto verify_return;
1601 cmp_new = mem_equal_const_time(new_owf_password.hash,
1602 cur_nt_hash->hash,
1603 sizeof(cur_nt_hash->hash));
1604 cmp_old = mem_equal_const_time(old_owf_password.hash,
1605 cur_nt_hash->hash,
1606 sizeof(cur_nt_hash->hash));
1607 if (!cmp_new && !cmp_old) {
1608 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1609 "any password known to dcname[%s]\n",
1610 __func__, domain->name, domain->alt_name,
1611 domain->dcname));
1612 verify_result = WERR_WRONG_PASSWORD;
1613 goto verify_return;
1616 if (!cmp_new) {
1617 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1618 "against the old password known to dcname[%s]\n",
1619 __func__, domain->name, domain->alt_name,
1620 domain->dcname));
1623 verify_result = WERR_OK;
1624 goto verify_return;
1626 check_return:
1627 verify_result = check_result;
1628 verify_return:
1629 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1630 info2->pdc_connection_status = verify_result;
1631 if (domain->dcname != NULL) {
1632 info2->flags |= NETLOGON_HAS_IP;
1633 info2->flags |= NETLOGON_HAS_TIMESERV;
1634 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1635 domain->dcname);
1636 if (info2->trusted_dc_name == NULL) {
1637 TALLOC_FREE(frame);
1638 return WERR_NOT_ENOUGH_MEMORY;
1640 } else {
1641 info2->trusted_dc_name = talloc_strdup(info2, "");
1642 if (info2->trusted_dc_name == NULL) {
1643 TALLOC_FREE(frame);
1644 return WERR_NOT_ENOUGH_MEMORY;
1647 info2->tc_connection_status = check_result;
1649 if (!W_ERROR_IS_OK(info2->pdc_connection_status) ||
1650 !W_ERROR_IS_OK(info2->tc_connection_status))
1652 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1653 "pdc_connection[%s] tc_connection[%s]\n",
1654 __func__, domain->name, domain->alt_name,
1655 domain->dcname,
1656 win_errstr(info2->pdc_connection_status),
1657 win_errstr(info2->tc_connection_status)));
1660 r->out.query->info2 = info2;
1662 DEBUG(5, ("%s: succeeded.\n", __func__));
1663 TALLOC_FREE(frame);
1664 return WERR_OK;
1667 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1668 struct winbindd_domain *domain,
1669 struct winbind_LogonControl *r)
1671 struct messaging_context *msg_ctx = global_messaging_context();
1672 NTSTATUS status;
1673 struct rpc_pipe_client *netlogon_pipe = NULL;
1674 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1675 struct cli_credentials *creds = NULL;
1676 struct samr_Password *cur_nt_hash = NULL;
1677 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1678 struct dcerpc_binding_handle *b;
1679 WERROR change_result = WERR_OK;
1680 bool retry = false;
1682 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1683 if (info1 == NULL) {
1684 return WERR_NOT_ENOUGH_MEMORY;
1687 if (domain->internal) {
1688 return WERR_NOT_SUPPORTED;
1691 status = pdb_get_trust_credentials(domain->name,
1692 domain->alt_name,
1693 p->mem_ctx,
1694 &creds);
1695 if (NT_STATUS_IS_OK(status)) {
1696 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1697 TALLOC_FREE(creds);
1700 reconnect:
1701 status = cm_connect_netlogon_secure(domain,
1702 &netlogon_pipe,
1703 &netlogon_creds_ctx);
1704 reset_cm_connection_on_error(domain, NULL, status);
1705 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1706 status = NT_STATUS_NO_LOGON_SERVERS;
1708 if (!NT_STATUS_IS_OK(status)) {
1709 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1710 __func__, domain->name, domain->alt_name,
1711 nt_errstr(status)));
1713 * Here we return a top level error!
1714 * This is different than TC_QUERY or TC_VERIFY.
1716 return ntstatus_to_werror(status);
1718 b = netlogon_pipe->binding_handle;
1720 if (cur_nt_hash == NULL) {
1721 change_result = WERR_NO_TRUST_LSA_SECRET;
1722 goto change_return;
1724 TALLOC_FREE(cur_nt_hash);
1726 status = trust_pw_change(netlogon_creds_ctx,
1727 msg_ctx, b, domain->name,
1728 domain->dcname,
1729 true); /* force */
1730 if (!NT_STATUS_IS_OK(status)) {
1731 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1732 retry = true;
1733 goto reconnect;
1736 DEBUG(1, ("trust_pw_change(%s): %s\n",
1737 domain->name, nt_errstr(status)));
1739 change_result = ntstatus_to_werror(status);
1740 goto change_return;
1743 change_result = WERR_OK;
1745 change_return:
1746 info1->pdc_connection_status = change_result;
1748 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1749 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1750 "pdc_connection[%s]\n",
1751 __func__, domain->name, domain->alt_name,
1752 domain->dcname,
1753 win_errstr(info1->pdc_connection_status)));
1756 r->out.query->info1 = info1;
1758 DEBUG(5, ("%s: succeeded.\n", __func__));
1759 return WERR_OK;
1762 WERROR _winbind_LogonControl(struct pipes_struct *p,
1763 struct winbind_LogonControl *r)
1765 struct winbindd_domain *domain;
1767 domain = wb_child_domain();
1768 if (domain == NULL) {
1769 return WERR_NO_SUCH_DOMAIN;
1772 switch (r->in.function_code) {
1773 case NETLOGON_CONTROL_REDISCOVER:
1774 if (r->in.level != 2) {
1775 return WERR_INVALID_PARAMETER;
1777 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1778 case NETLOGON_CONTROL_TC_QUERY:
1779 if (r->in.level != 2) {
1780 return WERR_INVALID_PARAMETER;
1782 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1783 case NETLOGON_CONTROL_TC_VERIFY:
1784 if (r->in.level != 2) {
1785 return WERR_INVALID_PARAMETER;
1787 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1788 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1789 if (r->in.level != 1) {
1790 return WERR_INVALID_PARAMETER;
1792 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1793 default:
1794 break;
1797 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1798 __func__, r->in.function_code));
1799 return WERR_NOT_SUPPORTED;
1802 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1803 struct winbind_GetForestTrustInformation *r)
1805 TALLOC_CTX *frame = talloc_stackframe();
1806 NTSTATUS status, result;
1807 struct winbindd_domain *domain;
1808 struct rpc_pipe_client *netlogon_pipe = NULL;
1809 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1810 struct dcerpc_binding_handle *b;
1811 bool retry = false;
1812 struct lsa_String trusted_domain_name = {};
1813 struct lsa_StringLarge trusted_domain_name_l = {};
1814 union lsa_TrustedDomainInfo *tdi = NULL;
1815 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1816 struct lsa_ForestTrustInformation _old_fti = {};
1817 struct lsa_ForestTrustInformation *old_fti = NULL;
1818 struct lsa_ForestTrustInformation *new_fti = NULL;
1819 struct lsa_ForestTrustInformation *merged_fti = NULL;
1820 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1821 bool update_fti = false;
1822 struct rpc_pipe_client *local_lsa_pipe;
1823 struct policy_handle local_lsa_policy;
1824 struct dcerpc_binding_handle *local_lsa = NULL;
1826 domain = wb_child_domain();
1827 if (domain == NULL) {
1828 TALLOC_FREE(frame);
1829 return WERR_NO_SUCH_DOMAIN;
1833 * checking for domain->internal and domain->primary
1834 * makes sure we only do some work when running as DC.
1837 if (domain->internal) {
1838 TALLOC_FREE(frame);
1839 return WERR_NO_SUCH_DOMAIN;
1842 if (domain->primary) {
1843 TALLOC_FREE(frame);
1844 return WERR_NO_SUCH_DOMAIN;
1847 trusted_domain_name.string = domain->name;
1848 trusted_domain_name_l.string = domain->name;
1850 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1851 &local_lsa_policy);
1852 if (!NT_STATUS_IS_OK(status)) {
1853 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1854 __location__, __func__, nt_errstr(status)));
1855 TALLOC_FREE(frame);
1856 return WERR_INTERNAL_ERROR;
1858 local_lsa = local_lsa_pipe->binding_handle;
1860 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1861 &local_lsa_policy,
1862 &trusted_domain_name,
1863 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1864 &tdi, &result);
1865 if (!NT_STATUS_IS_OK(status)) {
1866 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1867 __location__, __func__, domain->name, nt_errstr(status)));
1868 TALLOC_FREE(frame);
1869 return WERR_INTERNAL_ERROR;
1871 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1872 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1873 __location__, __func__, domain->name));
1874 TALLOC_FREE(frame);
1875 return WERR_NO_SUCH_DOMAIN;
1877 if (!NT_STATUS_IS_OK(result)) {
1878 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1879 __location__, __func__, domain->name, nt_errstr(result)));
1880 TALLOC_FREE(frame);
1881 return WERR_INTERNAL_ERROR;
1883 if (tdi == NULL) {
1884 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1885 "returned no trusted domain information\n",
1886 __location__, __func__));
1887 TALLOC_FREE(frame);
1888 return WERR_INTERNAL_ERROR;
1891 tdo = &tdi->info_ex;
1893 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1894 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1895 __func__, tdo->netbios_name.string,
1896 tdo->domain_name.string,
1897 (unsigned)tdo->trust_attributes));
1898 TALLOC_FREE(frame);
1899 return WERR_NO_SUCH_DOMAIN;
1902 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1903 TALLOC_FREE(frame);
1904 return WERR_INVALID_FLAGS;
1907 reconnect:
1908 status = cm_connect_netlogon_secure(domain,
1909 &netlogon_pipe,
1910 &netlogon_creds_ctx);
1911 reset_cm_connection_on_error(domain, NULL, status);
1912 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1913 status = NT_STATUS_NO_LOGON_SERVERS;
1915 if (!NT_STATUS_IS_OK(status)) {
1916 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1917 nt_errstr(status)));
1918 TALLOC_FREE(frame);
1919 return ntstatus_to_werror(status);
1921 b = netlogon_pipe->binding_handle;
1923 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1924 b, p->mem_ctx,
1925 &new_fti);
1926 if (!NT_STATUS_IS_OK(status)) {
1927 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1928 retry = true;
1929 goto reconnect;
1931 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1932 domain->name, nt_errstr(status)));
1933 TALLOC_FREE(frame);
1934 return ntstatus_to_werror(status);
1937 *r->out.forest_trust_info = new_fti;
1939 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1940 update_fti = true;
1943 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1944 &local_lsa_policy,
1945 &trusted_domain_name,
1946 LSA_FOREST_TRUST_DOMAIN_INFO,
1947 &old_fti, &result);
1948 if (!NT_STATUS_IS_OK(status)) {
1949 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1950 __location__, __func__, domain->name, nt_errstr(status)));
1951 TALLOC_FREE(frame);
1952 return WERR_INTERNAL_ERROR;
1954 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1955 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1956 __func__, domain->name));
1957 update_fti = true;
1958 old_fti = &_old_fti;
1959 result = NT_STATUS_OK;
1961 if (!NT_STATUS_IS_OK(result)) {
1962 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1963 __location__, __func__, domain->name, nt_errstr(result)));
1964 TALLOC_FREE(frame);
1965 return WERR_INTERNAL_ERROR;
1968 if (old_fti == NULL) {
1969 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1970 "returned success without returning forest trust information\n",
1971 __location__, __func__));
1972 TALLOC_FREE(frame);
1973 return WERR_INTERNAL_ERROR;
1976 if (!update_fti) {
1977 goto done;
1980 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1981 &merged_fti);
1982 if (!NT_STATUS_IS_OK(status)) {
1983 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1984 __location__, __func__, domain->name, nt_errstr(status)));
1985 TALLOC_FREE(frame);
1986 return ntstatus_to_werror(status);
1989 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1990 &local_lsa_policy,
1991 &trusted_domain_name_l,
1992 LSA_FOREST_TRUST_DOMAIN_INFO,
1993 merged_fti,
1994 0, /* check_only=0 => store it! */
1995 &collision_info,
1996 &result);
1997 if (!NT_STATUS_IS_OK(status)) {
1998 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1999 __location__, __func__, domain->name, nt_errstr(status)));
2000 TALLOC_FREE(frame);
2001 return WERR_INTERNAL_ERROR;
2003 if (!NT_STATUS_IS_OK(result)) {
2004 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
2005 __location__, __func__, domain->name, nt_errstr(result)));
2006 TALLOC_FREE(frame);
2007 return ntstatus_to_werror(result);
2010 done:
2011 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
2012 TALLOC_FREE(frame);
2013 return WERR_OK;
2016 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
2018 struct winbindd_domain *domain;
2019 NTSTATUS status;
2020 struct rpc_pipe_client *netlogon_pipe;
2021 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
2022 struct dcerpc_binding_handle *b = NULL;
2023 bool retry = false;
2025 DEBUG(5, ("_winbind_SendToSam received\n"));
2026 domain = wb_child_domain();
2027 if (domain == NULL) {
2028 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2031 reconnect:
2032 status = cm_connect_netlogon_secure(domain,
2033 &netlogon_pipe,
2034 &netlogon_creds_ctx);
2035 reset_cm_connection_on_error(domain, NULL, status);
2036 if (!NT_STATUS_IS_OK(status)) {
2037 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
2038 return status;
2041 b = netlogon_pipe->binding_handle;
2043 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
2045 &r->in.message);
2046 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
2047 retry = true;
2048 goto reconnect;
2051 return status;
2054 NTSTATUS _wbint_ListTrustedDomains(struct pipes_struct *p,
2055 struct wbint_ListTrustedDomains *r)
2057 struct winbindd_domain *domain = wb_child_domain();
2058 uint32_t i;
2059 NTSTATUS result;
2060 struct netr_DomainTrustList trusts;
2061 uint32_t count = 0;
2062 struct netr_DomainTrust *array = NULL;
2063 pid_t client_pid;
2065 if (domain == NULL) {
2066 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2069 /* Cut client_pid to 32bit */
2070 client_pid = r->in.client_pid;
2071 if ((uint64_t)client_pid != r->in.client_pid) {
2072 DBG_DEBUG("pid out of range\n");
2073 return NT_STATUS_INVALID_PARAMETER;
2076 DBG_NOTICE("[%s %"PRIu32"]: list trusted domains\n",
2077 r->in.client_name, client_pid);
2079 result = wb_cache_trusted_domains(domain, p->mem_ctx, &trusts);
2080 if (!NT_STATUS_IS_OK(result)) {
2081 DBG_NOTICE("wb_cache_trusted_domains returned %s\n",
2082 nt_errstr(result));
2083 return result;
2086 for (i=0; i<trusts.count; i++) {
2087 struct netr_DomainTrust *st = &trusts.array[i];
2088 struct netr_DomainTrust *dt = NULL;
2090 if (st->sid == NULL) {
2091 continue;
2093 if (dom_sid_equal(st->sid, &global_sid_NULL)) {
2094 continue;
2097 array = talloc_realloc(r->out.domains, array,
2098 struct netr_DomainTrust,
2099 count + 1);
2100 if (array == NULL) {
2101 return NT_STATUS_NO_MEMORY;
2104 dt = &array[count];
2106 *dt = (struct netr_DomainTrust) {
2107 .trust_flags = st->trust_flags,
2108 .trust_type = st->trust_type,
2109 .trust_attributes = st->trust_attributes,
2110 .netbios_name = talloc_move(array, &st->netbios_name),
2111 .dns_name = talloc_move(array, &st->dns_name),
2114 dt->sid = dom_sid_dup(array, st->sid);
2115 if (dt->sid == NULL) {
2116 return NT_STATUS_NO_MEMORY;
2119 count++;
2122 r->out.domains->array = array;
2123 r->out.domains->count = count;
2124 return NT_STATUS_OK;
2127 #include "librpc/gen_ndr/ndr_winbind_scompat.c"