sharesec: Check if share exists in configuration
[samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob2572588f6d1a1590bb6f13c1522884b378e099e7
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->active_directory) {
95 *r->out.flags |= WB_DOMINFO_DOMAIN_AD;
96 *r->out.flags |= WB_DOMINFO_DOMAIN_NATIVE;
98 if (domain->primary) {
99 *r->out.flags |= WB_DOMINFO_DOMAIN_PRIMARY;
102 return NT_STATUS_OK;
105 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
106 struct dcerpc_binding_handle *b,
107 NTSTATUS status)
109 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
110 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
111 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
112 invalidate_cm_connection(domain);
113 domain->conn.netlogon_force_reauth = true;
114 return true;
117 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
118 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
120 invalidate_cm_connection(domain);
121 /* We invalidated the connection. */
122 return true;
125 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
126 invalidate_cm_connection(domain);
127 return true;
130 return false;
133 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
135 struct winbindd_domain *domain = wb_child_domain();
136 char *dom_name;
137 char *name;
138 enum lsa_SidType type;
139 NTSTATUS status;
141 if (domain == NULL) {
142 return NT_STATUS_REQUEST_NOT_ACCEPTED;
145 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
146 &dom_name, &name, &type);
147 reset_cm_connection_on_error(domain, NULL, status);
148 if (!NT_STATUS_IS_OK(status)) {
149 return status;
152 *r->out.domain = dom_name;
153 *r->out.name = name;
154 *r->out.type = type;
155 return NT_STATUS_OK;
158 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
160 struct winbindd_domain *domain = wb_child_domain();
161 struct lsa_RefDomainList *domains = r->out.domains;
162 NTSTATUS status;
163 bool retry = false;
165 if (domain == NULL) {
166 return NT_STATUS_REQUEST_NOT_ACCEPTED;
170 * This breaks the winbindd_domain->methods abstraction: This
171 * is only called for remote domains, and both winbindd_msrpc
172 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
173 * done at the wbint RPC layer.
175 again:
176 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
177 &domains, &r->out.names);
179 if (domains != NULL) {
180 r->out.domains = domains;
183 if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
184 retry = true;
185 goto again;
188 return status;
191 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
193 struct winbindd_domain *domain = wb_child_domain();
194 NTSTATUS status;
196 if (domain == NULL) {
197 return NT_STATUS_REQUEST_NOT_ACCEPTED;
200 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
201 r->in.name, r->in.flags,
202 r->out.sid, r->out.type);
203 reset_cm_connection_on_error(domain, NULL, status);
204 return status;
207 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
208 struct wbint_Sids2UnixIDs *r)
210 uint32_t i;
212 struct lsa_DomainInfo *d;
213 struct wbint_TransID *ids;
214 uint32_t num_ids;
216 struct id_map **id_map_ptrs = NULL;
217 struct idmap_domain *dom;
218 NTSTATUS status = NT_STATUS_NO_MEMORY;
220 if (r->in.domains->count != 1) {
221 return NT_STATUS_INVALID_PARAMETER;
224 d = &r->in.domains->domains[0];
225 ids = r->in.ids->ids;
226 num_ids = r->in.ids->num_ids;
228 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
229 if (dom == NULL) {
230 struct dom_sid_buf buf;
231 DEBUG(10, ("idmap domain %s:%s not found\n",
232 d->name.string,
233 dom_sid_str_buf(d->sid, &buf)));
235 for (i=0; i<num_ids; i++) {
237 ids[i].xid = (struct unixid) {
238 .id = UINT32_MAX,
239 .type = ID_TYPE_NOT_SPECIFIED
243 return NT_STATUS_OK;
246 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
247 if (id_map_ptrs == NULL) {
248 goto nomem;
252 * Convert the input data into a list of id_map structs
253 * suitable for handing in to the idmap sids_to_unixids
254 * method.
257 for (i=0; i<num_ids; i++) {
258 struct id_map *m = id_map_ptrs[i];
260 sid_compose(m->sid, d->sid, ids[i].rid);
261 m->status = ID_UNKNOWN;
262 m->xid = (struct unixid) { .type = ids[i].type_hint };
265 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
267 if (NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
269 * This is okay. We need to transfer the mapped ones
270 * up to our caller. The individual mappings carry the
271 * information whether they are mapped or not.
273 status = NT_STATUS_OK;
276 if (!NT_STATUS_IS_OK(status)) {
277 DEBUG(10, ("sids_to_unixids returned %s\n",
278 nt_errstr(status)));
279 goto done;
283 * Extract the results for handing them back to the caller.
286 for (i=0; i<num_ids; i++) {
287 struct id_map *m = id_map_ptrs[i];
289 if (m->status == ID_REQUIRE_TYPE) {
290 ids[i].xid.id = UINT32_MAX;
291 ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE;
292 continue;
295 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
296 DBG_DEBUG("id %"PRIu32" is out of range "
297 "%"PRIu32"-%"PRIu32" for domain %s\n",
298 m->xid.id, dom->low_id, dom->high_id,
299 dom->name);
300 m->status = ID_UNMAPPED;
303 if (m->status == ID_MAPPED) {
304 ids[i].xid = m->xid;
305 } else {
306 ids[i].xid.id = UINT32_MAX;
307 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
311 goto done;
312 nomem:
313 status = NT_STATUS_NO_MEMORY;
314 done:
315 TALLOC_FREE(id_map_ptrs);
316 return status;
319 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
320 struct wbint_UnixIDs2Sids *r)
322 struct id_map **maps;
323 NTSTATUS status;
324 uint32_t i;
326 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
327 if (maps == NULL) {
328 return NT_STATUS_NO_MEMORY;
331 for (i=0; i<r->in.num_ids; i++) {
332 maps[i]->status = ID_UNKNOWN;
333 maps[i]->xid = r->in.xids[i];
336 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
337 r->in.domain_sid);
338 if (!NT_STATUS_IS_OK(status)) {
339 TALLOC_FREE(maps);
340 return status;
343 for (i=0; i<r->in.num_ids; i++) {
344 if (maps[i]->status == ID_MAPPED) {
345 r->out.xids[i] = maps[i]->xid;
346 sid_copy(&r->out.sids[i], maps[i]->sid);
347 } else {
348 r->out.sids[i] = (struct dom_sid) { 0 };
352 TALLOC_FREE(maps);
354 return NT_STATUS_OK;
357 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
359 struct unixid xid;
360 NTSTATUS status;
362 status = idmap_allocate_uid(&xid);
363 if (!NT_STATUS_IS_OK(status)) {
364 return status;
366 *r->out.uid = xid.id;
367 return NT_STATUS_OK;
370 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
372 struct unixid xid;
373 NTSTATUS status;
375 status = idmap_allocate_gid(&xid);
376 if (!NT_STATUS_IS_OK(status)) {
377 return status;
379 *r->out.gid = xid.id;
380 return NT_STATUS_OK;
383 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
385 struct idmap_domain *domain;
386 NTSTATUS status;
388 domain = idmap_find_domain(r->in.info->domain_name);
389 if ((domain == NULL) || (domain->query_user == NULL)) {
390 return NT_STATUS_REQUEST_NOT_ACCEPTED;
393 status = domain->query_user(domain, r->in.info);
394 return status;
397 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
398 struct wbint_LookupUserAliases *r)
400 struct winbindd_domain *domain = wb_child_domain();
401 NTSTATUS status;
403 if (domain == NULL) {
404 return NT_STATUS_REQUEST_NOT_ACCEPTED;
407 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
408 r->in.sids->num_sids,
409 r->in.sids->sids,
410 &r->out.rids->num_rids,
411 &r->out.rids->rids);
412 reset_cm_connection_on_error(domain, NULL, status);
413 return status;
416 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
417 struct wbint_LookupUserGroups *r)
419 struct winbindd_domain *domain = wb_child_domain();
420 NTSTATUS status;
422 if (domain == NULL) {
423 return NT_STATUS_REQUEST_NOT_ACCEPTED;
426 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
427 &r->out.sids->num_sids,
428 &r->out.sids->sids);
429 reset_cm_connection_on_error(domain, NULL, status);
430 return status;
433 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
434 struct wbint_QuerySequenceNumber *r)
436 struct winbindd_domain *domain = wb_child_domain();
437 NTSTATUS status;
439 if (domain == NULL) {
440 return NT_STATUS_REQUEST_NOT_ACCEPTED;
443 status = wb_cache_sequence_number(domain, r->out.sequence);
444 reset_cm_connection_on_error(domain, NULL, status);
445 return status;
448 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
449 struct wbint_LookupGroupMembers *r)
451 struct winbindd_domain *domain = wb_child_domain();
452 uint32_t i, num_names;
453 struct dom_sid *sid_mem;
454 char **names;
455 uint32_t *name_types;
456 NTSTATUS status;
458 if (domain == NULL) {
459 return NT_STATUS_REQUEST_NOT_ACCEPTED;
462 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
463 r->in.type, &num_names, &sid_mem,
464 &names, &name_types);
465 reset_cm_connection_on_error(domain, NULL, status);
466 if (!NT_STATUS_IS_OK(status)) {
467 return status;
470 r->out.members->num_principals = num_names;
471 r->out.members->principals = talloc_array(
472 r->out.members, struct wbint_Principal, num_names);
473 if (r->out.members->principals == NULL) {
474 return NT_STATUS_NO_MEMORY;
477 for (i=0; i<num_names; i++) {
478 struct wbint_Principal *m = &r->out.members->principals[i];
479 sid_copy(&m->sid, &sid_mem[i]);
480 m->name = talloc_move(r->out.members->principals, &names[i]);
481 m->type = (enum lsa_SidType)name_types[i];
484 return NT_STATUS_OK;
487 NTSTATUS _wbint_LookupAliasMembers(struct pipes_struct *p,
488 struct wbint_LookupAliasMembers *r)
490 struct winbindd_domain *domain = wb_child_domain();
491 NTSTATUS status;
493 if (domain == NULL) {
494 return NT_STATUS_REQUEST_NOT_ACCEPTED;
496 status = wb_cache_lookup_aliasmem(domain,
497 p->mem_ctx,
498 r->in.sid,
499 r->in.type,
500 &r->out.sids->num_sids,
501 &r->out.sids->sids);
502 reset_cm_connection_on_error(domain, NULL, status);
503 if (!NT_STATUS_IS_OK(status)) {
504 return status;
507 return NT_STATUS_OK;
510 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
511 struct wbint_QueryGroupList *r)
513 TALLOC_CTX *frame = NULL;
514 struct winbindd_domain *domain = wb_child_domain();
515 uint32_t i;
516 uint32_t num_local_groups = 0;
517 struct wb_acct_info *local_groups = NULL;
518 uint32_t num_dom_groups = 0;
519 struct wb_acct_info *dom_groups = NULL;
520 uint32_t ti = 0;
521 uint64_t num_total = 0;
522 struct wbint_Principal *result;
523 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
524 bool include_local_groups = false;
526 if (domain == NULL) {
527 return NT_STATUS_REQUEST_NOT_ACCEPTED;
530 frame = talloc_stackframe();
532 switch (lp_server_role()) {
533 case ROLE_ACTIVE_DIRECTORY_DC:
534 if (domain->internal) {
536 * we want to include local groups
537 * for BUILTIN and WORKGROUP
539 include_local_groups = true;
541 break;
542 case ROLE_DOMAIN_MEMBER:
544 * This is needed for GETGRENT to show also e.g. BUILTIN/users.
545 * Otherwise the test_membership_user (smbtorture
546 * local.nss.membership) would fail (getgrouplist() would
547 * reports BUILTIN/users).
549 if (domain->internal) {
551 * we want to include local groups
552 * for BUILTIN and LOCALSAM
554 include_local_groups = true;
556 break;
557 default:
559 * We might include local groups in more
560 * setups later, but that requires more work
561 * elsewhere.
563 break;
566 if (include_local_groups) {
567 status = wb_cache_enum_local_groups(domain, frame,
568 &num_local_groups,
569 &local_groups);
570 reset_cm_connection_on_error(domain, NULL, status);
571 if (!NT_STATUS_IS_OK(status)) {
572 goto out;
576 status = wb_cache_enum_dom_groups(domain, frame,
577 &num_dom_groups,
578 &dom_groups);
579 reset_cm_connection_on_error(domain, NULL, status);
580 if (!NT_STATUS_IS_OK(status)) {
581 goto out;
584 num_total = num_local_groups + num_dom_groups;
585 if (num_total > UINT32_MAX) {
586 status = NT_STATUS_INTERNAL_ERROR;
587 goto out;
590 result = talloc_array(frame, struct wbint_Principal, num_total);
591 if (result == NULL) {
592 status = NT_STATUS_NO_MEMORY;
593 goto out;
596 for (i = 0; i < num_local_groups; i++) {
597 struct wb_acct_info *lg = &local_groups[i];
598 struct wbint_Principal *rg = &result[ti++];
600 sid_compose(&rg->sid, &domain->sid, lg->rid);
601 rg->type = SID_NAME_ALIAS;
602 rg->name = talloc_strdup(result, lg->acct_name);
603 if (rg->name == NULL) {
604 status = NT_STATUS_NO_MEMORY;
605 goto out;
608 num_local_groups = 0;
610 for (i = 0; i < num_dom_groups; i++) {
611 struct wb_acct_info *dg = &dom_groups[i];
612 struct wbint_Principal *rg = &result[ti++];
614 sid_compose(&rg->sid, &domain->sid, dg->rid);
615 rg->type = SID_NAME_DOM_GRP;
616 rg->name = talloc_strdup(result, dg->acct_name);
617 if (rg->name == NULL) {
618 status = NT_STATUS_NO_MEMORY;
619 goto out;
622 num_dom_groups = 0;
624 r->out.groups->num_principals = ti;
625 r->out.groups->principals = talloc_move(r->out.groups, &result);
627 status = NT_STATUS_OK;
628 out:
629 TALLOC_FREE(frame);
630 return status;
633 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
634 struct wbint_QueryUserRidList *r)
636 struct winbindd_domain *domain = wb_child_domain();
637 NTSTATUS status;
639 if (domain == NULL) {
640 return NT_STATUS_REQUEST_NOT_ACCEPTED;
644 * Right now this is overkill. We should add a backend call
645 * just querying the rids.
648 status = wb_cache_query_user_list(domain, p->mem_ctx,
649 &r->out.rids->rids);
650 reset_cm_connection_on_error(domain, NULL, status);
652 if (!NT_STATUS_IS_OK(status)) {
653 return status;
656 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
658 return NT_STATUS_OK;
661 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
663 struct winbindd_domain *domain = wb_child_domain();
664 struct rpc_pipe_client *netlogon_pipe;
665 struct netr_DsRGetDCNameInfo *dc_info;
666 NTSTATUS status;
667 WERROR werr;
668 unsigned int orig_timeout;
669 struct dcerpc_binding_handle *b;
670 bool retry = false;
671 bool try_dsrgetdcname = false;
673 if (domain == NULL) {
674 return dsgetdcname(p->mem_ctx, global_messaging_context(),
675 r->in.domain_name, r->in.domain_guid,
676 r->in.site_name ? r->in.site_name : "",
677 r->in.flags,
678 r->out.dc_info);
681 if (domain->active_directory) {
682 try_dsrgetdcname = true;
685 reconnect:
686 status = cm_connect_netlogon(domain, &netlogon_pipe);
688 reset_cm_connection_on_error(domain, NULL, status);
689 if (!NT_STATUS_IS_OK(status)) {
690 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
691 return status;
694 b = netlogon_pipe->binding_handle;
696 /* This call can take a long time - allow the server to time out.
697 35 seconds should do it. */
699 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
701 if (try_dsrgetdcname) {
702 status = dcerpc_netr_DsRGetDCName(b,
703 p->mem_ctx, domain->dcname,
704 r->in.domain_name, NULL, r->in.domain_guid,
705 r->in.flags, r->out.dc_info, &werr);
706 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
707 goto done;
709 if (!retry &&
710 reset_cm_connection_on_error(domain, NULL, status))
712 retry = true;
713 goto reconnect;
715 try_dsrgetdcname = false;
716 retry = false;
720 * Fallback to less capable methods
723 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
724 if (dc_info == NULL) {
725 status = NT_STATUS_NO_MEMORY;
726 goto done;
729 if (r->in.flags & DS_PDC_REQUIRED) {
730 status = dcerpc_netr_GetDcName(b,
731 p->mem_ctx, domain->dcname,
732 r->in.domain_name, &dc_info->dc_unc, &werr);
733 } else {
734 status = dcerpc_netr_GetAnyDCName(b,
735 p->mem_ctx, domain->dcname,
736 r->in.domain_name, &dc_info->dc_unc, &werr);
739 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
740 retry = true;
741 goto reconnect;
743 if (!NT_STATUS_IS_OK(status)) {
744 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
745 nt_errstr(status)));
746 goto done;
748 if (!W_ERROR_IS_OK(werr)) {
749 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
750 win_errstr(werr)));
751 status = werror_to_ntstatus(werr);
752 goto done;
755 *r->out.dc_info = dc_info;
756 status = NT_STATUS_OK;
758 done:
759 /* And restore our original timeout. */
760 rpccli_set_timeout(netlogon_pipe, orig_timeout);
762 return status;
765 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
767 struct winbindd_domain *domain = wb_child_domain();
768 char *domain_name;
769 char **names;
770 enum lsa_SidType *types;
771 struct wbint_Principal *result;
772 NTSTATUS status;
773 uint32_t i;
775 if (domain == NULL) {
776 return NT_STATUS_REQUEST_NOT_ACCEPTED;
779 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
780 r->in.rids->rids, r->in.rids->num_rids,
781 &domain_name, &names, &types);
782 reset_cm_connection_on_error(domain, NULL, status);
783 if (!NT_STATUS_IS_OK(status) &&
784 !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
785 return status;
788 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
790 result = talloc_array(p->mem_ctx, struct wbint_Principal,
791 r->in.rids->num_rids);
792 if (result == NULL) {
793 return NT_STATUS_NO_MEMORY;
796 for (i=0; i<r->in.rids->num_rids; i++) {
797 sid_compose(&result[i].sid, r->in.domain_sid,
798 r->in.rids->rids[i]);
799 result[i].type = types[i];
800 result[i].name = talloc_move(result, &names[i]);
802 TALLOC_FREE(types);
803 TALLOC_FREE(names);
805 r->out.names->num_principals = r->in.rids->num_rids;
806 r->out.names->principals = result;
807 return NT_STATUS_OK;
810 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
811 struct wbint_CheckMachineAccount *r)
813 struct winbindd_domain *domain;
814 int num_retries = 0;
815 NTSTATUS status;
817 domain = wb_child_domain();
818 if (domain == NULL) {
819 return NT_STATUS_REQUEST_NOT_ACCEPTED;
822 again:
823 invalidate_cm_connection(domain);
824 domain->conn.netlogon_force_reauth = true;
827 struct rpc_pipe_client *netlogon_pipe = NULL;
828 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
829 status = cm_connect_netlogon_secure(domain,
830 &netlogon_pipe,
831 &netlogon_creds_ctx);
834 /* There is a race condition between fetching the trust account
835 password and the periodic machine password change. So it's
836 possible that the trust account password has been changed on us.
837 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
839 #define MAX_RETRIES 3
841 if ((num_retries < MAX_RETRIES)
842 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
843 num_retries++;
844 goto again;
847 if (!NT_STATUS_IS_OK(status)) {
848 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
849 goto done;
852 /* Pass back result code - zero for success, other values for
853 specific failures. */
855 DEBUG(3,("domain %s secret is %s\n", domain->name,
856 NT_STATUS_IS_OK(status) ? "good" : "bad"));
858 done:
859 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
860 ("Checking the trust account password for domain %s returned %s\n",
861 domain->name, nt_errstr(status)));
863 return status;
866 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
867 struct wbint_ChangeMachineAccount *r)
869 struct messaging_context *msg_ctx = global_messaging_context();
870 struct winbindd_domain *domain;
871 NTSTATUS status;
872 struct rpc_pipe_client *netlogon_pipe = NULL;
873 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
875 domain = wb_child_domain();
876 if (domain == NULL) {
877 return NT_STATUS_REQUEST_NOT_ACCEPTED;
880 if (r->in.dcname != NULL && r->in.dcname[0] != '\0') {
881 invalidate_cm_connection(domain);
882 TALLOC_FREE(domain->dcname);
884 domain->dcname = talloc_strdup(domain, r->in.dcname);
885 if (domain->dcname == NULL) {
886 status = NT_STATUS_NO_MEMORY;
887 goto done;
889 domain->force_dc = true;
891 DBG_NOTICE("attempt connection to change trust account "
892 "password for %s at %s\n",
893 domain->name, domain->dcname);
896 status = cm_connect_netlogon_secure(domain,
897 &netlogon_pipe,
898 &netlogon_creds_ctx);
899 if (!NT_STATUS_IS_OK(status)) {
900 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
901 goto done;
904 status = trust_pw_change(netlogon_creds_ctx,
905 msg_ctx,
906 netlogon_pipe->binding_handle,
907 domain->name,
908 domain->dcname,
909 true); /* force */
911 /* Pass back result code - zero for success, other values for
912 specific failures. */
914 DEBUG(3,("domain %s secret %s\n", domain->name,
915 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
917 done:
918 DEBUG(NT_STATUS_IS_OK(status) ? 5 :
919 domain->force_dc ? 0 : 2,
920 ("Changing the trust account password for domain %s at %s "
921 "(forced: %s) returned %s\n",
922 domain->name, domain->dcname, domain->force_dc ? "yes" : "no",
923 nt_errstr(status)));
924 domain->force_dc = false;
926 return status;
929 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
931 NTSTATUS status;
932 struct winbindd_domain *domain;
933 struct rpc_pipe_client *netlogon_pipe;
934 union netr_CONTROL_QUERY_INFORMATION info;
935 WERROR werr;
936 fstring logon_server;
937 struct dcerpc_binding_handle *b;
938 bool retry = false;
940 domain = wb_child_domain();
941 if (domain == NULL) {
942 return NT_STATUS_REQUEST_NOT_ACCEPTED;
945 reconnect:
946 status = cm_connect_netlogon(domain, &netlogon_pipe);
947 reset_cm_connection_on_error(domain, NULL, status);
948 if (!NT_STATUS_IS_OK(status)) {
949 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
950 nt_errstr(status)));
951 return status;
954 b = netlogon_pipe->binding_handle;
956 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
957 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
958 if (*r->out.dcname == NULL) {
959 DEBUG(2, ("Could not allocate memory\n"));
960 return NT_STATUS_NO_MEMORY;
964 * This provokes a WERR_NOT_SUPPORTED error message. This is
965 * documented in the wspp docs. I could not get a successful
966 * call to work, but the main point here is testing that the
967 * netlogon pipe works.
969 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
970 logon_server, NETLOGON_CONTROL_QUERY,
971 2, &info, &werr);
973 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
974 retry = true;
975 goto reconnect;
978 if (!NT_STATUS_IS_OK(status)) {
979 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
980 nt_errstr(status)));
981 return status;
984 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
985 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
986 "WERR_NOT_SUPPORTED\n",
987 win_errstr(werr)));
988 return werror_to_ntstatus(werr);
991 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
992 return NT_STATUS_OK;
995 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
996 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
998 struct winbindd_domain *domain;
999 NTSTATUS status;
1000 struct rpc_pipe_client *netlogon_pipe = NULL;
1001 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1002 struct dcerpc_binding_handle *b = NULL;
1003 bool retry = false;
1005 domain = wb_child_domain();
1006 if (domain == NULL) {
1007 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1010 reconnect:
1011 status = cm_connect_netlogon_secure(domain,
1012 &netlogon_pipe,
1013 &netlogon_creds_ctx);
1014 if (!NT_STATUS_IS_OK(status)) {
1015 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1016 goto done;
1019 b = netlogon_pipe->binding_handle;
1021 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
1022 netlogon_pipe->binding_handle,
1023 r->in.site_name,
1024 r->in.dns_ttl,
1025 r->in.dns_names);
1027 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1028 retry = true;
1029 goto reconnect;
1032 /* Pass back result code - zero for success, other values for
1033 specific failures. */
1035 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
1036 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
1038 done:
1039 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
1040 ("Update of DNS records via RW DC %s returned %s\n",
1041 domain->name, nt_errstr(status)));
1043 return status;
1046 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
1047 struct winbind_SamLogon *r)
1049 struct dcesrv_call_state *dce_call = p->dce_call;
1050 struct dcesrv_connection *dcesrv_conn = dce_call->conn;
1051 const struct tsocket_address *local_address =
1052 dcesrv_connection_get_local_address(dcesrv_conn);
1053 const struct tsocket_address *remote_address =
1054 dcesrv_connection_get_remote_address(dcesrv_conn);
1055 struct winbindd_domain *domain;
1056 NTSTATUS status;
1057 struct netr_IdentityInfo *identity_info = NULL;
1058 DATA_BLOB lm_response, nt_response;
1059 DATA_BLOB challenge = data_blob_null;
1060 uint32_t flags = 0;
1061 uint16_t validation_level;
1062 union netr_Validation *validation = NULL;
1063 bool interactive = false;
1066 * Make sure we start with authoritative=true,
1067 * it will only set to false if we don't know the
1068 * domain.
1070 r->out.authoritative = true;
1072 domain = wb_child_domain();
1073 if (domain == NULL) {
1074 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1077 switch (r->in.validation_level) {
1078 case 3:
1079 case 6:
1080 break;
1081 default:
1082 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1085 switch (r->in.logon_level) {
1086 case NetlogonInteractiveInformation:
1087 case NetlogonServiceInformation:
1088 case NetlogonInteractiveTransitiveInformation:
1089 case NetlogonServiceTransitiveInformation:
1090 if (r->in.logon.password == NULL) {
1091 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1094 interactive = true;
1095 identity_info = &r->in.logon.password->identity_info;
1097 challenge = data_blob_null;
1098 lm_response = data_blob_talloc(p->mem_ctx,
1099 r->in.logon.password->lmpassword.hash,
1100 sizeof(r->in.logon.password->lmpassword.hash));
1101 nt_response = data_blob_talloc(p->mem_ctx,
1102 r->in.logon.password->ntpassword.hash,
1103 sizeof(r->in.logon.password->ntpassword.hash));
1104 break;
1106 case NetlogonNetworkInformation:
1107 case NetlogonNetworkTransitiveInformation:
1108 if (r->in.logon.network == NULL) {
1109 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1112 interactive = false;
1113 identity_info = &r->in.logon.network->identity_info;
1115 challenge = data_blob_talloc(p->mem_ctx,
1116 r->in.logon.network->challenge,
1118 lm_response = data_blob_talloc(p->mem_ctx,
1119 r->in.logon.network->lm.data,
1120 r->in.logon.network->lm.length);
1121 nt_response = data_blob_talloc(p->mem_ctx,
1122 r->in.logon.network->nt.data,
1123 r->in.logon.network->nt.length);
1124 break;
1126 case NetlogonGenericInformation:
1127 if (r->in.logon.generic == NULL) {
1128 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1131 identity_info = &r->in.logon.generic->identity_info;
1133 * Not implemented here...
1135 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1137 default:
1138 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1141 status = winbind_dual_SamLogon(domain, p->mem_ctx,
1142 interactive,
1143 identity_info->parameter_control,
1144 identity_info->account_name.string,
1145 identity_info->domain_name.string,
1146 identity_info->workstation.string,
1147 identity_info->logon_id,
1148 "SamLogon",
1150 challenge,
1151 lm_response, nt_response,
1152 remote_address,
1153 local_address,
1154 &r->out.authoritative,
1155 true, /* skip_sam */
1156 &flags,
1157 &validation_level,
1158 &validation);
1159 if (!NT_STATUS_IS_OK(status)) {
1160 return status;
1162 switch (r->in.validation_level) {
1163 case 3:
1164 status = map_validation_to_info3(p->mem_ctx,
1165 validation_level,
1166 validation,
1167 &r->out.validation.sam3);
1168 TALLOC_FREE(validation);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 return status;
1172 return NT_STATUS_OK;
1173 case 6:
1174 status = map_validation_to_info6(p->mem_ctx,
1175 validation_level,
1176 validation,
1177 &r->out.validation.sam6);
1178 TALLOC_FREE(validation);
1179 if (!NT_STATUS_IS_OK(status)) {
1180 return status;
1182 return NT_STATUS_OK;
1185 smb_panic(__location__);
1186 return NT_STATUS_INTERNAL_ERROR;
1189 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1190 struct winbindd_domain *domain,
1191 struct winbind_LogonControl *r)
1193 NTSTATUS status;
1194 struct rpc_pipe_client *netlogon_pipe = NULL;
1195 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1196 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1197 WERROR check_result = WERR_INTERNAL_ERROR;
1199 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1200 if (info2 == NULL) {
1201 return WERR_NOT_ENOUGH_MEMORY;
1204 if (domain->internal) {
1205 check_result = WERR_OK;
1206 goto check_return;
1210 * For now we just force a reconnect
1212 * TODO: take care of the optional '\dcname'
1214 invalidate_cm_connection(domain);
1215 domain->conn.netlogon_force_reauth = true;
1216 status = cm_connect_netlogon_secure(domain,
1217 &netlogon_pipe,
1218 &netlogon_creds_ctx);
1219 reset_cm_connection_on_error(domain, NULL, status);
1220 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1221 status = NT_STATUS_NO_LOGON_SERVERS;
1223 if (!NT_STATUS_IS_OK(status)) {
1224 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1225 __func__, domain->name, domain->alt_name,
1226 nt_errstr(status)));
1228 * Here we return a top level error!
1229 * This is different than TC_QUERY or TC_VERIFY.
1231 return ntstatus_to_werror(status);
1233 check_result = WERR_OK;
1235 check_return:
1236 info2->pdc_connection_status = WERR_OK;
1237 if (domain->dcname != NULL) {
1238 info2->flags |= NETLOGON_HAS_IP;
1239 info2->flags |= NETLOGON_HAS_TIMESERV;
1240 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1241 domain->dcname);
1242 if (info2->trusted_dc_name == NULL) {
1243 return WERR_NOT_ENOUGH_MEMORY;
1245 } else {
1246 info2->trusted_dc_name = talloc_strdup(info2, "");
1247 if (info2->trusted_dc_name == NULL) {
1248 return WERR_NOT_ENOUGH_MEMORY;
1251 info2->tc_connection_status = check_result;
1253 if (!W_ERROR_IS_OK(info2->pdc_connection_status) ||
1254 !W_ERROR_IS_OK(info2->tc_connection_status))
1256 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1257 "pdc_connection[%s] tc_connection[%s]\n",
1258 __func__, domain->name, domain->alt_name,
1259 domain->dcname,
1260 win_errstr(info2->pdc_connection_status),
1261 win_errstr(info2->tc_connection_status)));
1264 r->out.query->info2 = info2;
1266 DEBUG(5, ("%s: succeeded.\n", __func__));
1267 return WERR_OK;
1270 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1271 struct winbindd_domain *domain,
1272 struct winbind_LogonControl *r)
1274 NTSTATUS status;
1275 struct rpc_pipe_client *netlogon_pipe = NULL;
1276 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1277 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1278 WERROR check_result = WERR_INTERNAL_ERROR;
1280 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1281 if (info2 == NULL) {
1282 return WERR_NOT_ENOUGH_MEMORY;
1285 if (domain->internal) {
1286 check_result = WERR_OK;
1287 goto check_return;
1290 status = cm_connect_netlogon_secure(domain,
1291 &netlogon_pipe,
1292 &netlogon_creds_ctx);
1293 reset_cm_connection_on_error(domain, NULL, status);
1294 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1295 status = NT_STATUS_NO_LOGON_SERVERS;
1297 if (!NT_STATUS_IS_OK(status)) {
1298 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1299 nt_errstr(status)));
1300 check_result = ntstatus_to_werror(status);
1301 goto check_return;
1303 check_result = WERR_OK;
1305 check_return:
1306 info2->pdc_connection_status = WERR_OK;
1307 if (domain->dcname != NULL) {
1308 info2->flags |= NETLOGON_HAS_IP;
1309 info2->flags |= NETLOGON_HAS_TIMESERV;
1310 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1311 domain->dcname);
1312 if (info2->trusted_dc_name == NULL) {
1313 return WERR_NOT_ENOUGH_MEMORY;
1315 } else {
1316 info2->trusted_dc_name = talloc_strdup(info2, "");
1317 if (info2->trusted_dc_name == NULL) {
1318 return WERR_NOT_ENOUGH_MEMORY;
1321 info2->tc_connection_status = check_result;
1323 if (!W_ERROR_IS_OK(info2->pdc_connection_status) ||
1324 !W_ERROR_IS_OK(info2->tc_connection_status))
1326 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1327 "pdc_connection[%s] tc_connection[%s]\n",
1328 __func__, domain->name, domain->alt_name,
1329 domain->dcname,
1330 win_errstr(info2->pdc_connection_status),
1331 win_errstr(info2->tc_connection_status)));
1334 r->out.query->info2 = info2;
1336 DEBUG(5, ("%s: succeeded.\n", __func__));
1337 return WERR_OK;
1340 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1341 struct winbindd_domain *domain,
1342 struct winbind_LogonControl *r)
1344 TALLOC_CTX *frame = talloc_stackframe();
1345 NTSTATUS status;
1346 NTSTATUS result;
1347 struct lsa_String trusted_domain_name = {};
1348 struct lsa_StringLarge trusted_domain_name_l = {};
1349 struct rpc_pipe_client *local_lsa_pipe = NULL;
1350 struct policy_handle local_lsa_policy = {};
1351 struct dcerpc_binding_handle *local_lsa = NULL;
1352 struct rpc_pipe_client *netlogon_pipe = NULL;
1353 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1354 struct cli_credentials *creds = NULL;
1355 struct samr_Password *cur_nt_hash = NULL;
1356 uint32_t trust_attributes = 0;
1357 struct samr_Password new_owf_password = {};
1358 bool cmp_new = false;
1359 struct samr_Password old_owf_password = {};
1360 bool cmp_old = false;
1361 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1362 bool fetch_fti = false;
1363 struct lsa_ForestTrustInformation *new_fti = NULL;
1364 struct netr_TrustInfo *trust_info = NULL;
1365 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1366 struct dcerpc_binding_handle *b = NULL;
1367 WERROR check_result = WERR_INTERNAL_ERROR;
1368 WERROR verify_result = WERR_INTERNAL_ERROR;
1369 bool retry = false;
1371 trusted_domain_name.string = domain->name;
1372 trusted_domain_name_l.string = domain->name;
1374 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1375 if (info2 == NULL) {
1376 TALLOC_FREE(frame);
1377 return WERR_NOT_ENOUGH_MEMORY;
1380 if (domain->internal) {
1381 check_result = WERR_OK;
1382 goto check_return;
1385 if (!domain->primary) {
1386 union lsa_TrustedDomainInfo *tdi = NULL;
1388 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1389 &local_lsa_policy);
1390 if (!NT_STATUS_IS_OK(status)) {
1391 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1392 __location__, __func__, nt_errstr(status)));
1393 TALLOC_FREE(frame);
1394 return WERR_INTERNAL_ERROR;
1396 local_lsa = local_lsa_pipe->binding_handle;
1398 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1399 &local_lsa_policy,
1400 &trusted_domain_name,
1401 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1402 &tdi, &result);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1405 __location__, __func__, domain->name, nt_errstr(status)));
1406 TALLOC_FREE(frame);
1407 return WERR_INTERNAL_ERROR;
1409 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1410 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1411 __location__, __func__, domain->name));
1412 TALLOC_FREE(frame);
1413 return WERR_NO_SUCH_DOMAIN;
1415 if (!NT_STATUS_IS_OK(result)) {
1416 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1417 __location__, __func__, domain->name, nt_errstr(result)));
1418 TALLOC_FREE(frame);
1419 return WERR_INTERNAL_ERROR;
1421 if (tdi == NULL) {
1422 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1423 "returned no trusted domain information\n",
1424 __location__, __func__));
1425 TALLOC_FREE(frame);
1426 return WERR_INTERNAL_ERROR;
1429 local_tdo = &tdi->info_ex;
1430 trust_attributes = local_tdo->trust_attributes;
1433 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1434 struct lsa_ForestTrustInformation *old_fti = NULL;
1436 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1437 &local_lsa_policy,
1438 &trusted_domain_name,
1439 LSA_FOREST_TRUST_DOMAIN_INFO,
1440 &old_fti, &result);
1441 if (!NT_STATUS_IS_OK(status)) {
1442 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1443 __location__, __func__, domain->name, nt_errstr(status)));
1444 TALLOC_FREE(frame);
1445 return WERR_INTERNAL_ERROR;
1447 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1448 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1449 __func__, domain->name));
1450 old_fti = NULL;
1451 fetch_fti = true;
1452 result = NT_STATUS_OK;
1454 if (!NT_STATUS_IS_OK(result)) {
1455 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1456 __location__, __func__, domain->name, nt_errstr(result)));
1457 TALLOC_FREE(frame);
1458 return WERR_INTERNAL_ERROR;
1461 TALLOC_FREE(old_fti);
1464 reconnect:
1465 status = cm_connect_netlogon_secure(domain,
1466 &netlogon_pipe,
1467 &netlogon_creds_ctx);
1468 reset_cm_connection_on_error(domain, NULL, status);
1469 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1470 status = NT_STATUS_NO_LOGON_SERVERS;
1472 if (!NT_STATUS_IS_OK(status)) {
1473 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1474 nt_errstr(status)));
1475 check_result = ntstatus_to_werror(status);
1476 goto check_return;
1478 check_result = WERR_OK;
1479 b = netlogon_pipe->binding_handle;
1481 status = winbindd_get_trust_credentials(domain,
1482 frame,
1483 true, /* netlogon */
1484 false, /* ipc_fallback */
1485 &creds);
1486 if (NT_STATUS_IS_OK(status)) {
1487 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1488 TALLOC_FREE(creds);
1490 if (cur_nt_hash == NULL) {
1491 verify_result = WERR_NO_TRUST_LSA_SECRET;
1492 goto verify_return;
1495 if (fetch_fti) {
1496 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1497 b, frame,
1498 &new_fti);
1499 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1500 status = NT_STATUS_NOT_SUPPORTED;
1502 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1503 new_fti = NULL;
1504 status = NT_STATUS_OK;
1506 if (!NT_STATUS_IS_OK(status)) {
1507 if (!retry &&
1508 reset_cm_connection_on_error(domain, b, status))
1510 retry = true;
1511 goto reconnect;
1513 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1514 "failed: %s\n",
1515 domain->name, nt_errstr(status)));
1516 check_result = ntstatus_to_werror(status);
1517 goto check_return;
1521 if (new_fti != NULL) {
1522 struct lsa_ForestTrustInformation old_fti = {};
1523 struct lsa_ForestTrustInformation *merged_fti = NULL;
1524 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1526 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1527 &old_fti, new_fti,
1528 &merged_fti);
1529 if (!NT_STATUS_IS_OK(status)) {
1530 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1531 __location__, __func__,
1532 domain->name, nt_errstr(status)));
1533 TALLOC_FREE(frame);
1534 return ntstatus_to_werror(status);
1537 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1538 &local_lsa_policy,
1539 &trusted_domain_name_l,
1540 LSA_FOREST_TRUST_DOMAIN_INFO,
1541 merged_fti,
1542 0, /* check_only=0 => store it! */
1543 &collision_info,
1544 &result);
1545 if (!NT_STATUS_IS_OK(status)) {
1546 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1547 __location__, __func__, domain->name, nt_errstr(status)));
1548 TALLOC_FREE(frame);
1549 return WERR_INTERNAL_ERROR;
1551 if (!NT_STATUS_IS_OK(result)) {
1552 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1553 __location__, __func__, domain->name, nt_errstr(result)));
1554 TALLOC_FREE(frame);
1555 return ntstatus_to_werror(result);
1559 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1560 b, frame,
1561 &new_owf_password,
1562 &old_owf_password,
1563 &trust_info);
1564 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1565 status = NT_STATUS_NOT_SUPPORTED;
1567 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1568 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1569 nt_errstr(status)));
1570 verify_result = WERR_OK;
1571 goto verify_return;
1573 if (!NT_STATUS_IS_OK(status)) {
1574 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1575 retry = true;
1576 goto reconnect;
1578 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1579 nt_errstr(status)));
1581 if (!dcerpc_binding_handle_is_connected(b)) {
1582 check_result = ntstatus_to_werror(status);
1583 goto check_return;
1584 } else {
1585 verify_result = ntstatus_to_werror(status);
1586 goto verify_return;
1590 if (trust_info != NULL && trust_info->count >= 1) {
1591 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1593 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1594 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1595 goto verify_return;
1599 cmp_new = mem_equal_const_time(new_owf_password.hash,
1600 cur_nt_hash->hash,
1601 sizeof(cur_nt_hash->hash));
1602 cmp_old = mem_equal_const_time(old_owf_password.hash,
1603 cur_nt_hash->hash,
1604 sizeof(cur_nt_hash->hash));
1605 if (!cmp_new && !cmp_old) {
1606 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1607 "any password known to dcname[%s]\n",
1608 __func__, domain->name, domain->alt_name,
1609 domain->dcname));
1610 verify_result = WERR_WRONG_PASSWORD;
1611 goto verify_return;
1614 if (!cmp_new) {
1615 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1616 "against the old password known to dcname[%s]\n",
1617 __func__, domain->name, domain->alt_name,
1618 domain->dcname));
1621 verify_result = WERR_OK;
1622 goto verify_return;
1624 check_return:
1625 verify_result = check_result;
1626 verify_return:
1627 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1628 info2->pdc_connection_status = verify_result;
1629 if (domain->dcname != NULL) {
1630 info2->flags |= NETLOGON_HAS_IP;
1631 info2->flags |= NETLOGON_HAS_TIMESERV;
1632 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1633 domain->dcname);
1634 if (info2->trusted_dc_name == NULL) {
1635 TALLOC_FREE(frame);
1636 return WERR_NOT_ENOUGH_MEMORY;
1638 } else {
1639 info2->trusted_dc_name = talloc_strdup(info2, "");
1640 if (info2->trusted_dc_name == NULL) {
1641 TALLOC_FREE(frame);
1642 return WERR_NOT_ENOUGH_MEMORY;
1645 info2->tc_connection_status = check_result;
1647 if (!W_ERROR_IS_OK(info2->pdc_connection_status) ||
1648 !W_ERROR_IS_OK(info2->tc_connection_status))
1650 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1651 "pdc_connection[%s] tc_connection[%s]\n",
1652 __func__, domain->name, domain->alt_name,
1653 domain->dcname,
1654 win_errstr(info2->pdc_connection_status),
1655 win_errstr(info2->tc_connection_status)));
1658 r->out.query->info2 = info2;
1660 DEBUG(5, ("%s: succeeded.\n", __func__));
1661 TALLOC_FREE(frame);
1662 return WERR_OK;
1665 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1666 struct winbindd_domain *domain,
1667 struct winbind_LogonControl *r)
1669 struct messaging_context *msg_ctx = global_messaging_context();
1670 NTSTATUS status;
1671 struct rpc_pipe_client *netlogon_pipe = NULL;
1672 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1673 struct cli_credentials *creds = NULL;
1674 struct samr_Password *cur_nt_hash = NULL;
1675 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1676 struct dcerpc_binding_handle *b;
1677 WERROR change_result = WERR_OK;
1678 bool retry = false;
1680 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1681 if (info1 == NULL) {
1682 return WERR_NOT_ENOUGH_MEMORY;
1685 if (domain->internal) {
1686 return WERR_NOT_SUPPORTED;
1689 status = pdb_get_trust_credentials(domain->name,
1690 domain->alt_name,
1691 p->mem_ctx,
1692 &creds);
1693 if (NT_STATUS_IS_OK(status)) {
1694 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1695 TALLOC_FREE(creds);
1698 reconnect:
1699 status = cm_connect_netlogon_secure(domain,
1700 &netlogon_pipe,
1701 &netlogon_creds_ctx);
1702 reset_cm_connection_on_error(domain, NULL, status);
1703 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1704 status = NT_STATUS_NO_LOGON_SERVERS;
1706 if (!NT_STATUS_IS_OK(status)) {
1707 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1708 __func__, domain->name, domain->alt_name,
1709 nt_errstr(status)));
1711 * Here we return a top level error!
1712 * This is different than TC_QUERY or TC_VERIFY.
1714 return ntstatus_to_werror(status);
1716 b = netlogon_pipe->binding_handle;
1718 if (cur_nt_hash == NULL) {
1719 change_result = WERR_NO_TRUST_LSA_SECRET;
1720 goto change_return;
1722 TALLOC_FREE(cur_nt_hash);
1724 status = trust_pw_change(netlogon_creds_ctx,
1725 msg_ctx, b, domain->name,
1726 domain->dcname,
1727 true); /* force */
1728 if (!NT_STATUS_IS_OK(status)) {
1729 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1730 retry = true;
1731 goto reconnect;
1734 DEBUG(1, ("trust_pw_change(%s): %s\n",
1735 domain->name, nt_errstr(status)));
1737 change_result = ntstatus_to_werror(status);
1738 goto change_return;
1741 change_result = WERR_OK;
1743 change_return:
1744 info1->pdc_connection_status = change_result;
1746 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1747 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1748 "pdc_connection[%s]\n",
1749 __func__, domain->name, domain->alt_name,
1750 domain->dcname,
1751 win_errstr(info1->pdc_connection_status)));
1754 r->out.query->info1 = info1;
1756 DEBUG(5, ("%s: succeeded.\n", __func__));
1757 return WERR_OK;
1760 WERROR _winbind_LogonControl(struct pipes_struct *p,
1761 struct winbind_LogonControl *r)
1763 struct winbindd_domain *domain;
1765 domain = wb_child_domain();
1766 if (domain == NULL) {
1767 return WERR_NO_SUCH_DOMAIN;
1770 switch (r->in.function_code) {
1771 case NETLOGON_CONTROL_REDISCOVER:
1772 if (r->in.level != 2) {
1773 return WERR_INVALID_PARAMETER;
1775 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1776 case NETLOGON_CONTROL_TC_QUERY:
1777 if (r->in.level != 2) {
1778 return WERR_INVALID_PARAMETER;
1780 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1781 case NETLOGON_CONTROL_TC_VERIFY:
1782 if (r->in.level != 2) {
1783 return WERR_INVALID_PARAMETER;
1785 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1786 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1787 if (r->in.level != 1) {
1788 return WERR_INVALID_PARAMETER;
1790 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1791 default:
1792 break;
1795 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1796 __func__, r->in.function_code));
1797 return WERR_NOT_SUPPORTED;
1800 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1801 struct winbind_GetForestTrustInformation *r)
1803 TALLOC_CTX *frame = talloc_stackframe();
1804 NTSTATUS status, result;
1805 struct winbindd_domain *domain;
1806 struct rpc_pipe_client *netlogon_pipe = NULL;
1807 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1808 struct dcerpc_binding_handle *b;
1809 bool retry = false;
1810 struct lsa_String trusted_domain_name = {};
1811 struct lsa_StringLarge trusted_domain_name_l = {};
1812 union lsa_TrustedDomainInfo *tdi = NULL;
1813 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1814 struct lsa_ForestTrustInformation _old_fti = {};
1815 struct lsa_ForestTrustInformation *old_fti = NULL;
1816 struct lsa_ForestTrustInformation *new_fti = NULL;
1817 struct lsa_ForestTrustInformation *merged_fti = NULL;
1818 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1819 bool update_fti = false;
1820 struct rpc_pipe_client *local_lsa_pipe;
1821 struct policy_handle local_lsa_policy;
1822 struct dcerpc_binding_handle *local_lsa = NULL;
1824 domain = wb_child_domain();
1825 if (domain == NULL) {
1826 TALLOC_FREE(frame);
1827 return WERR_NO_SUCH_DOMAIN;
1831 * checking for domain->internal and domain->primary
1832 * makes sure we only do some work when running as DC.
1835 if (domain->internal) {
1836 TALLOC_FREE(frame);
1837 return WERR_NO_SUCH_DOMAIN;
1840 if (domain->primary) {
1841 TALLOC_FREE(frame);
1842 return WERR_NO_SUCH_DOMAIN;
1845 trusted_domain_name.string = domain->name;
1846 trusted_domain_name_l.string = domain->name;
1848 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1849 &local_lsa_policy);
1850 if (!NT_STATUS_IS_OK(status)) {
1851 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1852 __location__, __func__, nt_errstr(status)));
1853 TALLOC_FREE(frame);
1854 return WERR_INTERNAL_ERROR;
1856 local_lsa = local_lsa_pipe->binding_handle;
1858 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1859 &local_lsa_policy,
1860 &trusted_domain_name,
1861 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1862 &tdi, &result);
1863 if (!NT_STATUS_IS_OK(status)) {
1864 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1865 __location__, __func__, domain->name, nt_errstr(status)));
1866 TALLOC_FREE(frame);
1867 return WERR_INTERNAL_ERROR;
1869 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1870 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1871 __location__, __func__, domain->name));
1872 TALLOC_FREE(frame);
1873 return WERR_NO_SUCH_DOMAIN;
1875 if (!NT_STATUS_IS_OK(result)) {
1876 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1877 __location__, __func__, domain->name, nt_errstr(result)));
1878 TALLOC_FREE(frame);
1879 return WERR_INTERNAL_ERROR;
1881 if (tdi == NULL) {
1882 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1883 "returned no trusted domain information\n",
1884 __location__, __func__));
1885 TALLOC_FREE(frame);
1886 return WERR_INTERNAL_ERROR;
1889 tdo = &tdi->info_ex;
1891 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1892 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1893 __func__, tdo->netbios_name.string,
1894 tdo->domain_name.string,
1895 (unsigned)tdo->trust_attributes));
1896 TALLOC_FREE(frame);
1897 return WERR_NO_SUCH_DOMAIN;
1900 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1901 TALLOC_FREE(frame);
1902 return WERR_INVALID_FLAGS;
1905 reconnect:
1906 status = cm_connect_netlogon_secure(domain,
1907 &netlogon_pipe,
1908 &netlogon_creds_ctx);
1909 reset_cm_connection_on_error(domain, NULL, status);
1910 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1911 status = NT_STATUS_NO_LOGON_SERVERS;
1913 if (!NT_STATUS_IS_OK(status)) {
1914 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1915 nt_errstr(status)));
1916 TALLOC_FREE(frame);
1917 return ntstatus_to_werror(status);
1919 b = netlogon_pipe->binding_handle;
1921 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1922 b, p->mem_ctx,
1923 &new_fti);
1924 if (!NT_STATUS_IS_OK(status)) {
1925 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1926 retry = true;
1927 goto reconnect;
1929 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1930 domain->name, nt_errstr(status)));
1931 TALLOC_FREE(frame);
1932 return ntstatus_to_werror(status);
1935 *r->out.forest_trust_info = new_fti;
1937 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1938 update_fti = true;
1941 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1942 &local_lsa_policy,
1943 &trusted_domain_name,
1944 LSA_FOREST_TRUST_DOMAIN_INFO,
1945 &old_fti, &result);
1946 if (!NT_STATUS_IS_OK(status)) {
1947 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1948 __location__, __func__, domain->name, nt_errstr(status)));
1949 TALLOC_FREE(frame);
1950 return WERR_INTERNAL_ERROR;
1952 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1953 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1954 __func__, domain->name));
1955 update_fti = true;
1956 old_fti = &_old_fti;
1957 result = NT_STATUS_OK;
1959 if (!NT_STATUS_IS_OK(result)) {
1960 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1961 __location__, __func__, domain->name, nt_errstr(result)));
1962 TALLOC_FREE(frame);
1963 return WERR_INTERNAL_ERROR;
1966 if (old_fti == NULL) {
1967 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1968 "returned success without returning forest trust information\n",
1969 __location__, __func__));
1970 TALLOC_FREE(frame);
1971 return WERR_INTERNAL_ERROR;
1974 if (!update_fti) {
1975 goto done;
1978 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1979 &merged_fti);
1980 if (!NT_STATUS_IS_OK(status)) {
1981 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1982 __location__, __func__, domain->name, nt_errstr(status)));
1983 TALLOC_FREE(frame);
1984 return ntstatus_to_werror(status);
1987 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1988 &local_lsa_policy,
1989 &trusted_domain_name_l,
1990 LSA_FOREST_TRUST_DOMAIN_INFO,
1991 merged_fti,
1992 0, /* check_only=0 => store it! */
1993 &collision_info,
1994 &result);
1995 if (!NT_STATUS_IS_OK(status)) {
1996 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1997 __location__, __func__, domain->name, nt_errstr(status)));
1998 TALLOC_FREE(frame);
1999 return WERR_INTERNAL_ERROR;
2001 if (!NT_STATUS_IS_OK(result)) {
2002 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
2003 __location__, __func__, domain->name, nt_errstr(result)));
2004 TALLOC_FREE(frame);
2005 return ntstatus_to_werror(result);
2008 done:
2009 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
2010 TALLOC_FREE(frame);
2011 return WERR_OK;
2014 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
2016 struct winbindd_domain *domain;
2017 NTSTATUS status;
2018 struct rpc_pipe_client *netlogon_pipe;
2019 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
2020 struct dcerpc_binding_handle *b = NULL;
2021 bool retry = false;
2023 DEBUG(5, ("_winbind_SendToSam received\n"));
2024 domain = wb_child_domain();
2025 if (domain == NULL) {
2026 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2029 reconnect:
2030 status = cm_connect_netlogon_secure(domain,
2031 &netlogon_pipe,
2032 &netlogon_creds_ctx);
2033 reset_cm_connection_on_error(domain, NULL, status);
2034 if (!NT_STATUS_IS_OK(status)) {
2035 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
2036 return status;
2039 b = netlogon_pipe->binding_handle;
2041 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
2043 &r->in.message);
2044 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
2045 retry = true;
2046 goto reconnect;
2049 return status;
2052 NTSTATUS _wbint_ListTrustedDomains(struct pipes_struct *p,
2053 struct wbint_ListTrustedDomains *r)
2055 struct winbindd_domain *domain = wb_child_domain();
2056 uint32_t i;
2057 NTSTATUS result;
2058 struct netr_DomainTrustList trusts;
2059 uint32_t count = 0;
2060 struct netr_DomainTrust *array = NULL;
2061 pid_t client_pid;
2063 if (domain == NULL) {
2064 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2067 /* Cut client_pid to 32bit */
2068 client_pid = r->in.client_pid;
2069 if ((uint64_t)client_pid != r->in.client_pid) {
2070 DBG_DEBUG("pid out of range\n");
2071 return NT_STATUS_INVALID_PARAMETER;
2074 DBG_NOTICE("[%s %"PRIu32"]: list trusted domains\n",
2075 r->in.client_name, client_pid);
2077 result = wb_cache_trusted_domains(domain, p->mem_ctx, &trusts);
2078 if (!NT_STATUS_IS_OK(result)) {
2079 DBG_NOTICE("wb_cache_trusted_domains returned %s\n",
2080 nt_errstr(result));
2081 return result;
2084 for (i=0; i<trusts.count; i++) {
2085 struct netr_DomainTrust *st = &trusts.array[i];
2086 struct netr_DomainTrust *dt = NULL;
2088 if (st->sid == NULL) {
2089 continue;
2091 if (dom_sid_equal(st->sid, &global_sid_NULL)) {
2092 continue;
2095 array = talloc_realloc(r->out.domains, array,
2096 struct netr_DomainTrust,
2097 count + 1);
2098 if (array == NULL) {
2099 return NT_STATUS_NO_MEMORY;
2102 dt = &array[count];
2104 *dt = (struct netr_DomainTrust) {
2105 .trust_flags = st->trust_flags,
2106 .trust_type = st->trust_type,
2107 .trust_attributes = st->trust_attributes,
2108 .netbios_name = talloc_move(array, &st->netbios_name),
2109 .dns_name = talloc_move(array, &st->dns_name),
2112 dt->sid = dom_sid_dup(array, st->sid);
2113 if (dt->sid == NULL) {
2114 return NT_STATUS_NO_MEMORY;
2117 count++;
2120 r->out.domains->array = array;
2121 r->out.domains->count = count;
2122 return NT_STATUS_OK;
2125 #include "librpc/gen_ndr/ndr_winbind_scompat.c"