winbindd: use reset_cm_connection_on_error() instead of dcerpc_binding_handle_is_conn...
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blobf7f01431c91f3cbe43545b6300f8d1560dcbb13d
1 /*
2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "ntdomain.h"
28 #include "librpc/gen_ndr/srv_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
31 #include "idmap.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
34 #include "passdb.h"
35 #include "../source4/dsdb/samdb/samdb.h"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
39 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
41 *r->out.out_data = r->in.in_data;
44 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
45 struct dcerpc_binding_handle *b,
46 NTSTATUS status)
48 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
49 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
50 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
51 invalidate_cm_connection(domain);
52 domain->conn.netlogon_force_reauth = true;
53 return true;
56 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
57 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
59 invalidate_cm_connection(domain);
60 /* We invalidated the connection. */
61 return true;
64 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
65 invalidate_cm_connection(domain);
66 return true;
69 return false;
72 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
74 struct winbindd_domain *domain = wb_child_domain();
75 char *dom_name;
76 char *name;
77 enum lsa_SidType type;
78 NTSTATUS status;
80 if (domain == NULL) {
81 return NT_STATUS_REQUEST_NOT_ACCEPTED;
84 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
85 &dom_name, &name, &type);
86 reset_cm_connection_on_error(domain, NULL, status);
87 if (!NT_STATUS_IS_OK(status)) {
88 return status;
91 *r->out.domain = dom_name;
92 *r->out.name = name;
93 *r->out.type = type;
94 return NT_STATUS_OK;
97 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
99 struct winbindd_domain *domain = wb_child_domain();
100 struct lsa_RefDomainList *domains = r->out.domains;
101 NTSTATUS status;
103 if (domain == NULL) {
104 return NT_STATUS_REQUEST_NOT_ACCEPTED;
108 * This breaks the winbindd_domain->methods abstraction: This
109 * is only called for remote domains, and both winbindd_msrpc
110 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
111 * done at the wbint RPC layer.
113 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
114 &domains, &r->out.names);
116 if (domains != NULL) {
117 r->out.domains = domains;
120 reset_cm_connection_on_error(domain, NULL, status);
121 return status;
124 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
126 struct winbindd_domain *domain = wb_child_domain();
127 NTSTATUS status;
129 if (domain == NULL) {
130 return NT_STATUS_REQUEST_NOT_ACCEPTED;
133 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
134 r->in.name, r->in.flags,
135 r->out.sid, r->out.type);
136 reset_cm_connection_on_error(domain, NULL, status);
137 return status;
140 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
141 struct wbint_Sids2UnixIDs *r)
143 uint32_t i;
145 struct lsa_DomainInfo *d;
146 struct wbint_TransID *ids;
147 uint32_t num_ids;
149 struct id_map **id_map_ptrs = NULL;
150 struct idmap_domain *dom;
151 NTSTATUS status = NT_STATUS_NO_MEMORY;
153 if (r->in.domains->count != 1) {
154 return NT_STATUS_INVALID_PARAMETER;
157 d = &r->in.domains->domains[0];
158 ids = r->in.ids->ids;
159 num_ids = r->in.ids->num_ids;
161 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
162 if (dom == NULL) {
163 DEBUG(10, ("idmap domain %s:%s not found\n",
164 d->name.string, sid_string_dbg(d->sid)));
166 for (i=0; i<num_ids; i++) {
168 ids[i].xid = (struct unixid) {
169 .id = UINT32_MAX,
170 .type = ID_TYPE_NOT_SPECIFIED
174 return NT_STATUS_OK;
177 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
178 if (id_map_ptrs == NULL) {
179 goto nomem;
183 * Convert the input data into a list of id_map structs
184 * suitable for handing in to the idmap sids_to_unixids
185 * method.
188 for (i=0; i<num_ids; i++) {
189 struct id_map *m = id_map_ptrs[i];
191 sid_compose(m->sid, d->sid, ids[i].rid);
192 m->status = ID_UNKNOWN;
193 m->xid = (struct unixid) { .type = ids[i].type };
196 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
198 if (!NT_STATUS_IS_OK(status)) {
199 DEBUG(10, ("sids_to_unixids returned %s\n",
200 nt_errstr(status)));
201 goto done;
205 * Extract the results for handing them back to the caller.
208 for (i=0; i<num_ids; i++) {
209 struct id_map *m = id_map_ptrs[i];
211 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
212 DBG_DEBUG("id %"PRIu32" is out of range "
213 "%"PRIu32"-%"PRIu32" for domain %s\n",
214 m->xid.id, dom->low_id, dom->high_id,
215 dom->name);
216 m->status = ID_UNMAPPED;
219 if (m->status == ID_MAPPED) {
220 ids[i].xid = m->xid;
221 } else {
222 ids[i].xid.id = UINT32_MAX;
223 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
227 goto done;
228 nomem:
229 status = NT_STATUS_NO_MEMORY;
230 done:
231 TALLOC_FREE(id_map_ptrs);
232 return status;
235 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
236 struct wbint_UnixIDs2Sids *r)
238 struct id_map **maps;
239 NTSTATUS status;
240 uint32_t i;
242 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
243 if (maps == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 for (i=0; i<r->in.num_ids; i++) {
248 maps[i]->status = ID_UNKNOWN;
249 maps[i]->xid = r->in.xids[i];
252 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
253 r->in.domain_sid);
254 if (!NT_STATUS_IS_OK(status)) {
255 TALLOC_FREE(maps);
256 return status;
259 for (i=0; i<r->in.num_ids; i++) {
260 r->out.xids[i] = maps[i]->xid;
261 sid_copy(&r->out.sids[i], maps[i]->sid);
264 TALLOC_FREE(maps);
266 return NT_STATUS_OK;
269 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
271 struct unixid xid;
272 NTSTATUS status;
274 status = idmap_allocate_uid(&xid);
275 if (!NT_STATUS_IS_OK(status)) {
276 return status;
278 *r->out.uid = xid.id;
279 return NT_STATUS_OK;
282 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
284 struct unixid xid;
285 NTSTATUS status;
287 status = idmap_allocate_gid(&xid);
288 if (!NT_STATUS_IS_OK(status)) {
289 return status;
291 *r->out.gid = xid.id;
292 return NT_STATUS_OK;
295 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
297 struct idmap_domain *domain;
298 NTSTATUS status;
300 domain = idmap_find_domain(r->in.info->domain_name);
301 if ((domain == NULL) || (domain->query_user == NULL)) {
302 return NT_STATUS_REQUEST_NOT_ACCEPTED;
305 status = domain->query_user(domain, r->in.info);
306 return status;
309 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
310 struct wbint_LookupUserAliases *r)
312 struct winbindd_domain *domain = wb_child_domain();
313 NTSTATUS status;
315 if (domain == NULL) {
316 return NT_STATUS_REQUEST_NOT_ACCEPTED;
319 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
320 r->in.sids->num_sids,
321 r->in.sids->sids,
322 &r->out.rids->num_rids,
323 &r->out.rids->rids);
324 reset_cm_connection_on_error(domain, NULL, status);
325 return status;
328 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
329 struct wbint_LookupUserGroups *r)
331 struct winbindd_domain *domain = wb_child_domain();
332 NTSTATUS status;
334 if (domain == NULL) {
335 return NT_STATUS_REQUEST_NOT_ACCEPTED;
338 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
339 &r->out.sids->num_sids,
340 &r->out.sids->sids);
341 reset_cm_connection_on_error(domain, NULL, status);
342 return status;
345 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
346 struct wbint_QuerySequenceNumber *r)
348 struct winbindd_domain *domain = wb_child_domain();
349 NTSTATUS status;
351 if (domain == NULL) {
352 return NT_STATUS_REQUEST_NOT_ACCEPTED;
355 status = wb_cache_sequence_number(domain, r->out.sequence);
356 reset_cm_connection_on_error(domain, NULL, status);
357 return status;
360 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
361 struct wbint_LookupGroupMembers *r)
363 struct winbindd_domain *domain = wb_child_domain();
364 uint32_t i, num_names;
365 struct dom_sid *sid_mem;
366 char **names;
367 uint32_t *name_types;
368 NTSTATUS status;
370 if (domain == NULL) {
371 return NT_STATUS_REQUEST_NOT_ACCEPTED;
374 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
375 r->in.type, &num_names, &sid_mem,
376 &names, &name_types);
377 reset_cm_connection_on_error(domain, NULL, status);
378 if (!NT_STATUS_IS_OK(status)) {
379 return status;
382 r->out.members->num_principals = num_names;
383 r->out.members->principals = talloc_array(
384 r->out.members, struct wbint_Principal, num_names);
385 if (r->out.members->principals == NULL) {
386 return NT_STATUS_NO_MEMORY;
389 for (i=0; i<num_names; i++) {
390 struct wbint_Principal *m = &r->out.members->principals[i];
391 sid_copy(&m->sid, &sid_mem[i]);
392 m->name = talloc_move(r->out.members->principals, &names[i]);
393 m->type = (enum lsa_SidType)name_types[i];
396 return NT_STATUS_OK;
399 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
400 struct wbint_QueryGroupList *r)
402 TALLOC_CTX *frame = NULL;
403 struct winbindd_domain *domain = wb_child_domain();
404 uint32_t i;
405 uint32_t num_local_groups = 0;
406 struct wb_acct_info *local_groups = NULL;
407 uint32_t num_dom_groups = 0;
408 struct wb_acct_info *dom_groups = NULL;
409 uint32_t ti = 0;
410 uint64_t num_total = 0;
411 struct wbint_Principal *result;
412 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
413 bool include_local_groups = false;
415 if (domain == NULL) {
416 return NT_STATUS_REQUEST_NOT_ACCEPTED;
419 frame = talloc_stackframe();
421 switch (lp_server_role()) {
422 case ROLE_ACTIVE_DIRECTORY_DC:
423 if (domain->internal) {
425 * we want to include local groups
426 * for BUILTIN and WORKGROUP
428 include_local_groups = true;
430 break;
431 default:
433 * We might include local groups in more
434 * setups later, but that requires more work
435 * elsewhere.
437 break;
440 if (include_local_groups) {
441 status = wb_cache_enum_local_groups(domain, frame,
442 &num_local_groups,
443 &local_groups);
444 reset_cm_connection_on_error(domain, NULL, status);
445 if (!NT_STATUS_IS_OK(status)) {
446 goto out;
450 status = wb_cache_enum_dom_groups(domain, frame,
451 &num_dom_groups,
452 &dom_groups);
453 reset_cm_connection_on_error(domain, NULL, status);
454 if (!NT_STATUS_IS_OK(status)) {
455 goto out;
458 num_total = num_local_groups + num_dom_groups;
459 if (num_total > UINT32_MAX) {
460 status = NT_STATUS_INTERNAL_ERROR;
461 goto out;
464 result = talloc_array(frame, struct wbint_Principal, num_total);
465 if (result == NULL) {
466 status = NT_STATUS_NO_MEMORY;
467 goto out;
470 for (i = 0; i < num_local_groups; i++) {
471 struct wb_acct_info *lg = &local_groups[i];
472 struct wbint_Principal *rg = &result[ti++];
474 sid_compose(&rg->sid, &domain->sid, lg->rid);
475 rg->type = SID_NAME_ALIAS;
476 rg->name = talloc_strdup(result, lg->acct_name);
477 if (rg->name == NULL) {
478 status = NT_STATUS_NO_MEMORY;
479 goto out;
482 num_local_groups = 0;
484 for (i = 0; i < num_dom_groups; i++) {
485 struct wb_acct_info *dg = &dom_groups[i];
486 struct wbint_Principal *rg = &result[ti++];
488 sid_compose(&rg->sid, &domain->sid, dg->rid);
489 rg->type = SID_NAME_DOM_GRP;
490 rg->name = talloc_strdup(result, dg->acct_name);
491 if (rg->name == NULL) {
492 status = NT_STATUS_NO_MEMORY;
493 goto out;
496 num_dom_groups = 0;
498 r->out.groups->num_principals = ti;
499 r->out.groups->principals = talloc_move(r->out.groups, &result);
501 status = NT_STATUS_OK;
502 out:
503 TALLOC_FREE(frame);
504 return status;
507 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
508 struct wbint_QueryUserRidList *r)
510 struct winbindd_domain *domain = wb_child_domain();
511 NTSTATUS status;
513 if (domain == NULL) {
514 return NT_STATUS_REQUEST_NOT_ACCEPTED;
518 * Right now this is overkill. We should add a backend call
519 * just querying the rids.
522 status = wb_cache_query_user_list(domain, p->mem_ctx,
523 &r->out.rids->rids);
524 reset_cm_connection_on_error(domain, NULL, status);
526 if (!NT_STATUS_IS_OK(status)) {
527 return status;
530 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
532 return NT_STATUS_OK;
535 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
537 struct winbindd_domain *domain = wb_child_domain();
538 struct rpc_pipe_client *netlogon_pipe;
539 struct netr_DsRGetDCNameInfo *dc_info;
540 NTSTATUS status;
541 WERROR werr;
542 unsigned int orig_timeout;
543 struct dcerpc_binding_handle *b;
545 if (domain == NULL) {
546 return dsgetdcname(p->mem_ctx, server_messaging_context(),
547 r->in.domain_name, r->in.domain_guid,
548 r->in.site_name ? r->in.site_name : "",
549 r->in.flags,
550 r->out.dc_info);
553 status = cm_connect_netlogon(domain, &netlogon_pipe);
555 reset_cm_connection_on_error(domain, NULL, status);
556 if (!NT_STATUS_IS_OK(status)) {
557 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
558 return status;
561 b = netlogon_pipe->binding_handle;
563 /* This call can take a long time - allow the server to time out.
564 35 seconds should do it. */
566 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
568 if (domain->active_directory) {
569 status = dcerpc_netr_DsRGetDCName(b,
570 p->mem_ctx, domain->dcname,
571 r->in.domain_name, NULL, r->in.domain_guid,
572 r->in.flags, r->out.dc_info, &werr);
573 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
574 goto done;
576 if (reset_cm_connection_on_error(domain, NULL, status)) {
577 /* Re-initialize. */
578 status = cm_connect_netlogon(domain, &netlogon_pipe);
580 reset_cm_connection_on_error(domain, NULL, status);
581 if (!NT_STATUS_IS_OK(status)) {
582 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
583 return status;
586 b = netlogon_pipe->binding_handle;
588 /* This call can take a long time - allow the server to time out.
589 35 seconds should do it. */
591 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
596 * Fallback to less capable methods
599 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
600 if (dc_info == NULL) {
601 status = NT_STATUS_NO_MEMORY;
602 goto done;
605 if (r->in.flags & DS_PDC_REQUIRED) {
606 status = dcerpc_netr_GetDcName(b,
607 p->mem_ctx, domain->dcname,
608 r->in.domain_name, &dc_info->dc_unc, &werr);
609 } else {
610 status = dcerpc_netr_GetAnyDCName(b,
611 p->mem_ctx, domain->dcname,
612 r->in.domain_name, &dc_info->dc_unc, &werr);
615 reset_cm_connection_on_error(domain, NULL, status);
616 if (!NT_STATUS_IS_OK(status)) {
617 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
618 nt_errstr(status)));
619 goto done;
621 if (!W_ERROR_IS_OK(werr)) {
622 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
623 win_errstr(werr)));
624 status = werror_to_ntstatus(werr);
625 goto done;
628 *r->out.dc_info = dc_info;
629 status = NT_STATUS_OK;
631 done:
632 /* And restore our original timeout. */
633 rpccli_set_timeout(netlogon_pipe, orig_timeout);
635 return status;
638 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
640 struct winbindd_domain *domain = wb_child_domain();
641 char *domain_name;
642 char **names;
643 enum lsa_SidType *types;
644 struct wbint_Principal *result;
645 NTSTATUS status;
646 uint32_t i;
648 if (domain == NULL) {
649 return NT_STATUS_REQUEST_NOT_ACCEPTED;
652 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
653 r->in.rids->rids, r->in.rids->num_rids,
654 &domain_name, &names, &types);
655 reset_cm_connection_on_error(domain, NULL, status);
656 if (!NT_STATUS_IS_OK(status)) {
657 return status;
660 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
662 result = talloc_array(p->mem_ctx, struct wbint_Principal,
663 r->in.rids->num_rids);
664 if (result == NULL) {
665 return NT_STATUS_NO_MEMORY;
668 for (i=0; i<r->in.rids->num_rids; i++) {
669 sid_compose(&result[i].sid, r->in.domain_sid,
670 r->in.rids->rids[i]);
671 result[i].type = types[i];
672 result[i].name = talloc_move(result, &names[i]);
674 TALLOC_FREE(types);
675 TALLOC_FREE(names);
677 r->out.names->num_principals = r->in.rids->num_rids;
678 r->out.names->principals = result;
679 return NT_STATUS_OK;
682 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
683 struct wbint_CheckMachineAccount *r)
685 struct winbindd_domain *domain;
686 int num_retries = 0;
687 NTSTATUS status;
689 domain = wb_child_domain();
690 if (domain == NULL) {
691 return NT_STATUS_REQUEST_NOT_ACCEPTED;
694 again:
695 invalidate_cm_connection(domain);
696 domain->conn.netlogon_force_reauth = true;
699 struct rpc_pipe_client *netlogon_pipe = NULL;
700 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
701 status = cm_connect_netlogon_secure(domain,
702 &netlogon_pipe,
703 &netlogon_creds_ctx);
706 /* There is a race condition between fetching the trust account
707 password and the periodic machine password change. So it's
708 possible that the trust account password has been changed on us.
709 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
711 #define MAX_RETRIES 3
713 if ((num_retries < MAX_RETRIES)
714 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
715 num_retries++;
716 goto again;
719 if (!NT_STATUS_IS_OK(status)) {
720 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
721 goto done;
724 /* Pass back result code - zero for success, other values for
725 specific failures. */
727 DEBUG(3,("domain %s secret is %s\n", domain->name,
728 NT_STATUS_IS_OK(status) ? "good" : "bad"));
730 done:
731 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
732 ("Checking the trust account password for domain %s returned %s\n",
733 domain->name, nt_errstr(status)));
735 return status;
738 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
739 struct wbint_ChangeMachineAccount *r)
741 struct messaging_context *msg_ctx = server_messaging_context();
742 struct winbindd_domain *domain;
743 NTSTATUS status;
744 struct rpc_pipe_client *netlogon_pipe = NULL;
745 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
747 domain = wb_child_domain();
748 if (domain == NULL) {
749 return NT_STATUS_REQUEST_NOT_ACCEPTED;
752 status = cm_connect_netlogon_secure(domain,
753 &netlogon_pipe,
754 &netlogon_creds_ctx);
755 if (!NT_STATUS_IS_OK(status)) {
756 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
757 goto done;
760 status = trust_pw_change(netlogon_creds_ctx,
761 msg_ctx,
762 netlogon_pipe->binding_handle,
763 domain->name,
764 domain->dcname,
765 true); /* force */
767 /* Pass back result code - zero for success, other values for
768 specific failures. */
770 DEBUG(3,("domain %s secret %s\n", domain->name,
771 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
773 done:
774 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
775 ("Changing the trust account password for domain %s returned %s\n",
776 domain->name, nt_errstr(status)));
778 return status;
781 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
783 NTSTATUS status;
784 struct winbindd_domain *domain;
785 struct rpc_pipe_client *netlogon_pipe;
786 union netr_CONTROL_QUERY_INFORMATION info;
787 WERROR werr;
788 fstring logon_server;
789 struct dcerpc_binding_handle *b;
790 bool retry = false;
792 domain = wb_child_domain();
793 if (domain == NULL) {
794 return NT_STATUS_REQUEST_NOT_ACCEPTED;
797 reconnect:
798 status = cm_connect_netlogon(domain, &netlogon_pipe);
799 reset_cm_connection_on_error(domain, NULL, status);
800 if (!NT_STATUS_IS_OK(status)) {
801 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
802 nt_errstr(status)));
803 return status;
806 b = netlogon_pipe->binding_handle;
808 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
809 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
810 if (*r->out.dcname == NULL) {
811 DEBUG(2, ("Could not allocate memory\n"));
812 return NT_STATUS_NO_MEMORY;
816 * This provokes a WERR_NOT_SUPPORTED error message. This is
817 * documented in the wspp docs. I could not get a successful
818 * call to work, but the main point here is testing that the
819 * netlogon pipe works.
821 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
822 logon_server, NETLOGON_CONTROL_QUERY,
823 2, &info, &werr);
825 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
826 retry = true;
827 goto reconnect;
830 if (!NT_STATUS_IS_OK(status)) {
831 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
832 nt_errstr(status)));
833 return status;
836 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
837 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
838 "WERR_NOT_SUPPORTED\n",
839 win_errstr(werr)));
840 return werror_to_ntstatus(werr);
843 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
844 return NT_STATUS_OK;
847 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
848 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
850 struct winbindd_domain *domain;
851 NTSTATUS status;
852 struct rpc_pipe_client *netlogon_pipe = NULL;
853 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
855 domain = wb_child_domain();
856 if (domain == NULL) {
857 return NT_STATUS_REQUEST_NOT_ACCEPTED;
860 status = cm_connect_netlogon_secure(domain,
861 &netlogon_pipe,
862 &netlogon_creds_ctx);
863 if (!NT_STATUS_IS_OK(status)) {
864 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
865 goto done;
868 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
869 netlogon_pipe->binding_handle,
870 r->in.site_name,
871 r->in.dns_ttl,
872 r->in.dns_names);
874 /* Pass back result code - zero for success, other values for
875 specific failures. */
877 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
878 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
880 done:
881 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
882 ("Update of DNS records via RW DC %s returned %s\n",
883 domain->name, nt_errstr(status)));
885 return status;
888 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
889 struct winbind_SamLogon *r)
891 struct winbindd_domain *domain;
892 NTSTATUS status;
893 struct netr_IdentityInfo *identity_info = NULL;
894 const uint8_t chal_zero[8] = {0, };
895 const uint8_t *challenge = chal_zero;
896 DATA_BLOB lm_response, nt_response;
897 uint32_t flags = 0;
898 uint16_t validation_level;
899 union netr_Validation *validation = NULL;
900 bool interactive = false;
902 domain = wb_child_domain();
903 if (domain == NULL) {
904 return NT_STATUS_REQUEST_NOT_ACCEPTED;
907 switch (r->in.validation_level) {
908 case 3:
909 case 6:
910 break;
911 default:
912 return NT_STATUS_REQUEST_NOT_ACCEPTED;
915 switch (r->in.logon_level) {
916 case NetlogonInteractiveInformation:
917 case NetlogonServiceInformation:
918 case NetlogonInteractiveTransitiveInformation:
919 case NetlogonServiceTransitiveInformation:
920 if (r->in.logon.password == NULL) {
921 return NT_STATUS_REQUEST_NOT_ACCEPTED;
924 interactive = true;
925 identity_info = &r->in.logon.password->identity_info;
927 challenge = chal_zero;
928 lm_response = data_blob_talloc(p->mem_ctx,
929 r->in.logon.password->lmpassword.hash,
930 sizeof(r->in.logon.password->lmpassword.hash));
931 nt_response = data_blob_talloc(p->mem_ctx,
932 r->in.logon.password->ntpassword.hash,
933 sizeof(r->in.logon.password->ntpassword.hash));
934 break;
936 case NetlogonNetworkInformation:
937 case NetlogonNetworkTransitiveInformation:
938 if (r->in.logon.network == NULL) {
939 return NT_STATUS_REQUEST_NOT_ACCEPTED;
942 interactive = false;
943 identity_info = &r->in.logon.network->identity_info;
945 challenge = r->in.logon.network->challenge;
946 lm_response = data_blob_talloc(p->mem_ctx,
947 r->in.logon.network->lm.data,
948 r->in.logon.network->lm.length);
949 nt_response = data_blob_talloc(p->mem_ctx,
950 r->in.logon.network->nt.data,
951 r->in.logon.network->nt.length);
952 break;
954 case NetlogonGenericInformation:
955 if (r->in.logon.generic == NULL) {
956 return NT_STATUS_REQUEST_NOT_ACCEPTED;
959 identity_info = &r->in.logon.generic->identity_info;
961 * Not implemented here...
963 return NT_STATUS_REQUEST_NOT_ACCEPTED;
965 default:
966 return NT_STATUS_REQUEST_NOT_ACCEPTED;
969 status = winbind_dual_SamLogon(domain, p->mem_ctx,
970 interactive,
971 identity_info->parameter_control,
972 identity_info->account_name.string,
973 identity_info->domain_name.string,
974 identity_info->workstation.string,
975 challenge,
976 lm_response, nt_response,
977 &r->out.authoritative,
978 true, /* skip_sam */
979 &flags,
980 &validation_level,
981 &validation);
982 if (!NT_STATUS_IS_OK(status)) {
983 return status;
985 switch (r->in.validation_level) {
986 case 3:
987 status = map_validation_to_info3(p->mem_ctx,
988 validation_level,
989 validation,
990 &r->out.validation.sam3);
991 TALLOC_FREE(validation);
992 if (!NT_STATUS_IS_OK(status)) {
993 return status;
995 return NT_STATUS_OK;
996 case 6:
997 status = map_validation_to_info6(p->mem_ctx,
998 validation_level,
999 validation,
1000 &r->out.validation.sam6);
1001 TALLOC_FREE(validation);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 return status;
1005 return NT_STATUS_OK;
1008 smb_panic(__location__);
1009 return NT_STATUS_INTERNAL_ERROR;
1012 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1013 struct winbindd_domain *domain,
1014 struct winbind_LogonControl *r)
1016 NTSTATUS status;
1017 struct rpc_pipe_client *netlogon_pipe = NULL;
1018 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1019 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1020 WERROR check_result = WERR_INTERNAL_ERROR;
1022 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1023 if (info2 == NULL) {
1024 return WERR_NOT_ENOUGH_MEMORY;
1027 if (domain->internal) {
1028 check_result = WERR_OK;
1029 goto check_return;
1033 * For now we just force a reconnect
1035 * TODO: take care of the optional '\dcname'
1037 invalidate_cm_connection(domain);
1038 domain->conn.netlogon_force_reauth = true;
1039 status = cm_connect_netlogon_secure(domain,
1040 &netlogon_pipe,
1041 &netlogon_creds_ctx);
1042 reset_cm_connection_on_error(domain, NULL, status);
1043 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1044 status = NT_STATUS_NO_LOGON_SERVERS;
1046 if (!NT_STATUS_IS_OK(status)) {
1047 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1048 __func__, domain->name, domain->alt_name,
1049 nt_errstr(status)));
1051 * Here we return a top level error!
1052 * This is different than TC_QUERY or TC_VERIFY.
1054 return ntstatus_to_werror(status);
1056 check_result = WERR_OK;
1058 check_return:
1059 info2->pdc_connection_status = WERR_OK;
1060 if (domain->dcname != NULL) {
1061 info2->flags |= NETLOGON_HAS_IP;
1062 info2->flags |= NETLOGON_HAS_TIMESERV;
1063 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1064 domain->dcname);
1065 if (info2->trusted_dc_name == NULL) {
1066 return WERR_NOT_ENOUGH_MEMORY;
1068 } else {
1069 info2->trusted_dc_name = talloc_strdup(info2, "");
1070 if (info2->trusted_dc_name == NULL) {
1071 return WERR_NOT_ENOUGH_MEMORY;
1074 info2->tc_connection_status = check_result;
1076 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1077 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1078 "pdc_connection[%s] tc_connection[%s]\n",
1079 __func__, domain->name, domain->alt_name,
1080 domain->dcname,
1081 win_errstr(info2->pdc_connection_status),
1082 win_errstr(info2->tc_connection_status)));
1085 r->out.query->info2 = info2;
1087 DEBUG(5, ("%s: succeeded.\n", __func__));
1088 return WERR_OK;
1091 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1092 struct winbindd_domain *domain,
1093 struct winbind_LogonControl *r)
1095 NTSTATUS status;
1096 struct rpc_pipe_client *netlogon_pipe = NULL;
1097 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1098 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1099 WERROR check_result = WERR_INTERNAL_ERROR;
1101 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1102 if (info2 == NULL) {
1103 return WERR_NOT_ENOUGH_MEMORY;
1106 if (domain->internal) {
1107 check_result = WERR_OK;
1108 goto check_return;
1111 status = cm_connect_netlogon_secure(domain,
1112 &netlogon_pipe,
1113 &netlogon_creds_ctx);
1114 reset_cm_connection_on_error(domain, NULL, status);
1115 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1116 status = NT_STATUS_NO_LOGON_SERVERS;
1118 if (!NT_STATUS_IS_OK(status)) {
1119 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1120 nt_errstr(status)));
1121 check_result = ntstatus_to_werror(status);
1122 goto check_return;
1124 check_result = WERR_OK;
1126 check_return:
1127 info2->pdc_connection_status = WERR_OK;
1128 if (domain->dcname != NULL) {
1129 info2->flags |= NETLOGON_HAS_IP;
1130 info2->flags |= NETLOGON_HAS_TIMESERV;
1131 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1132 domain->dcname);
1133 if (info2->trusted_dc_name == NULL) {
1134 return WERR_NOT_ENOUGH_MEMORY;
1136 } else {
1137 info2->trusted_dc_name = talloc_strdup(info2, "");
1138 if (info2->trusted_dc_name == NULL) {
1139 return WERR_NOT_ENOUGH_MEMORY;
1142 info2->tc_connection_status = check_result;
1144 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1145 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1146 "pdc_connection[%s] tc_connection[%s]\n",
1147 __func__, domain->name, domain->alt_name,
1148 domain->dcname,
1149 win_errstr(info2->pdc_connection_status),
1150 win_errstr(info2->tc_connection_status)));
1153 r->out.query->info2 = info2;
1155 DEBUG(5, ("%s: succeeded.\n", __func__));
1156 return WERR_OK;
1159 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1160 struct winbindd_domain *domain,
1161 struct winbind_LogonControl *r)
1163 TALLOC_CTX *frame = talloc_stackframe();
1164 NTSTATUS status;
1165 NTSTATUS result;
1166 struct lsa_String trusted_domain_name = {};
1167 struct lsa_StringLarge trusted_domain_name_l = {};
1168 struct rpc_pipe_client *local_lsa_pipe = NULL;
1169 struct policy_handle local_lsa_policy = {};
1170 struct dcerpc_binding_handle *local_lsa = NULL;
1171 struct rpc_pipe_client *netlogon_pipe = NULL;
1172 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1173 struct cli_credentials *creds = NULL;
1174 struct samr_Password *cur_nt_hash = NULL;
1175 uint32_t trust_attributes = 0;
1176 struct samr_Password new_owf_password = {};
1177 int cmp_new = -1;
1178 struct samr_Password old_owf_password = {};
1179 int cmp_old = -1;
1180 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1181 bool fetch_fti = false;
1182 struct lsa_ForestTrustInformation *new_fti = NULL;
1183 struct netr_TrustInfo *trust_info = NULL;
1184 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1185 struct dcerpc_binding_handle *b = NULL;
1186 WERROR check_result = WERR_INTERNAL_ERROR;
1187 WERROR verify_result = WERR_INTERNAL_ERROR;
1188 bool retry = false;
1190 trusted_domain_name.string = domain->name;
1191 trusted_domain_name_l.string = domain->name;
1193 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1194 if (info2 == NULL) {
1195 TALLOC_FREE(frame);
1196 return WERR_NOT_ENOUGH_MEMORY;
1199 if (domain->internal) {
1200 check_result = WERR_OK;
1201 goto check_return;
1204 status = pdb_get_trust_credentials(domain->name,
1205 domain->alt_name,
1206 frame,
1207 &creds);
1208 if (NT_STATUS_IS_OK(status)) {
1209 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1210 TALLOC_FREE(creds);
1213 if (!domain->primary) {
1214 union lsa_TrustedDomainInfo *tdi = NULL;
1216 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1217 &local_lsa_policy);
1218 if (!NT_STATUS_IS_OK(status)) {
1219 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1220 __location__, __func__, nt_errstr(status)));
1221 TALLOC_FREE(frame);
1222 return WERR_INTERNAL_ERROR;
1224 local_lsa = local_lsa_pipe->binding_handle;
1226 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1227 &local_lsa_policy,
1228 &trusted_domain_name,
1229 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1230 &tdi, &result);
1231 if (!NT_STATUS_IS_OK(status)) {
1232 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1233 __location__, __func__, domain->name, nt_errstr(status)));
1234 TALLOC_FREE(frame);
1235 return WERR_INTERNAL_ERROR;
1237 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1238 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1239 __location__, __func__, domain->name));
1240 TALLOC_FREE(frame);
1241 return WERR_NO_SUCH_DOMAIN;
1243 if (!NT_STATUS_IS_OK(result)) {
1244 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1245 __location__, __func__, domain->name, nt_errstr(result)));
1246 TALLOC_FREE(frame);
1247 return WERR_INTERNAL_ERROR;
1249 if (tdi == NULL) {
1250 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1251 "returned no trusted domain information\n",
1252 __location__, __func__));
1253 TALLOC_FREE(frame);
1254 return WERR_INTERNAL_ERROR;
1257 local_tdo = &tdi->info_ex;
1258 trust_attributes = local_tdo->trust_attributes;
1261 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1262 struct lsa_ForestTrustInformation *old_fti = NULL;
1264 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1265 &local_lsa_policy,
1266 &trusted_domain_name,
1267 LSA_FOREST_TRUST_DOMAIN_INFO,
1268 &old_fti, &result);
1269 if (!NT_STATUS_IS_OK(status)) {
1270 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1271 __location__, __func__, domain->name, nt_errstr(status)));
1272 TALLOC_FREE(frame);
1273 return WERR_INTERNAL_ERROR;
1275 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1276 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1277 __func__, domain->name));
1278 old_fti = NULL;
1279 fetch_fti = true;
1280 result = NT_STATUS_OK;
1282 if (!NT_STATUS_IS_OK(result)) {
1283 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1284 __location__, __func__, domain->name, nt_errstr(result)));
1285 TALLOC_FREE(frame);
1286 return WERR_INTERNAL_ERROR;
1289 TALLOC_FREE(old_fti);
1292 reconnect:
1293 status = cm_connect_netlogon_secure(domain,
1294 &netlogon_pipe,
1295 &netlogon_creds_ctx);
1296 reset_cm_connection_on_error(domain, NULL, status);
1297 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1298 status = NT_STATUS_NO_LOGON_SERVERS;
1300 if (!NT_STATUS_IS_OK(status)) {
1301 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1302 nt_errstr(status)));
1303 check_result = ntstatus_to_werror(status);
1304 goto check_return;
1306 check_result = WERR_OK;
1307 b = netlogon_pipe->binding_handle;
1309 if (cur_nt_hash == NULL) {
1310 verify_result = WERR_NO_TRUST_LSA_SECRET;
1311 goto verify_return;
1314 if (fetch_fti) {
1315 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1316 b, frame,
1317 &new_fti);
1318 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1319 status = NT_STATUS_NOT_SUPPORTED;
1321 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1322 new_fti = NULL;
1323 status = NT_STATUS_OK;
1325 if (!NT_STATUS_IS_OK(status)) {
1326 if (!retry &&
1327 reset_cm_connection_on_error(domain, b, status))
1329 retry = true;
1330 goto reconnect;
1332 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1333 "failed: %s\n",
1334 domain->name, nt_errstr(status)));
1335 check_result = ntstatus_to_werror(status);
1336 goto check_return;
1340 if (new_fti != NULL) {
1341 struct lsa_ForestTrustInformation old_fti = {};
1342 struct lsa_ForestTrustInformation *merged_fti = NULL;
1343 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1345 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1346 &old_fti, new_fti,
1347 &merged_fti);
1348 if (!NT_STATUS_IS_OK(status)) {
1349 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1350 __location__, __func__,
1351 domain->name, nt_errstr(status)));
1352 TALLOC_FREE(frame);
1353 return ntstatus_to_werror(status);
1356 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1357 &local_lsa_policy,
1358 &trusted_domain_name_l,
1359 LSA_FOREST_TRUST_DOMAIN_INFO,
1360 merged_fti,
1361 0, /* check_only=0 => store it! */
1362 &collision_info,
1363 &result);
1364 if (!NT_STATUS_IS_OK(status)) {
1365 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1366 __location__, __func__, domain->name, nt_errstr(status)));
1367 TALLOC_FREE(frame);
1368 return WERR_INTERNAL_ERROR;
1370 if (!NT_STATUS_IS_OK(result)) {
1371 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1372 __location__, __func__, domain->name, nt_errstr(result)));
1373 TALLOC_FREE(frame);
1374 return ntstatus_to_werror(result);
1378 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1379 b, frame,
1380 &new_owf_password,
1381 &old_owf_password,
1382 &trust_info);
1383 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1384 status = NT_STATUS_NOT_SUPPORTED;
1386 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1387 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1388 nt_errstr(status)));
1389 verify_result = WERR_OK;
1390 goto verify_return;
1392 if (!NT_STATUS_IS_OK(status)) {
1393 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1394 retry = true;
1395 goto reconnect;
1397 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1398 nt_errstr(status)));
1400 if (!dcerpc_binding_handle_is_connected(b)) {
1401 check_result = ntstatus_to_werror(status);
1402 goto check_return;
1403 } else {
1404 verify_result = ntstatus_to_werror(status);
1405 goto verify_return;
1409 if (trust_info != NULL && trust_info->count >= 1) {
1410 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1412 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1413 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1414 goto verify_return;
1418 cmp_new = memcmp(new_owf_password.hash,
1419 cur_nt_hash->hash,
1420 sizeof(cur_nt_hash->hash));
1421 cmp_old = memcmp(old_owf_password.hash,
1422 cur_nt_hash->hash,
1423 sizeof(cur_nt_hash->hash));
1424 if (cmp_new != 0 && cmp_old != 0) {
1425 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1426 "any password known to dcname[%s]\n",
1427 __func__, domain->name, domain->alt_name,
1428 domain->dcname));
1429 verify_result = WERR_WRONG_PASSWORD;
1430 goto verify_return;
1433 if (cmp_new != 0) {
1434 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1435 "against the old password known to dcname[%s]\n",
1436 __func__, domain->name, domain->alt_name,
1437 domain->dcname));
1440 verify_result = WERR_OK;
1441 goto verify_return;
1443 check_return:
1444 verify_result = check_result;
1445 verify_return:
1446 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1447 info2->pdc_connection_status = verify_result;
1448 if (domain->dcname != NULL) {
1449 info2->flags |= NETLOGON_HAS_IP;
1450 info2->flags |= NETLOGON_HAS_TIMESERV;
1451 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1452 domain->dcname);
1453 if (info2->trusted_dc_name == NULL) {
1454 TALLOC_FREE(frame);
1455 return WERR_NOT_ENOUGH_MEMORY;
1457 } else {
1458 info2->trusted_dc_name = talloc_strdup(info2, "");
1459 if (info2->trusted_dc_name == NULL) {
1460 TALLOC_FREE(frame);
1461 return WERR_NOT_ENOUGH_MEMORY;
1464 info2->tc_connection_status = check_result;
1466 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1467 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1468 "pdc_connection[%s] tc_connection[%s]\n",
1469 __func__, domain->name, domain->alt_name,
1470 domain->dcname,
1471 win_errstr(info2->pdc_connection_status),
1472 win_errstr(info2->tc_connection_status)));
1475 r->out.query->info2 = info2;
1477 DEBUG(5, ("%s: succeeded.\n", __func__));
1478 TALLOC_FREE(frame);
1479 return WERR_OK;
1482 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1483 struct winbindd_domain *domain,
1484 struct winbind_LogonControl *r)
1486 struct messaging_context *msg_ctx = server_messaging_context();
1487 NTSTATUS status;
1488 struct rpc_pipe_client *netlogon_pipe = NULL;
1489 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1490 struct cli_credentials *creds = NULL;
1491 struct samr_Password *cur_nt_hash = NULL;
1492 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1493 struct dcerpc_binding_handle *b;
1494 WERROR change_result = WERR_OK;
1495 bool retry = false;
1497 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1498 if (info1 == NULL) {
1499 return WERR_NOT_ENOUGH_MEMORY;
1502 if (domain->internal) {
1503 return WERR_NOT_SUPPORTED;
1506 status = pdb_get_trust_credentials(domain->name,
1507 domain->alt_name,
1508 p->mem_ctx,
1509 &creds);
1510 if (NT_STATUS_IS_OK(status)) {
1511 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1512 TALLOC_FREE(creds);
1515 reconnect:
1516 status = cm_connect_netlogon_secure(domain,
1517 &netlogon_pipe,
1518 &netlogon_creds_ctx);
1519 reset_cm_connection_on_error(domain, NULL, status);
1520 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1521 status = NT_STATUS_NO_LOGON_SERVERS;
1523 if (!NT_STATUS_IS_OK(status)) {
1524 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1525 __func__, domain->name, domain->alt_name,
1526 nt_errstr(status)));
1528 * Here we return a top level error!
1529 * This is different than TC_QUERY or TC_VERIFY.
1531 return ntstatus_to_werror(status);
1533 b = netlogon_pipe->binding_handle;
1535 if (cur_nt_hash == NULL) {
1536 change_result = WERR_NO_TRUST_LSA_SECRET;
1537 goto change_return;
1539 TALLOC_FREE(cur_nt_hash);
1541 status = trust_pw_change(netlogon_creds_ctx,
1542 msg_ctx, b, domain->name,
1543 domain->dcname,
1544 true); /* force */
1545 if (!NT_STATUS_IS_OK(status)) {
1546 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1547 retry = true;
1548 goto reconnect;
1551 DEBUG(1, ("trust_pw_change(%s): %s\n",
1552 domain->name, nt_errstr(status)));
1554 change_result = ntstatus_to_werror(status);
1555 goto change_return;
1558 change_result = WERR_OK;
1560 change_return:
1561 info1->pdc_connection_status = change_result;
1563 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1564 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1565 "pdc_connection[%s]\n",
1566 __func__, domain->name, domain->alt_name,
1567 domain->dcname,
1568 win_errstr(info1->pdc_connection_status)));
1571 r->out.query->info1 = info1;
1573 DEBUG(5, ("%s: succeeded.\n", __func__));
1574 return WERR_OK;
1577 WERROR _winbind_LogonControl(struct pipes_struct *p,
1578 struct winbind_LogonControl *r)
1580 struct winbindd_domain *domain;
1582 domain = wb_child_domain();
1583 if (domain == NULL) {
1584 return WERR_NO_SUCH_DOMAIN;
1587 switch (r->in.function_code) {
1588 case NETLOGON_CONTROL_REDISCOVER:
1589 if (r->in.level != 2) {
1590 return WERR_INVALID_PARAMETER;
1592 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1593 case NETLOGON_CONTROL_TC_QUERY:
1594 if (r->in.level != 2) {
1595 return WERR_INVALID_PARAMETER;
1597 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1598 case NETLOGON_CONTROL_TC_VERIFY:
1599 if (r->in.level != 2) {
1600 return WERR_INVALID_PARAMETER;
1602 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1603 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1604 if (r->in.level != 1) {
1605 return WERR_INVALID_PARAMETER;
1607 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1608 default:
1609 break;
1612 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1613 __func__, r->in.function_code));
1614 return WERR_NOT_SUPPORTED;
1617 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1618 struct winbind_GetForestTrustInformation *r)
1620 TALLOC_CTX *frame = talloc_stackframe();
1621 NTSTATUS status, result;
1622 struct winbindd_domain *domain;
1623 struct rpc_pipe_client *netlogon_pipe = NULL;
1624 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1625 struct dcerpc_binding_handle *b;
1626 bool retry = false;
1627 struct lsa_String trusted_domain_name = {};
1628 struct lsa_StringLarge trusted_domain_name_l = {};
1629 union lsa_TrustedDomainInfo *tdi = NULL;
1630 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1631 struct lsa_ForestTrustInformation _old_fti = {};
1632 struct lsa_ForestTrustInformation *old_fti = NULL;
1633 struct lsa_ForestTrustInformation *new_fti = NULL;
1634 struct lsa_ForestTrustInformation *merged_fti = NULL;
1635 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1636 bool update_fti = false;
1637 struct rpc_pipe_client *local_lsa_pipe;
1638 struct policy_handle local_lsa_policy;
1639 struct dcerpc_binding_handle *local_lsa = NULL;
1641 domain = wb_child_domain();
1642 if (domain == NULL) {
1643 TALLOC_FREE(frame);
1644 return WERR_NO_SUCH_DOMAIN;
1648 * checking for domain->internal and domain->primary
1649 * makes sure we only do some work when running as DC.
1652 if (domain->internal) {
1653 TALLOC_FREE(frame);
1654 return WERR_NO_SUCH_DOMAIN;
1657 if (domain->primary) {
1658 TALLOC_FREE(frame);
1659 return WERR_NO_SUCH_DOMAIN;
1662 trusted_domain_name.string = domain->name;
1663 trusted_domain_name_l.string = domain->name;
1665 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1666 &local_lsa_policy);
1667 if (!NT_STATUS_IS_OK(status)) {
1668 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1669 __location__, __func__, nt_errstr(status)));
1670 TALLOC_FREE(frame);
1671 return WERR_INTERNAL_ERROR;
1673 local_lsa = local_lsa_pipe->binding_handle;
1675 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1676 &local_lsa_policy,
1677 &trusted_domain_name,
1678 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1679 &tdi, &result);
1680 if (!NT_STATUS_IS_OK(status)) {
1681 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1682 __location__, __func__, domain->name, nt_errstr(status)));
1683 TALLOC_FREE(frame);
1684 return WERR_INTERNAL_ERROR;
1686 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1687 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1688 __location__, __func__, domain->name));
1689 TALLOC_FREE(frame);
1690 return WERR_NO_SUCH_DOMAIN;
1692 if (!NT_STATUS_IS_OK(result)) {
1693 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1694 __location__, __func__, domain->name, nt_errstr(result)));
1695 TALLOC_FREE(frame);
1696 return WERR_INTERNAL_ERROR;
1698 if (tdi == NULL) {
1699 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1700 "returned no trusted domain information\n",
1701 __location__, __func__));
1702 TALLOC_FREE(frame);
1703 return WERR_INTERNAL_ERROR;
1706 tdo = &tdi->info_ex;
1708 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1709 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1710 __func__, tdo->netbios_name.string,
1711 tdo->domain_name.string,
1712 (unsigned)tdo->trust_attributes));
1713 TALLOC_FREE(frame);
1714 return WERR_NO_SUCH_DOMAIN;
1717 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1718 TALLOC_FREE(frame);
1719 return WERR_INVALID_FLAGS;
1722 reconnect:
1723 status = cm_connect_netlogon_secure(domain,
1724 &netlogon_pipe,
1725 &netlogon_creds_ctx);
1726 reset_cm_connection_on_error(domain, NULL, status);
1727 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1728 status = NT_STATUS_NO_LOGON_SERVERS;
1730 if (!NT_STATUS_IS_OK(status)) {
1731 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1732 nt_errstr(status)));
1733 TALLOC_FREE(frame);
1734 return ntstatus_to_werror(status);
1736 b = netlogon_pipe->binding_handle;
1738 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1739 b, p->mem_ctx,
1740 &new_fti);
1741 if (!NT_STATUS_IS_OK(status)) {
1742 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1743 retry = true;
1744 goto reconnect;
1746 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1747 domain->name, nt_errstr(status)));
1748 TALLOC_FREE(frame);
1749 return ntstatus_to_werror(status);
1752 *r->out.forest_trust_info = new_fti;
1754 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1755 update_fti = true;
1758 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1759 &local_lsa_policy,
1760 &trusted_domain_name,
1761 LSA_FOREST_TRUST_DOMAIN_INFO,
1762 &old_fti, &result);
1763 if (!NT_STATUS_IS_OK(status)) {
1764 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1765 __location__, __func__, domain->name, nt_errstr(status)));
1766 TALLOC_FREE(frame);
1767 return WERR_INTERNAL_ERROR;
1769 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1770 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1771 __func__, domain->name));
1772 update_fti = true;
1773 old_fti = &_old_fti;
1774 result = NT_STATUS_OK;
1776 if (!NT_STATUS_IS_OK(result)) {
1777 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1778 __location__, __func__, domain->name, nt_errstr(result)));
1779 TALLOC_FREE(frame);
1780 return WERR_INTERNAL_ERROR;
1783 if (old_fti == NULL) {
1784 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1785 "returned success without returning forest trust information\n",
1786 __location__, __func__));
1787 TALLOC_FREE(frame);
1788 return WERR_INTERNAL_ERROR;
1791 if (!update_fti) {
1792 goto done;
1795 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1796 &merged_fti);
1797 if (!NT_STATUS_IS_OK(status)) {
1798 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1799 __location__, __func__, domain->name, nt_errstr(status)));
1800 TALLOC_FREE(frame);
1801 return ntstatus_to_werror(status);
1804 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1805 &local_lsa_policy,
1806 &trusted_domain_name_l,
1807 LSA_FOREST_TRUST_DOMAIN_INFO,
1808 merged_fti,
1809 0, /* check_only=0 => store it! */
1810 &collision_info,
1811 &result);
1812 if (!NT_STATUS_IS_OK(status)) {
1813 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1814 __location__, __func__, domain->name, nt_errstr(status)));
1815 TALLOC_FREE(frame);
1816 return WERR_INTERNAL_ERROR;
1818 if (!NT_STATUS_IS_OK(result)) {
1819 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1820 __location__, __func__, domain->name, nt_errstr(result)));
1821 TALLOC_FREE(frame);
1822 return ntstatus_to_werror(result);
1825 done:
1826 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1827 TALLOC_FREE(frame);
1828 return WERR_OK;
1831 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1833 struct winbindd_domain *domain;
1834 NTSTATUS status;
1835 struct rpc_pipe_client *netlogon_pipe;
1836 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1838 DEBUG(5, ("_winbind_SendToSam received\n"));
1839 domain = wb_child_domain();
1840 if (domain == NULL) {
1841 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1844 status = cm_connect_netlogon_secure(domain,
1845 &netlogon_pipe,
1846 &netlogon_creds_ctx);
1847 if (!NT_STATUS_IS_OK(status)) {
1848 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1849 return status;
1852 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1853 netlogon_pipe->binding_handle,
1854 &r->in.message);
1856 return status;