python/samba/tests: add test cases for s3/registry init funcs
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blobae2bd77c8a6cd8230908f09aee236bbe2ae0d046
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 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
50 struct dcerpc_binding_handle *b,
51 NTSTATUS status)
53 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
54 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
55 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
56 invalidate_cm_connection(domain);
57 domain->conn.netlogon_force_reauth = true;
58 return true;
61 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
62 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
64 invalidate_cm_connection(domain);
65 /* We invalidated the connection. */
66 return true;
69 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
70 invalidate_cm_connection(domain);
71 return true;
74 return false;
77 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
79 struct winbindd_domain *domain = wb_child_domain();
80 char *dom_name;
81 char *name;
82 enum lsa_SidType type;
83 NTSTATUS status;
85 if (domain == NULL) {
86 return NT_STATUS_REQUEST_NOT_ACCEPTED;
89 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
90 &dom_name, &name, &type);
91 reset_cm_connection_on_error(domain, NULL, status);
92 if (!NT_STATUS_IS_OK(status)) {
93 return status;
96 *r->out.domain = dom_name;
97 *r->out.name = name;
98 *r->out.type = type;
99 return NT_STATUS_OK;
102 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
104 struct winbindd_domain *domain = wb_child_domain();
105 struct lsa_RefDomainList *domains = r->out.domains;
106 NTSTATUS status;
107 bool retry = false;
109 if (domain == NULL) {
110 return NT_STATUS_REQUEST_NOT_ACCEPTED;
114 * This breaks the winbindd_domain->methods abstraction: This
115 * is only called for remote domains, and both winbindd_msrpc
116 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
117 * done at the wbint RPC layer.
119 again:
120 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
121 &domains, &r->out.names);
123 if (domains != NULL) {
124 r->out.domains = domains;
127 if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
128 retry = true;
129 goto again;
132 return status;
135 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
137 struct winbindd_domain *domain = wb_child_domain();
138 NTSTATUS status;
140 if (domain == NULL) {
141 return NT_STATUS_REQUEST_NOT_ACCEPTED;
144 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
145 r->in.name, r->in.flags,
146 r->out.sid, r->out.type);
147 reset_cm_connection_on_error(domain, NULL, status);
148 return status;
151 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
152 struct wbint_Sids2UnixIDs *r)
154 uint32_t i;
156 struct lsa_DomainInfo *d;
157 struct wbint_TransID *ids;
158 uint32_t num_ids;
160 struct id_map **id_map_ptrs = NULL;
161 struct idmap_domain *dom;
162 NTSTATUS status = NT_STATUS_NO_MEMORY;
164 if (r->in.domains->count != 1) {
165 return NT_STATUS_INVALID_PARAMETER;
168 d = &r->in.domains->domains[0];
169 ids = r->in.ids->ids;
170 num_ids = r->in.ids->num_ids;
172 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
173 if (dom == NULL) {
174 struct dom_sid_buf buf;
175 DEBUG(10, ("idmap domain %s:%s not found\n",
176 d->name.string,
177 dom_sid_str_buf(d->sid, &buf)));
179 for (i=0; i<num_ids; i++) {
181 ids[i].xid = (struct unixid) {
182 .id = UINT32_MAX,
183 .type = ID_TYPE_NOT_SPECIFIED
187 return NT_STATUS_OK;
190 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
191 if (id_map_ptrs == NULL) {
192 goto nomem;
196 * Convert the input data into a list of id_map structs
197 * suitable for handing in to the idmap sids_to_unixids
198 * method.
201 for (i=0; i<num_ids; i++) {
202 struct id_map *m = id_map_ptrs[i];
204 sid_compose(m->sid, d->sid, ids[i].rid);
205 m->status = ID_UNKNOWN;
206 m->xid = (struct unixid) { .type = ids[i].type_hint };
209 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
211 if (NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
213 * This is okay. We need to transfer the mapped ones
214 * up to our caller. The individual mappings carry the
215 * information whether they are mapped or not.
217 status = NT_STATUS_OK;
220 if (!NT_STATUS_IS_OK(status)) {
221 DEBUG(10, ("sids_to_unixids returned %s\n",
222 nt_errstr(status)));
223 goto done;
227 * Extract the results for handing them back to the caller.
230 for (i=0; i<num_ids; i++) {
231 struct id_map *m = id_map_ptrs[i];
233 if (m->status == ID_REQUIRE_TYPE) {
234 ids[i].xid.id = UINT32_MAX;
235 ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE;
236 continue;
239 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
240 DBG_DEBUG("id %"PRIu32" is out of range "
241 "%"PRIu32"-%"PRIu32" for domain %s\n",
242 m->xid.id, dom->low_id, dom->high_id,
243 dom->name);
244 m->status = ID_UNMAPPED;
247 if (m->status == ID_MAPPED) {
248 ids[i].xid = m->xid;
249 } else {
250 ids[i].xid.id = UINT32_MAX;
251 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
255 goto done;
256 nomem:
257 status = NT_STATUS_NO_MEMORY;
258 done:
259 TALLOC_FREE(id_map_ptrs);
260 return status;
263 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
264 struct wbint_UnixIDs2Sids *r)
266 struct id_map **maps;
267 NTSTATUS status;
268 uint32_t i;
270 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
271 if (maps == NULL) {
272 return NT_STATUS_NO_MEMORY;
275 for (i=0; i<r->in.num_ids; i++) {
276 maps[i]->status = ID_UNKNOWN;
277 maps[i]->xid = r->in.xids[i];
280 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
281 r->in.domain_sid);
282 if (!NT_STATUS_IS_OK(status)) {
283 TALLOC_FREE(maps);
284 return status;
287 for (i=0; i<r->in.num_ids; i++) {
288 if (maps[i]->status == ID_MAPPED) {
289 r->out.xids[i] = maps[i]->xid;
290 sid_copy(&r->out.sids[i], maps[i]->sid);
291 } else {
292 r->out.sids[i] = (struct dom_sid) { 0 };
296 TALLOC_FREE(maps);
298 return NT_STATUS_OK;
301 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
303 struct unixid xid;
304 NTSTATUS status;
306 status = idmap_allocate_uid(&xid);
307 if (!NT_STATUS_IS_OK(status)) {
308 return status;
310 *r->out.uid = xid.id;
311 return NT_STATUS_OK;
314 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
316 struct unixid xid;
317 NTSTATUS status;
319 status = idmap_allocate_gid(&xid);
320 if (!NT_STATUS_IS_OK(status)) {
321 return status;
323 *r->out.gid = xid.id;
324 return NT_STATUS_OK;
327 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
329 struct idmap_domain *domain;
330 NTSTATUS status;
332 domain = idmap_find_domain(r->in.info->domain_name);
333 if ((domain == NULL) || (domain->query_user == NULL)) {
334 return NT_STATUS_REQUEST_NOT_ACCEPTED;
337 status = domain->query_user(domain, r->in.info);
338 return status;
341 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
342 struct wbint_LookupUserAliases *r)
344 struct winbindd_domain *domain = wb_child_domain();
345 NTSTATUS status;
347 if (domain == NULL) {
348 return NT_STATUS_REQUEST_NOT_ACCEPTED;
351 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
352 r->in.sids->num_sids,
353 r->in.sids->sids,
354 &r->out.rids->num_rids,
355 &r->out.rids->rids);
356 reset_cm_connection_on_error(domain, NULL, status);
357 return status;
360 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
361 struct wbint_LookupUserGroups *r)
363 struct winbindd_domain *domain = wb_child_domain();
364 NTSTATUS status;
366 if (domain == NULL) {
367 return NT_STATUS_REQUEST_NOT_ACCEPTED;
370 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
371 &r->out.sids->num_sids,
372 &r->out.sids->sids);
373 reset_cm_connection_on_error(domain, NULL, status);
374 return status;
377 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
378 struct wbint_QuerySequenceNumber *r)
380 struct winbindd_domain *domain = wb_child_domain();
381 NTSTATUS status;
383 if (domain == NULL) {
384 return NT_STATUS_REQUEST_NOT_ACCEPTED;
387 status = wb_cache_sequence_number(domain, r->out.sequence);
388 reset_cm_connection_on_error(domain, NULL, status);
389 return status;
392 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
393 struct wbint_LookupGroupMembers *r)
395 struct winbindd_domain *domain = wb_child_domain();
396 uint32_t i, num_names;
397 struct dom_sid *sid_mem;
398 char **names;
399 uint32_t *name_types;
400 NTSTATUS status;
402 if (domain == NULL) {
403 return NT_STATUS_REQUEST_NOT_ACCEPTED;
406 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
407 r->in.type, &num_names, &sid_mem,
408 &names, &name_types);
409 reset_cm_connection_on_error(domain, NULL, status);
410 if (!NT_STATUS_IS_OK(status)) {
411 return status;
414 r->out.members->num_principals = num_names;
415 r->out.members->principals = talloc_array(
416 r->out.members, struct wbint_Principal, num_names);
417 if (r->out.members->principals == NULL) {
418 return NT_STATUS_NO_MEMORY;
421 for (i=0; i<num_names; i++) {
422 struct wbint_Principal *m = &r->out.members->principals[i];
423 sid_copy(&m->sid, &sid_mem[i]);
424 m->name = talloc_move(r->out.members->principals, &names[i]);
425 m->type = (enum lsa_SidType)name_types[i];
428 return NT_STATUS_OK;
431 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
432 struct wbint_QueryGroupList *r)
434 TALLOC_CTX *frame = NULL;
435 struct winbindd_domain *domain = wb_child_domain();
436 uint32_t i;
437 uint32_t num_local_groups = 0;
438 struct wb_acct_info *local_groups = NULL;
439 uint32_t num_dom_groups = 0;
440 struct wb_acct_info *dom_groups = NULL;
441 uint32_t ti = 0;
442 uint64_t num_total = 0;
443 struct wbint_Principal *result;
444 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
445 bool include_local_groups = false;
447 if (domain == NULL) {
448 return NT_STATUS_REQUEST_NOT_ACCEPTED;
451 frame = talloc_stackframe();
453 switch (lp_server_role()) {
454 case ROLE_ACTIVE_DIRECTORY_DC:
455 if (domain->internal) {
457 * we want to include local groups
458 * for BUILTIN and WORKGROUP
460 include_local_groups = true;
462 break;
463 default:
465 * We might include local groups in more
466 * setups later, but that requires more work
467 * elsewhere.
469 break;
472 if (include_local_groups) {
473 status = wb_cache_enum_local_groups(domain, frame,
474 &num_local_groups,
475 &local_groups);
476 reset_cm_connection_on_error(domain, NULL, status);
477 if (!NT_STATUS_IS_OK(status)) {
478 goto out;
482 status = wb_cache_enum_dom_groups(domain, frame,
483 &num_dom_groups,
484 &dom_groups);
485 reset_cm_connection_on_error(domain, NULL, status);
486 if (!NT_STATUS_IS_OK(status)) {
487 goto out;
490 num_total = num_local_groups + num_dom_groups;
491 if (num_total > UINT32_MAX) {
492 status = NT_STATUS_INTERNAL_ERROR;
493 goto out;
496 result = talloc_array(frame, struct wbint_Principal, num_total);
497 if (result == NULL) {
498 status = NT_STATUS_NO_MEMORY;
499 goto out;
502 for (i = 0; i < num_local_groups; i++) {
503 struct wb_acct_info *lg = &local_groups[i];
504 struct wbint_Principal *rg = &result[ti++];
506 sid_compose(&rg->sid, &domain->sid, lg->rid);
507 rg->type = SID_NAME_ALIAS;
508 rg->name = talloc_strdup(result, lg->acct_name);
509 if (rg->name == NULL) {
510 status = NT_STATUS_NO_MEMORY;
511 goto out;
514 num_local_groups = 0;
516 for (i = 0; i < num_dom_groups; i++) {
517 struct wb_acct_info *dg = &dom_groups[i];
518 struct wbint_Principal *rg = &result[ti++];
520 sid_compose(&rg->sid, &domain->sid, dg->rid);
521 rg->type = SID_NAME_DOM_GRP;
522 rg->name = talloc_strdup(result, dg->acct_name);
523 if (rg->name == NULL) {
524 status = NT_STATUS_NO_MEMORY;
525 goto out;
528 num_dom_groups = 0;
530 r->out.groups->num_principals = ti;
531 r->out.groups->principals = talloc_move(r->out.groups, &result);
533 status = NT_STATUS_OK;
534 out:
535 TALLOC_FREE(frame);
536 return status;
539 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
540 struct wbint_QueryUserRidList *r)
542 struct winbindd_domain *domain = wb_child_domain();
543 NTSTATUS status;
545 if (domain == NULL) {
546 return NT_STATUS_REQUEST_NOT_ACCEPTED;
550 * Right now this is overkill. We should add a backend call
551 * just querying the rids.
554 status = wb_cache_query_user_list(domain, p->mem_ctx,
555 &r->out.rids->rids);
556 reset_cm_connection_on_error(domain, NULL, status);
558 if (!NT_STATUS_IS_OK(status)) {
559 return status;
562 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
564 return NT_STATUS_OK;
567 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
569 struct winbindd_domain *domain = wb_child_domain();
570 struct rpc_pipe_client *netlogon_pipe;
571 struct netr_DsRGetDCNameInfo *dc_info;
572 NTSTATUS status;
573 WERROR werr;
574 unsigned int orig_timeout;
575 struct dcerpc_binding_handle *b;
576 bool retry = false;
577 bool try_dsrgetdcname = false;
579 if (domain == NULL) {
580 return dsgetdcname(p->mem_ctx, global_messaging_context(),
581 r->in.domain_name, r->in.domain_guid,
582 r->in.site_name ? r->in.site_name : "",
583 r->in.flags,
584 r->out.dc_info);
587 if (domain->active_directory) {
588 try_dsrgetdcname = true;
591 reconnect:
592 status = cm_connect_netlogon(domain, &netlogon_pipe);
594 reset_cm_connection_on_error(domain, NULL, status);
595 if (!NT_STATUS_IS_OK(status)) {
596 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
597 return status;
600 b = netlogon_pipe->binding_handle;
602 /* This call can take a long time - allow the server to time out.
603 35 seconds should do it. */
605 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
607 if (try_dsrgetdcname) {
608 status = dcerpc_netr_DsRGetDCName(b,
609 p->mem_ctx, domain->dcname,
610 r->in.domain_name, NULL, r->in.domain_guid,
611 r->in.flags, r->out.dc_info, &werr);
612 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
613 goto done;
615 if (!retry &&
616 reset_cm_connection_on_error(domain, NULL, status))
618 retry = true;
619 goto reconnect;
621 try_dsrgetdcname = false;
622 retry = false;
626 * Fallback to less capable methods
629 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
630 if (dc_info == NULL) {
631 status = NT_STATUS_NO_MEMORY;
632 goto done;
635 if (r->in.flags & DS_PDC_REQUIRED) {
636 status = dcerpc_netr_GetDcName(b,
637 p->mem_ctx, domain->dcname,
638 r->in.domain_name, &dc_info->dc_unc, &werr);
639 } else {
640 status = dcerpc_netr_GetAnyDCName(b,
641 p->mem_ctx, domain->dcname,
642 r->in.domain_name, &dc_info->dc_unc, &werr);
645 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
646 retry = true;
647 goto reconnect;
649 if (!NT_STATUS_IS_OK(status)) {
650 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
651 nt_errstr(status)));
652 goto done;
654 if (!W_ERROR_IS_OK(werr)) {
655 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
656 win_errstr(werr)));
657 status = werror_to_ntstatus(werr);
658 goto done;
661 *r->out.dc_info = dc_info;
662 status = NT_STATUS_OK;
664 done:
665 /* And restore our original timeout. */
666 rpccli_set_timeout(netlogon_pipe, orig_timeout);
668 return status;
671 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
673 struct winbindd_domain *domain = wb_child_domain();
674 char *domain_name;
675 char **names;
676 enum lsa_SidType *types;
677 struct wbint_Principal *result;
678 NTSTATUS status;
679 uint32_t i;
681 if (domain == NULL) {
682 return NT_STATUS_REQUEST_NOT_ACCEPTED;
685 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
686 r->in.rids->rids, r->in.rids->num_rids,
687 &domain_name, &names, &types);
688 reset_cm_connection_on_error(domain, NULL, status);
689 if (!NT_STATUS_IS_OK(status) &&
690 !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
691 return status;
694 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
696 result = talloc_array(p->mem_ctx, struct wbint_Principal,
697 r->in.rids->num_rids);
698 if (result == NULL) {
699 return NT_STATUS_NO_MEMORY;
702 for (i=0; i<r->in.rids->num_rids; i++) {
703 sid_compose(&result[i].sid, r->in.domain_sid,
704 r->in.rids->rids[i]);
705 result[i].type = types[i];
706 result[i].name = talloc_move(result, &names[i]);
708 TALLOC_FREE(types);
709 TALLOC_FREE(names);
711 r->out.names->num_principals = r->in.rids->num_rids;
712 r->out.names->principals = result;
713 return NT_STATUS_OK;
716 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
717 struct wbint_CheckMachineAccount *r)
719 struct winbindd_domain *domain;
720 int num_retries = 0;
721 NTSTATUS status;
723 domain = wb_child_domain();
724 if (domain == NULL) {
725 return NT_STATUS_REQUEST_NOT_ACCEPTED;
728 again:
729 invalidate_cm_connection(domain);
730 domain->conn.netlogon_force_reauth = true;
733 struct rpc_pipe_client *netlogon_pipe = NULL;
734 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
735 status = cm_connect_netlogon_secure(domain,
736 &netlogon_pipe,
737 &netlogon_creds_ctx);
740 /* There is a race condition between fetching the trust account
741 password and the periodic machine password change. So it's
742 possible that the trust account password has been changed on us.
743 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
745 #define MAX_RETRIES 3
747 if ((num_retries < MAX_RETRIES)
748 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
749 num_retries++;
750 goto again;
753 if (!NT_STATUS_IS_OK(status)) {
754 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
755 goto done;
758 /* Pass back result code - zero for success, other values for
759 specific failures. */
761 DEBUG(3,("domain %s secret is %s\n", domain->name,
762 NT_STATUS_IS_OK(status) ? "good" : "bad"));
764 done:
765 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
766 ("Checking the trust account password for domain %s returned %s\n",
767 domain->name, nt_errstr(status)));
769 return status;
772 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
773 struct wbint_ChangeMachineAccount *r)
775 struct messaging_context *msg_ctx = global_messaging_context();
776 struct winbindd_domain *domain;
777 NTSTATUS status;
778 struct rpc_pipe_client *netlogon_pipe = NULL;
779 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
781 domain = wb_child_domain();
782 if (domain == NULL) {
783 return NT_STATUS_REQUEST_NOT_ACCEPTED;
786 status = cm_connect_netlogon_secure(domain,
787 &netlogon_pipe,
788 &netlogon_creds_ctx);
789 if (!NT_STATUS_IS_OK(status)) {
790 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
791 goto done;
794 status = trust_pw_change(netlogon_creds_ctx,
795 msg_ctx,
796 netlogon_pipe->binding_handle,
797 domain->name,
798 domain->dcname,
799 true); /* force */
801 /* Pass back result code - zero for success, other values for
802 specific failures. */
804 DEBUG(3,("domain %s secret %s\n", domain->name,
805 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
807 done:
808 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
809 ("Changing the trust account password for domain %s returned %s\n",
810 domain->name, nt_errstr(status)));
812 return status;
815 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
817 NTSTATUS status;
818 struct winbindd_domain *domain;
819 struct rpc_pipe_client *netlogon_pipe;
820 union netr_CONTROL_QUERY_INFORMATION info;
821 WERROR werr;
822 fstring logon_server;
823 struct dcerpc_binding_handle *b;
824 bool retry = false;
826 domain = wb_child_domain();
827 if (domain == NULL) {
828 return NT_STATUS_REQUEST_NOT_ACCEPTED;
831 reconnect:
832 status = cm_connect_netlogon(domain, &netlogon_pipe);
833 reset_cm_connection_on_error(domain, NULL, status);
834 if (!NT_STATUS_IS_OK(status)) {
835 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
836 nt_errstr(status)));
837 return status;
840 b = netlogon_pipe->binding_handle;
842 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
843 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
844 if (*r->out.dcname == NULL) {
845 DEBUG(2, ("Could not allocate memory\n"));
846 return NT_STATUS_NO_MEMORY;
850 * This provokes a WERR_NOT_SUPPORTED error message. This is
851 * documented in the wspp docs. I could not get a successful
852 * call to work, but the main point here is testing that the
853 * netlogon pipe works.
855 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
856 logon_server, NETLOGON_CONTROL_QUERY,
857 2, &info, &werr);
859 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
860 retry = true;
861 goto reconnect;
864 if (!NT_STATUS_IS_OK(status)) {
865 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
866 nt_errstr(status)));
867 return status;
870 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
871 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
872 "WERR_NOT_SUPPORTED\n",
873 win_errstr(werr)));
874 return werror_to_ntstatus(werr);
877 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
878 return NT_STATUS_OK;
881 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
882 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
884 struct winbindd_domain *domain;
885 NTSTATUS status;
886 struct rpc_pipe_client *netlogon_pipe = NULL;
887 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
888 struct dcerpc_binding_handle *b = NULL;
889 bool retry = false;
891 domain = wb_child_domain();
892 if (domain == NULL) {
893 return NT_STATUS_REQUEST_NOT_ACCEPTED;
896 reconnect:
897 status = cm_connect_netlogon_secure(domain,
898 &netlogon_pipe,
899 &netlogon_creds_ctx);
900 if (!NT_STATUS_IS_OK(status)) {
901 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
902 goto done;
905 b = netlogon_pipe->binding_handle;
907 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
908 netlogon_pipe->binding_handle,
909 r->in.site_name,
910 r->in.dns_ttl,
911 r->in.dns_names);
913 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
914 retry = true;
915 goto reconnect;
918 /* Pass back result code - zero for success, other values for
919 specific failures. */
921 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
922 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
924 done:
925 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
926 ("Update of DNS records via RW DC %s returned %s\n",
927 domain->name, nt_errstr(status)));
929 return status;
932 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
933 struct winbind_SamLogon *r)
935 struct dcesrv_call_state *dce_call = p->dce_call;
936 struct dcesrv_connection *dcesrv_conn = dce_call->conn;
937 const struct tsocket_address *local_address =
938 dcesrv_connection_get_local_address(dcesrv_conn);
939 const struct tsocket_address *remote_address =
940 dcesrv_connection_get_remote_address(dcesrv_conn);
941 struct winbindd_domain *domain;
942 NTSTATUS status;
943 struct netr_IdentityInfo *identity_info = NULL;
944 DATA_BLOB lm_response, nt_response;
945 DATA_BLOB challenge = data_blob_null;
946 uint32_t flags = 0;
947 uint16_t validation_level;
948 union netr_Validation *validation = NULL;
949 bool interactive = false;
952 * Make sure we start with authoritative=true,
953 * it will only set to false if we don't know the
954 * domain.
956 r->out.authoritative = true;
958 domain = wb_child_domain();
959 if (domain == NULL) {
960 return NT_STATUS_REQUEST_NOT_ACCEPTED;
963 switch (r->in.validation_level) {
964 case 3:
965 case 6:
966 break;
967 default:
968 return NT_STATUS_REQUEST_NOT_ACCEPTED;
971 switch (r->in.logon_level) {
972 case NetlogonInteractiveInformation:
973 case NetlogonServiceInformation:
974 case NetlogonInteractiveTransitiveInformation:
975 case NetlogonServiceTransitiveInformation:
976 if (r->in.logon.password == NULL) {
977 return NT_STATUS_REQUEST_NOT_ACCEPTED;
980 interactive = true;
981 identity_info = &r->in.logon.password->identity_info;
983 challenge = data_blob_null;
984 lm_response = data_blob_talloc(p->mem_ctx,
985 r->in.logon.password->lmpassword.hash,
986 sizeof(r->in.logon.password->lmpassword.hash));
987 nt_response = data_blob_talloc(p->mem_ctx,
988 r->in.logon.password->ntpassword.hash,
989 sizeof(r->in.logon.password->ntpassword.hash));
990 break;
992 case NetlogonNetworkInformation:
993 case NetlogonNetworkTransitiveInformation:
994 if (r->in.logon.network == NULL) {
995 return NT_STATUS_REQUEST_NOT_ACCEPTED;
998 interactive = false;
999 identity_info = &r->in.logon.network->identity_info;
1001 challenge = data_blob_talloc(p->mem_ctx,
1002 r->in.logon.network->challenge,
1004 lm_response = data_blob_talloc(p->mem_ctx,
1005 r->in.logon.network->lm.data,
1006 r->in.logon.network->lm.length);
1007 nt_response = data_blob_talloc(p->mem_ctx,
1008 r->in.logon.network->nt.data,
1009 r->in.logon.network->nt.length);
1010 break;
1012 case NetlogonGenericInformation:
1013 if (r->in.logon.generic == NULL) {
1014 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1017 identity_info = &r->in.logon.generic->identity_info;
1019 * Not implemented here...
1021 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1023 default:
1024 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1027 status = winbind_dual_SamLogon(domain, p->mem_ctx,
1028 interactive,
1029 identity_info->parameter_control,
1030 identity_info->account_name.string,
1031 identity_info->domain_name.string,
1032 identity_info->workstation.string,
1033 identity_info->logon_id,
1034 "SamLogon",
1036 challenge,
1037 lm_response, nt_response,
1038 remote_address,
1039 local_address,
1040 &r->out.authoritative,
1041 true, /* skip_sam */
1042 &flags,
1043 &validation_level,
1044 &validation);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 return status;
1048 switch (r->in.validation_level) {
1049 case 3:
1050 status = map_validation_to_info3(p->mem_ctx,
1051 validation_level,
1052 validation,
1053 &r->out.validation.sam3);
1054 TALLOC_FREE(validation);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 return status;
1058 return NT_STATUS_OK;
1059 case 6:
1060 status = map_validation_to_info6(p->mem_ctx,
1061 validation_level,
1062 validation,
1063 &r->out.validation.sam6);
1064 TALLOC_FREE(validation);
1065 if (!NT_STATUS_IS_OK(status)) {
1066 return status;
1068 return NT_STATUS_OK;
1071 smb_panic(__location__);
1072 return NT_STATUS_INTERNAL_ERROR;
1075 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1076 struct winbindd_domain *domain,
1077 struct winbind_LogonControl *r)
1079 NTSTATUS status;
1080 struct rpc_pipe_client *netlogon_pipe = NULL;
1081 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1082 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1083 WERROR check_result = WERR_INTERNAL_ERROR;
1085 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1086 if (info2 == NULL) {
1087 return WERR_NOT_ENOUGH_MEMORY;
1090 if (domain->internal) {
1091 check_result = WERR_OK;
1092 goto check_return;
1096 * For now we just force a reconnect
1098 * TODO: take care of the optional '\dcname'
1100 invalidate_cm_connection(domain);
1101 domain->conn.netlogon_force_reauth = true;
1102 status = cm_connect_netlogon_secure(domain,
1103 &netlogon_pipe,
1104 &netlogon_creds_ctx);
1105 reset_cm_connection_on_error(domain, NULL, status);
1106 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1107 status = NT_STATUS_NO_LOGON_SERVERS;
1109 if (!NT_STATUS_IS_OK(status)) {
1110 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1111 __func__, domain->name, domain->alt_name,
1112 nt_errstr(status)));
1114 * Here we return a top level error!
1115 * This is different than TC_QUERY or TC_VERIFY.
1117 return ntstatus_to_werror(status);
1119 check_result = WERR_OK;
1121 check_return:
1122 info2->pdc_connection_status = WERR_OK;
1123 if (domain->dcname != NULL) {
1124 info2->flags |= NETLOGON_HAS_IP;
1125 info2->flags |= NETLOGON_HAS_TIMESERV;
1126 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1127 domain->dcname);
1128 if (info2->trusted_dc_name == NULL) {
1129 return WERR_NOT_ENOUGH_MEMORY;
1131 } else {
1132 info2->trusted_dc_name = talloc_strdup(info2, "");
1133 if (info2->trusted_dc_name == NULL) {
1134 return WERR_NOT_ENOUGH_MEMORY;
1137 info2->tc_connection_status = check_result;
1139 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1140 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1141 "pdc_connection[%s] tc_connection[%s]\n",
1142 __func__, domain->name, domain->alt_name,
1143 domain->dcname,
1144 win_errstr(info2->pdc_connection_status),
1145 win_errstr(info2->tc_connection_status)));
1148 r->out.query->info2 = info2;
1150 DEBUG(5, ("%s: succeeded.\n", __func__));
1151 return WERR_OK;
1154 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1155 struct winbindd_domain *domain,
1156 struct winbind_LogonControl *r)
1158 NTSTATUS status;
1159 struct rpc_pipe_client *netlogon_pipe = NULL;
1160 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1161 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1162 WERROR check_result = WERR_INTERNAL_ERROR;
1164 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1165 if (info2 == NULL) {
1166 return WERR_NOT_ENOUGH_MEMORY;
1169 if (domain->internal) {
1170 check_result = WERR_OK;
1171 goto check_return;
1174 status = cm_connect_netlogon_secure(domain,
1175 &netlogon_pipe,
1176 &netlogon_creds_ctx);
1177 reset_cm_connection_on_error(domain, NULL, status);
1178 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1179 status = NT_STATUS_NO_LOGON_SERVERS;
1181 if (!NT_STATUS_IS_OK(status)) {
1182 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1183 nt_errstr(status)));
1184 check_result = ntstatus_to_werror(status);
1185 goto check_return;
1187 check_result = WERR_OK;
1189 check_return:
1190 info2->pdc_connection_status = WERR_OK;
1191 if (domain->dcname != NULL) {
1192 info2->flags |= NETLOGON_HAS_IP;
1193 info2->flags |= NETLOGON_HAS_TIMESERV;
1194 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1195 domain->dcname);
1196 if (info2->trusted_dc_name == NULL) {
1197 return WERR_NOT_ENOUGH_MEMORY;
1199 } else {
1200 info2->trusted_dc_name = talloc_strdup(info2, "");
1201 if (info2->trusted_dc_name == NULL) {
1202 return WERR_NOT_ENOUGH_MEMORY;
1205 info2->tc_connection_status = check_result;
1207 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1208 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1209 "pdc_connection[%s] tc_connection[%s]\n",
1210 __func__, domain->name, domain->alt_name,
1211 domain->dcname,
1212 win_errstr(info2->pdc_connection_status),
1213 win_errstr(info2->tc_connection_status)));
1216 r->out.query->info2 = info2;
1218 DEBUG(5, ("%s: succeeded.\n", __func__));
1219 return WERR_OK;
1222 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1223 struct winbindd_domain *domain,
1224 struct winbind_LogonControl *r)
1226 TALLOC_CTX *frame = talloc_stackframe();
1227 NTSTATUS status;
1228 NTSTATUS result;
1229 struct lsa_String trusted_domain_name = {};
1230 struct lsa_StringLarge trusted_domain_name_l = {};
1231 struct rpc_pipe_client *local_lsa_pipe = NULL;
1232 struct policy_handle local_lsa_policy = {};
1233 struct dcerpc_binding_handle *local_lsa = NULL;
1234 struct rpc_pipe_client *netlogon_pipe = NULL;
1235 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1236 struct cli_credentials *creds = NULL;
1237 struct samr_Password *cur_nt_hash = NULL;
1238 uint32_t trust_attributes = 0;
1239 struct samr_Password new_owf_password = {};
1240 int cmp_new = -1;
1241 struct samr_Password old_owf_password = {};
1242 int cmp_old = -1;
1243 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1244 bool fetch_fti = false;
1245 struct lsa_ForestTrustInformation *new_fti = NULL;
1246 struct netr_TrustInfo *trust_info = NULL;
1247 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1248 struct dcerpc_binding_handle *b = NULL;
1249 WERROR check_result = WERR_INTERNAL_ERROR;
1250 WERROR verify_result = WERR_INTERNAL_ERROR;
1251 bool retry = false;
1253 trusted_domain_name.string = domain->name;
1254 trusted_domain_name_l.string = domain->name;
1256 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1257 if (info2 == NULL) {
1258 TALLOC_FREE(frame);
1259 return WERR_NOT_ENOUGH_MEMORY;
1262 if (domain->internal) {
1263 check_result = WERR_OK;
1264 goto check_return;
1267 status = pdb_get_trust_credentials(domain->name,
1268 domain->alt_name,
1269 frame,
1270 &creds);
1271 if (NT_STATUS_IS_OK(status)) {
1272 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1273 TALLOC_FREE(creds);
1276 if (!domain->primary) {
1277 union lsa_TrustedDomainInfo *tdi = NULL;
1279 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1280 &local_lsa_policy);
1281 if (!NT_STATUS_IS_OK(status)) {
1282 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1283 __location__, __func__, nt_errstr(status)));
1284 TALLOC_FREE(frame);
1285 return WERR_INTERNAL_ERROR;
1287 local_lsa = local_lsa_pipe->binding_handle;
1289 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1290 &local_lsa_policy,
1291 &trusted_domain_name,
1292 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1293 &tdi, &result);
1294 if (!NT_STATUS_IS_OK(status)) {
1295 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1296 __location__, __func__, domain->name, nt_errstr(status)));
1297 TALLOC_FREE(frame);
1298 return WERR_INTERNAL_ERROR;
1300 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1301 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1302 __location__, __func__, domain->name));
1303 TALLOC_FREE(frame);
1304 return WERR_NO_SUCH_DOMAIN;
1306 if (!NT_STATUS_IS_OK(result)) {
1307 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1308 __location__, __func__, domain->name, nt_errstr(result)));
1309 TALLOC_FREE(frame);
1310 return WERR_INTERNAL_ERROR;
1312 if (tdi == NULL) {
1313 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1314 "returned no trusted domain information\n",
1315 __location__, __func__));
1316 TALLOC_FREE(frame);
1317 return WERR_INTERNAL_ERROR;
1320 local_tdo = &tdi->info_ex;
1321 trust_attributes = local_tdo->trust_attributes;
1324 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1325 struct lsa_ForestTrustInformation *old_fti = NULL;
1327 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1328 &local_lsa_policy,
1329 &trusted_domain_name,
1330 LSA_FOREST_TRUST_DOMAIN_INFO,
1331 &old_fti, &result);
1332 if (!NT_STATUS_IS_OK(status)) {
1333 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1334 __location__, __func__, domain->name, nt_errstr(status)));
1335 TALLOC_FREE(frame);
1336 return WERR_INTERNAL_ERROR;
1338 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1339 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1340 __func__, domain->name));
1341 old_fti = NULL;
1342 fetch_fti = true;
1343 result = NT_STATUS_OK;
1345 if (!NT_STATUS_IS_OK(result)) {
1346 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1347 __location__, __func__, domain->name, nt_errstr(result)));
1348 TALLOC_FREE(frame);
1349 return WERR_INTERNAL_ERROR;
1352 TALLOC_FREE(old_fti);
1355 reconnect:
1356 status = cm_connect_netlogon_secure(domain,
1357 &netlogon_pipe,
1358 &netlogon_creds_ctx);
1359 reset_cm_connection_on_error(domain, NULL, status);
1360 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1361 status = NT_STATUS_NO_LOGON_SERVERS;
1363 if (!NT_STATUS_IS_OK(status)) {
1364 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1365 nt_errstr(status)));
1366 check_result = ntstatus_to_werror(status);
1367 goto check_return;
1369 check_result = WERR_OK;
1370 b = netlogon_pipe->binding_handle;
1372 if (cur_nt_hash == NULL) {
1373 verify_result = WERR_NO_TRUST_LSA_SECRET;
1374 goto verify_return;
1377 if (fetch_fti) {
1378 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1379 b, frame,
1380 &new_fti);
1381 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1382 status = NT_STATUS_NOT_SUPPORTED;
1384 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1385 new_fti = NULL;
1386 status = NT_STATUS_OK;
1388 if (!NT_STATUS_IS_OK(status)) {
1389 if (!retry &&
1390 reset_cm_connection_on_error(domain, b, status))
1392 retry = true;
1393 goto reconnect;
1395 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1396 "failed: %s\n",
1397 domain->name, nt_errstr(status)));
1398 check_result = ntstatus_to_werror(status);
1399 goto check_return;
1403 if (new_fti != NULL) {
1404 struct lsa_ForestTrustInformation old_fti = {};
1405 struct lsa_ForestTrustInformation *merged_fti = NULL;
1406 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1408 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1409 &old_fti, new_fti,
1410 &merged_fti);
1411 if (!NT_STATUS_IS_OK(status)) {
1412 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1413 __location__, __func__,
1414 domain->name, nt_errstr(status)));
1415 TALLOC_FREE(frame);
1416 return ntstatus_to_werror(status);
1419 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1420 &local_lsa_policy,
1421 &trusted_domain_name_l,
1422 LSA_FOREST_TRUST_DOMAIN_INFO,
1423 merged_fti,
1424 0, /* check_only=0 => store it! */
1425 &collision_info,
1426 &result);
1427 if (!NT_STATUS_IS_OK(status)) {
1428 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1429 __location__, __func__, domain->name, nt_errstr(status)));
1430 TALLOC_FREE(frame);
1431 return WERR_INTERNAL_ERROR;
1433 if (!NT_STATUS_IS_OK(result)) {
1434 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1435 __location__, __func__, domain->name, nt_errstr(result)));
1436 TALLOC_FREE(frame);
1437 return ntstatus_to_werror(result);
1441 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1442 b, frame,
1443 &new_owf_password,
1444 &old_owf_password,
1445 &trust_info);
1446 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1447 status = NT_STATUS_NOT_SUPPORTED;
1449 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1450 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1451 nt_errstr(status)));
1452 verify_result = WERR_OK;
1453 goto verify_return;
1455 if (!NT_STATUS_IS_OK(status)) {
1456 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1457 retry = true;
1458 goto reconnect;
1460 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1461 nt_errstr(status)));
1463 if (!dcerpc_binding_handle_is_connected(b)) {
1464 check_result = ntstatus_to_werror(status);
1465 goto check_return;
1466 } else {
1467 verify_result = ntstatus_to_werror(status);
1468 goto verify_return;
1472 if (trust_info != NULL && trust_info->count >= 1) {
1473 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1475 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1476 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1477 goto verify_return;
1481 cmp_new = memcmp(new_owf_password.hash,
1482 cur_nt_hash->hash,
1483 sizeof(cur_nt_hash->hash));
1484 cmp_old = memcmp(old_owf_password.hash,
1485 cur_nt_hash->hash,
1486 sizeof(cur_nt_hash->hash));
1487 if (cmp_new != 0 && cmp_old != 0) {
1488 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1489 "any password known to dcname[%s]\n",
1490 __func__, domain->name, domain->alt_name,
1491 domain->dcname));
1492 verify_result = WERR_WRONG_PASSWORD;
1493 goto verify_return;
1496 if (cmp_new != 0) {
1497 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1498 "against the old password known to dcname[%s]\n",
1499 __func__, domain->name, domain->alt_name,
1500 domain->dcname));
1503 verify_result = WERR_OK;
1504 goto verify_return;
1506 check_return:
1507 verify_result = check_result;
1508 verify_return:
1509 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1510 info2->pdc_connection_status = verify_result;
1511 if (domain->dcname != NULL) {
1512 info2->flags |= NETLOGON_HAS_IP;
1513 info2->flags |= NETLOGON_HAS_TIMESERV;
1514 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1515 domain->dcname);
1516 if (info2->trusted_dc_name == NULL) {
1517 TALLOC_FREE(frame);
1518 return WERR_NOT_ENOUGH_MEMORY;
1520 } else {
1521 info2->trusted_dc_name = talloc_strdup(info2, "");
1522 if (info2->trusted_dc_name == NULL) {
1523 TALLOC_FREE(frame);
1524 return WERR_NOT_ENOUGH_MEMORY;
1527 info2->tc_connection_status = check_result;
1529 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1530 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1531 "pdc_connection[%s] tc_connection[%s]\n",
1532 __func__, domain->name, domain->alt_name,
1533 domain->dcname,
1534 win_errstr(info2->pdc_connection_status),
1535 win_errstr(info2->tc_connection_status)));
1538 r->out.query->info2 = info2;
1540 DEBUG(5, ("%s: succeeded.\n", __func__));
1541 TALLOC_FREE(frame);
1542 return WERR_OK;
1545 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1546 struct winbindd_domain *domain,
1547 struct winbind_LogonControl *r)
1549 struct messaging_context *msg_ctx = global_messaging_context();
1550 NTSTATUS status;
1551 struct rpc_pipe_client *netlogon_pipe = NULL;
1552 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1553 struct cli_credentials *creds = NULL;
1554 struct samr_Password *cur_nt_hash = NULL;
1555 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1556 struct dcerpc_binding_handle *b;
1557 WERROR change_result = WERR_OK;
1558 bool retry = false;
1560 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1561 if (info1 == NULL) {
1562 return WERR_NOT_ENOUGH_MEMORY;
1565 if (domain->internal) {
1566 return WERR_NOT_SUPPORTED;
1569 status = pdb_get_trust_credentials(domain->name,
1570 domain->alt_name,
1571 p->mem_ctx,
1572 &creds);
1573 if (NT_STATUS_IS_OK(status)) {
1574 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1575 TALLOC_FREE(creds);
1578 reconnect:
1579 status = cm_connect_netlogon_secure(domain,
1580 &netlogon_pipe,
1581 &netlogon_creds_ctx);
1582 reset_cm_connection_on_error(domain, NULL, status);
1583 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1584 status = NT_STATUS_NO_LOGON_SERVERS;
1586 if (!NT_STATUS_IS_OK(status)) {
1587 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1588 __func__, domain->name, domain->alt_name,
1589 nt_errstr(status)));
1591 * Here we return a top level error!
1592 * This is different than TC_QUERY or TC_VERIFY.
1594 return ntstatus_to_werror(status);
1596 b = netlogon_pipe->binding_handle;
1598 if (cur_nt_hash == NULL) {
1599 change_result = WERR_NO_TRUST_LSA_SECRET;
1600 goto change_return;
1602 TALLOC_FREE(cur_nt_hash);
1604 status = trust_pw_change(netlogon_creds_ctx,
1605 msg_ctx, b, domain->name,
1606 domain->dcname,
1607 true); /* force */
1608 if (!NT_STATUS_IS_OK(status)) {
1609 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1610 retry = true;
1611 goto reconnect;
1614 DEBUG(1, ("trust_pw_change(%s): %s\n",
1615 domain->name, nt_errstr(status)));
1617 change_result = ntstatus_to_werror(status);
1618 goto change_return;
1621 change_result = WERR_OK;
1623 change_return:
1624 info1->pdc_connection_status = change_result;
1626 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1627 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1628 "pdc_connection[%s]\n",
1629 __func__, domain->name, domain->alt_name,
1630 domain->dcname,
1631 win_errstr(info1->pdc_connection_status)));
1634 r->out.query->info1 = info1;
1636 DEBUG(5, ("%s: succeeded.\n", __func__));
1637 return WERR_OK;
1640 WERROR _winbind_LogonControl(struct pipes_struct *p,
1641 struct winbind_LogonControl *r)
1643 struct winbindd_domain *domain;
1645 domain = wb_child_domain();
1646 if (domain == NULL) {
1647 return WERR_NO_SUCH_DOMAIN;
1650 switch (r->in.function_code) {
1651 case NETLOGON_CONTROL_REDISCOVER:
1652 if (r->in.level != 2) {
1653 return WERR_INVALID_PARAMETER;
1655 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1656 case NETLOGON_CONTROL_TC_QUERY:
1657 if (r->in.level != 2) {
1658 return WERR_INVALID_PARAMETER;
1660 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1661 case NETLOGON_CONTROL_TC_VERIFY:
1662 if (r->in.level != 2) {
1663 return WERR_INVALID_PARAMETER;
1665 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1666 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1667 if (r->in.level != 1) {
1668 return WERR_INVALID_PARAMETER;
1670 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1671 default:
1672 break;
1675 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1676 __func__, r->in.function_code));
1677 return WERR_NOT_SUPPORTED;
1680 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1681 struct winbind_GetForestTrustInformation *r)
1683 TALLOC_CTX *frame = talloc_stackframe();
1684 NTSTATUS status, result;
1685 struct winbindd_domain *domain;
1686 struct rpc_pipe_client *netlogon_pipe = NULL;
1687 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1688 struct dcerpc_binding_handle *b;
1689 bool retry = false;
1690 struct lsa_String trusted_domain_name = {};
1691 struct lsa_StringLarge trusted_domain_name_l = {};
1692 union lsa_TrustedDomainInfo *tdi = NULL;
1693 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1694 struct lsa_ForestTrustInformation _old_fti = {};
1695 struct lsa_ForestTrustInformation *old_fti = NULL;
1696 struct lsa_ForestTrustInformation *new_fti = NULL;
1697 struct lsa_ForestTrustInformation *merged_fti = NULL;
1698 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1699 bool update_fti = false;
1700 struct rpc_pipe_client *local_lsa_pipe;
1701 struct policy_handle local_lsa_policy;
1702 struct dcerpc_binding_handle *local_lsa = NULL;
1704 domain = wb_child_domain();
1705 if (domain == NULL) {
1706 TALLOC_FREE(frame);
1707 return WERR_NO_SUCH_DOMAIN;
1711 * checking for domain->internal and domain->primary
1712 * makes sure we only do some work when running as DC.
1715 if (domain->internal) {
1716 TALLOC_FREE(frame);
1717 return WERR_NO_SUCH_DOMAIN;
1720 if (domain->primary) {
1721 TALLOC_FREE(frame);
1722 return WERR_NO_SUCH_DOMAIN;
1725 trusted_domain_name.string = domain->name;
1726 trusted_domain_name_l.string = domain->name;
1728 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1729 &local_lsa_policy);
1730 if (!NT_STATUS_IS_OK(status)) {
1731 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1732 __location__, __func__, nt_errstr(status)));
1733 TALLOC_FREE(frame);
1734 return WERR_INTERNAL_ERROR;
1736 local_lsa = local_lsa_pipe->binding_handle;
1738 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1739 &local_lsa_policy,
1740 &trusted_domain_name,
1741 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1742 &tdi, &result);
1743 if (!NT_STATUS_IS_OK(status)) {
1744 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1745 __location__, __func__, domain->name, nt_errstr(status)));
1746 TALLOC_FREE(frame);
1747 return WERR_INTERNAL_ERROR;
1749 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1750 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1751 __location__, __func__, domain->name));
1752 TALLOC_FREE(frame);
1753 return WERR_NO_SUCH_DOMAIN;
1755 if (!NT_STATUS_IS_OK(result)) {
1756 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1757 __location__, __func__, domain->name, nt_errstr(result)));
1758 TALLOC_FREE(frame);
1759 return WERR_INTERNAL_ERROR;
1761 if (tdi == NULL) {
1762 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1763 "returned no trusted domain information\n",
1764 __location__, __func__));
1765 TALLOC_FREE(frame);
1766 return WERR_INTERNAL_ERROR;
1769 tdo = &tdi->info_ex;
1771 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1772 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1773 __func__, tdo->netbios_name.string,
1774 tdo->domain_name.string,
1775 (unsigned)tdo->trust_attributes));
1776 TALLOC_FREE(frame);
1777 return WERR_NO_SUCH_DOMAIN;
1780 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1781 TALLOC_FREE(frame);
1782 return WERR_INVALID_FLAGS;
1785 reconnect:
1786 status = cm_connect_netlogon_secure(domain,
1787 &netlogon_pipe,
1788 &netlogon_creds_ctx);
1789 reset_cm_connection_on_error(domain, NULL, status);
1790 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1791 status = NT_STATUS_NO_LOGON_SERVERS;
1793 if (!NT_STATUS_IS_OK(status)) {
1794 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1795 nt_errstr(status)));
1796 TALLOC_FREE(frame);
1797 return ntstatus_to_werror(status);
1799 b = netlogon_pipe->binding_handle;
1801 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1802 b, p->mem_ctx,
1803 &new_fti);
1804 if (!NT_STATUS_IS_OK(status)) {
1805 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1806 retry = true;
1807 goto reconnect;
1809 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1810 domain->name, nt_errstr(status)));
1811 TALLOC_FREE(frame);
1812 return ntstatus_to_werror(status);
1815 *r->out.forest_trust_info = new_fti;
1817 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1818 update_fti = true;
1821 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1822 &local_lsa_policy,
1823 &trusted_domain_name,
1824 LSA_FOREST_TRUST_DOMAIN_INFO,
1825 &old_fti, &result);
1826 if (!NT_STATUS_IS_OK(status)) {
1827 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1828 __location__, __func__, domain->name, nt_errstr(status)));
1829 TALLOC_FREE(frame);
1830 return WERR_INTERNAL_ERROR;
1832 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1833 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1834 __func__, domain->name));
1835 update_fti = true;
1836 old_fti = &_old_fti;
1837 result = NT_STATUS_OK;
1839 if (!NT_STATUS_IS_OK(result)) {
1840 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1841 __location__, __func__, domain->name, nt_errstr(result)));
1842 TALLOC_FREE(frame);
1843 return WERR_INTERNAL_ERROR;
1846 if (old_fti == NULL) {
1847 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1848 "returned success without returning forest trust information\n",
1849 __location__, __func__));
1850 TALLOC_FREE(frame);
1851 return WERR_INTERNAL_ERROR;
1854 if (!update_fti) {
1855 goto done;
1858 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1859 &merged_fti);
1860 if (!NT_STATUS_IS_OK(status)) {
1861 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1862 __location__, __func__, domain->name, nt_errstr(status)));
1863 TALLOC_FREE(frame);
1864 return ntstatus_to_werror(status);
1867 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1868 &local_lsa_policy,
1869 &trusted_domain_name_l,
1870 LSA_FOREST_TRUST_DOMAIN_INFO,
1871 merged_fti,
1872 0, /* check_only=0 => store it! */
1873 &collision_info,
1874 &result);
1875 if (!NT_STATUS_IS_OK(status)) {
1876 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1877 __location__, __func__, domain->name, nt_errstr(status)));
1878 TALLOC_FREE(frame);
1879 return WERR_INTERNAL_ERROR;
1881 if (!NT_STATUS_IS_OK(result)) {
1882 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1883 __location__, __func__, domain->name, nt_errstr(result)));
1884 TALLOC_FREE(frame);
1885 return ntstatus_to_werror(result);
1888 done:
1889 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1890 TALLOC_FREE(frame);
1891 return WERR_OK;
1894 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1896 struct winbindd_domain *domain;
1897 NTSTATUS status;
1898 struct rpc_pipe_client *netlogon_pipe;
1899 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1900 struct dcerpc_binding_handle *b = NULL;
1901 bool retry = false;
1903 DEBUG(5, ("_winbind_SendToSam received\n"));
1904 domain = wb_child_domain();
1905 if (domain == NULL) {
1906 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1909 reconnect:
1910 status = cm_connect_netlogon_secure(domain,
1911 &netlogon_pipe,
1912 &netlogon_creds_ctx);
1913 reset_cm_connection_on_error(domain, NULL, status);
1914 if (!NT_STATUS_IS_OK(status)) {
1915 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1916 return status;
1919 b = netlogon_pipe->binding_handle;
1921 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1923 &r->in.message);
1924 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1925 retry = true;
1926 goto reconnect;
1929 return status;
1932 NTSTATUS _wbint_ListTrustedDomains(struct pipes_struct *p,
1933 struct wbint_ListTrustedDomains *r)
1935 struct winbindd_domain *domain = wb_child_domain();
1936 uint32_t i, n;
1937 NTSTATUS result;
1938 struct netr_DomainTrustList trusts;
1939 struct netr_DomainTrustList *out = NULL;
1940 pid_t client_pid;
1942 if (domain == NULL) {
1943 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1946 /* Cut client_pid to 32bit */
1947 client_pid = r->in.client_pid;
1948 if ((uint64_t)client_pid != r->in.client_pid) {
1949 DBG_DEBUG("pid out of range\n");
1950 return NT_STATUS_INVALID_PARAMETER;
1953 DBG_NOTICE("[%s %"PRIu32"]: list trusted domains\n",
1954 r->in.client_name, client_pid);
1956 result = wb_cache_trusted_domains(domain, p->mem_ctx, &trusts);
1957 if (!NT_STATUS_IS_OK(result)) {
1958 DBG_NOTICE("wb_cache_trusted_domains returned %s\n",
1959 nt_errstr(result));
1960 return result;
1963 out = talloc_zero(p->mem_ctx, struct netr_DomainTrustList);
1964 if (out == NULL) {
1965 return NT_STATUS_NO_MEMORY;
1968 r->out.domains = out;
1970 for (i=0; i<trusts.count; i++) {
1971 if (trusts.array[i].sid == NULL) {
1972 continue;
1974 if (dom_sid_equal(trusts.array[i].sid, &global_sid_NULL)) {
1975 continue;
1978 n = out->count;
1979 out->array = talloc_realloc(out, out->array,
1980 struct netr_DomainTrust,
1981 n + 1);
1982 if (out->array == NULL) {
1983 return NT_STATUS_NO_MEMORY;
1985 out->count = n + 1;
1987 out->array[n].netbios_name = talloc_steal(
1988 out->array, trusts.array[i].netbios_name);
1989 if (out->array[n].netbios_name == NULL) {
1990 return NT_STATUS_NO_MEMORY;
1993 out->array[n].dns_name = talloc_steal(
1994 out->array, trusts.array[i].dns_name);
1995 if (out->array[n].dns_name == NULL) {
1996 return NT_STATUS_NO_MEMORY;
1999 out->array[n].sid = dom_sid_dup(out->array,
2000 trusts.array[i].sid);
2001 if (out->array[n].sid == NULL) {
2002 return NT_STATUS_NO_MEMORY;
2005 out->array[n].trust_flags = trusts.array[i].trust_flags;
2006 out->array[n].trust_type = trusts.array[i].trust_type;
2007 out->array[n].trust_attributes = trusts.array[i].trust_attributes;
2010 return NT_STATUS_OK;
2013 #include "librpc/gen_ndr/ndr_winbind_scompat.c"