CID 1311763: Fix incorrect return value
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob1fe66e155fa03211b6d0e365797e44480ddec12c
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"
37 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
39 *r->out.out_data = r->in.in_data;
42 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
43 NTSTATUS status)
45 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
46 invalidate_cm_connection(domain);
47 /* We invalidated the connection. */
48 return true;
50 return false;
53 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
55 struct winbindd_domain *domain = wb_child_domain();
56 char *dom_name;
57 char *name;
58 enum lsa_SidType type;
59 NTSTATUS status;
61 if (domain == NULL) {
62 return NT_STATUS_REQUEST_NOT_ACCEPTED;
65 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
66 &dom_name, &name, &type);
67 reset_cm_connection_on_error(domain, status);
68 if (!NT_STATUS_IS_OK(status)) {
69 return status;
72 *r->out.domain = dom_name;
73 *r->out.name = name;
74 *r->out.type = type;
75 return NT_STATUS_OK;
78 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
80 struct winbindd_domain *domain = wb_child_domain();
81 struct lsa_RefDomainList *domains = r->out.domains;
82 NTSTATUS status;
84 if (domain == NULL) {
85 return NT_STATUS_REQUEST_NOT_ACCEPTED;
89 * This breaks the winbindd_domain->methods abstraction: This
90 * is only called for remote domains, and both winbindd_msrpc
91 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
92 * done at the wbint RPC layer.
94 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
95 &domains, &r->out.names);
97 if (domains != NULL) {
98 r->out.domains = domains;
101 reset_cm_connection_on_error(domain, status);
102 return status;
105 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
107 struct winbindd_domain *domain = wb_child_domain();
108 NTSTATUS status;
110 if (domain == NULL) {
111 return NT_STATUS_REQUEST_NOT_ACCEPTED;
114 status = domain->methods->name_to_sid(
115 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
116 r->out.sid, r->out.type);
117 reset_cm_connection_on_error(domain, status);
118 return status;
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
124 uint32_t i, j;
125 struct id_map *ids = NULL;
126 struct id_map **id_ptrs = NULL;
127 struct dom_sid *sids = NULL;
128 uint32_t *id_idx = NULL;
129 NTSTATUS status = NT_STATUS_NO_MEMORY;
131 for (i=0; i<r->in.domains->count; i++) {
132 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
133 struct idmap_domain *dom;
134 uint32_t num_ids;
136 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
137 if (dom == NULL) {
138 DEBUG(10, ("idmap domain %s:%s not found\n",
139 d->name.string, sid_string_dbg(d->sid)));
140 continue;
143 num_ids = 0;
145 for (j=0; j<r->in.ids->num_ids; j++) {
146 if (r->in.ids->ids[j].domain_index == i) {
147 num_ids += 1;
151 ids = talloc_realloc(talloc_tos(), ids,
152 struct id_map, num_ids);
153 if (ids == NULL) {
154 goto nomem;
156 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
157 struct id_map *, num_ids+1);
158 if (id_ptrs == NULL) {
159 goto nomem;
161 id_idx = talloc_realloc(talloc_tos(), id_idx,
162 uint32_t, num_ids);
163 if (id_idx == NULL) {
164 goto nomem;
166 sids = talloc_realloc(talloc_tos(), sids,
167 struct dom_sid, num_ids);
168 if (sids == NULL) {
169 goto nomem;
172 num_ids = 0;
175 * Convert the input data into a list of
176 * id_map structs suitable for handing in
177 * to the idmap sids_to_unixids method.
179 for (j=0; j<r->in.ids->num_ids; j++) {
180 struct wbint_TransID *id = &r->in.ids->ids[j];
182 if (id->domain_index != i) {
183 continue;
185 id_idx[num_ids] = j;
186 id_ptrs[num_ids] = &ids[num_ids];
188 ids[num_ids].sid = &sids[num_ids];
189 sid_compose(ids[num_ids].sid, d->sid, id->rid);
190 ids[num_ids].xid.type = id->type;
191 ids[num_ids].status = ID_UNKNOWN;
192 num_ids += 1;
194 id_ptrs[num_ids] = NULL;
196 status = dom->methods->sids_to_unixids(dom, id_ptrs);
197 DEBUG(10, ("sids_to_unixids returned %s\n",
198 nt_errstr(status)));
201 * Extract the results for handing them back to the caller.
203 for (j=0; j<num_ids; j++) {
204 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
206 if (ids[j].status != ID_MAPPED) {
207 id->xid.id = UINT32_MAX;
208 id->xid.type = ID_TYPE_NOT_SPECIFIED;
209 continue;
212 id->xid = ids[j].xid;
215 status = NT_STATUS_OK;
216 nomem:
217 TALLOC_FREE(ids);
218 TALLOC_FREE(id_ptrs);
219 TALLOC_FREE(id_idx);
220 TALLOC_FREE(sids);
221 return status;
224 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
226 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
227 r->out.sid, r->in.uid);
230 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
232 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
233 r->out.sid, r->in.gid);
236 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
238 struct unixid xid;
239 NTSTATUS status;
241 status = idmap_allocate_uid(&xid);
242 if (!NT_STATUS_IS_OK(status)) {
243 return status;
245 *r->out.uid = xid.id;
246 return NT_STATUS_OK;
249 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
251 struct unixid xid;
252 NTSTATUS status;
254 status = idmap_allocate_gid(&xid);
255 if (!NT_STATUS_IS_OK(status)) {
256 return status;
258 *r->out.gid = xid.id;
259 return NT_STATUS_OK;
262 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
264 struct winbindd_domain *domain = wb_child_domain();
265 NTSTATUS status;
267 if (domain == NULL) {
268 return NT_STATUS_REQUEST_NOT_ACCEPTED;
271 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
272 r->out.info);
273 reset_cm_connection_on_error(domain, status);
274 return status;
277 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
278 struct wbint_LookupUserAliases *r)
280 struct winbindd_domain *domain = wb_child_domain();
281 NTSTATUS status;
283 if (domain == NULL) {
284 return NT_STATUS_REQUEST_NOT_ACCEPTED;
287 status = domain->methods->lookup_useraliases(
288 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
289 &r->out.rids->num_rids, &r->out.rids->rids);
290 reset_cm_connection_on_error(domain, status);
291 return status;
294 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
295 struct wbint_LookupUserGroups *r)
297 struct winbindd_domain *domain = wb_child_domain();
298 NTSTATUS status;
300 if (domain == NULL) {
301 return NT_STATUS_REQUEST_NOT_ACCEPTED;
304 status = domain->methods->lookup_usergroups(
305 domain, p->mem_ctx, r->in.sid,
306 &r->out.sids->num_sids, &r->out.sids->sids);
307 reset_cm_connection_on_error(domain, status);
308 return status;
311 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
312 struct wbint_QuerySequenceNumber *r)
314 struct winbindd_domain *domain = wb_child_domain();
315 NTSTATUS status;
317 if (domain == NULL) {
318 return NT_STATUS_REQUEST_NOT_ACCEPTED;
321 status = domain->methods->sequence_number(domain, r->out.sequence);
322 reset_cm_connection_on_error(domain, status);
323 return status;
326 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
327 struct wbint_LookupGroupMembers *r)
329 struct winbindd_domain *domain = wb_child_domain();
330 uint32_t i, num_names;
331 struct dom_sid *sid_mem;
332 char **names;
333 uint32_t *name_types;
334 NTSTATUS status;
336 if (domain == NULL) {
337 return NT_STATUS_REQUEST_NOT_ACCEPTED;
340 status = domain->methods->lookup_groupmem(
341 domain, p->mem_ctx, r->in.sid, r->in.type,
342 &num_names, &sid_mem, &names, &name_types);
343 reset_cm_connection_on_error(domain, status);
344 if (!NT_STATUS_IS_OK(status)) {
345 return status;
348 r->out.members->num_principals = num_names;
349 r->out.members->principals = talloc_array(
350 r->out.members, struct wbint_Principal, num_names);
351 if (r->out.members->principals == NULL) {
352 return NT_STATUS_NO_MEMORY;
355 for (i=0; i<num_names; i++) {
356 struct wbint_Principal *m = &r->out.members->principals[i];
357 sid_copy(&m->sid, &sid_mem[i]);
358 m->name = talloc_move(r->out.members->principals, &names[i]);
359 m->type = (enum lsa_SidType)name_types[i];
362 return NT_STATUS_OK;
365 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
366 struct wbint_QueryUserList *r)
368 struct winbindd_domain *domain = wb_child_domain();
369 NTSTATUS status;
371 if (domain == NULL) {
372 return NT_STATUS_REQUEST_NOT_ACCEPTED;
375 status = domain->methods->query_user_list(
376 domain, p->mem_ctx, &r->out.users->num_userinfos,
377 &r->out.users->userinfos);
378 reset_cm_connection_on_error(domain, status);
379 return status;
382 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
383 struct wbint_QueryGroupList *r)
385 struct winbindd_domain *domain = wb_child_domain();
386 uint32_t i;
387 uint32_t num_local_groups = 0;
388 struct wb_acct_info *local_groups = NULL;
389 uint32_t num_dom_groups = 0;
390 struct wb_acct_info *dom_groups = NULL;
391 uint32_t ti = 0;
392 uint64_t num_total = 0;
393 struct wbint_Principal *result;
394 NTSTATUS status;
395 bool include_local_groups = false;
397 if (domain == NULL) {
398 return NT_STATUS_REQUEST_NOT_ACCEPTED;
401 switch (lp_server_role()) {
402 case ROLE_ACTIVE_DIRECTORY_DC:
403 if (domain->internal) {
405 * we want to include local groups
406 * for BUILTIN and WORKGROUP
408 include_local_groups = true;
410 break;
411 default:
413 * We might include local groups in more
414 * setups later, but that requires more work
415 * elsewhere.
417 break;
420 if (include_local_groups) {
421 status = domain->methods->enum_local_groups(domain, talloc_tos(),
422 &num_local_groups,
423 &local_groups);
424 reset_cm_connection_on_error(domain, status);
425 if (!NT_STATUS_IS_OK(status)) {
426 return status;
430 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
431 &num_dom_groups,
432 &dom_groups);
433 reset_cm_connection_on_error(domain, status);
434 if (!NT_STATUS_IS_OK(status)) {
435 return status;
438 num_total = num_local_groups + num_dom_groups;
439 if (num_total > UINT32_MAX) {
440 return NT_STATUS_INTERNAL_ERROR;
443 result = talloc_array(r->out.groups, struct wbint_Principal,
444 num_total);
445 if (result == NULL) {
446 return NT_STATUS_NO_MEMORY;
449 for (i = 0; i < num_local_groups; i++) {
450 struct wb_acct_info *lg = &local_groups[i];
451 struct wbint_Principal *rg = &result[ti++];
453 sid_compose(&rg->sid, &domain->sid, lg->rid);
454 rg->type = SID_NAME_ALIAS;
455 rg->name = talloc_strdup(result, lg->acct_name);
456 if (rg->name == NULL) {
457 TALLOC_FREE(result);
458 TALLOC_FREE(dom_groups);
459 TALLOC_FREE(local_groups);
460 return NT_STATUS_NO_MEMORY;
463 num_local_groups = 0;
464 TALLOC_FREE(local_groups);
466 for (i = 0; i < num_dom_groups; i++) {
467 struct wb_acct_info *dg = &dom_groups[i];
468 struct wbint_Principal *rg = &result[ti++];
470 sid_compose(&rg->sid, &domain->sid, dg->rid);
471 rg->type = SID_NAME_DOM_GRP;
472 rg->name = talloc_strdup(result, dg->acct_name);
473 if (rg->name == NULL) {
474 TALLOC_FREE(result);
475 TALLOC_FREE(dom_groups);
476 TALLOC_FREE(local_groups);
477 return NT_STATUS_NO_MEMORY;
480 num_dom_groups = 0;
481 TALLOC_FREE(dom_groups);
483 r->out.groups->num_principals = ti;
484 r->out.groups->principals = result;
486 return NT_STATUS_OK;
489 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
491 struct winbindd_domain *domain = wb_child_domain();
492 struct rpc_pipe_client *netlogon_pipe;
493 struct netr_DsRGetDCNameInfo *dc_info;
494 NTSTATUS status;
495 WERROR werr;
496 unsigned int orig_timeout;
497 struct dcerpc_binding_handle *b;
499 if (domain == NULL) {
500 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
501 r->in.domain_name, r->in.domain_guid,
502 r->in.site_name ? r->in.site_name : "",
503 r->in.flags,
504 r->out.dc_info);
507 status = cm_connect_netlogon(domain, &netlogon_pipe);
509 reset_cm_connection_on_error(domain, status);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
512 return status;
515 b = netlogon_pipe->binding_handle;
517 /* This call can take a long time - allow the server to time out.
518 35 seconds should do it. */
520 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
522 if (domain->active_directory) {
523 status = dcerpc_netr_DsRGetDCName(b,
524 p->mem_ctx, domain->dcname,
525 r->in.domain_name, NULL, r->in.domain_guid,
526 r->in.flags, r->out.dc_info, &werr);
527 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
528 goto done;
530 if (reset_cm_connection_on_error(domain, status)) {
531 /* Re-initialize. */
532 status = cm_connect_netlogon(domain, &netlogon_pipe);
534 reset_cm_connection_on_error(domain, status);
535 if (!NT_STATUS_IS_OK(status)) {
536 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
537 return status;
540 b = netlogon_pipe->binding_handle;
542 /* This call can take a long time - allow the server to time out.
543 35 seconds should do it. */
545 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
550 * Fallback to less capable methods
553 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
554 if (dc_info == NULL) {
555 status = NT_STATUS_NO_MEMORY;
556 goto done;
559 if (r->in.flags & DS_PDC_REQUIRED) {
560 status = dcerpc_netr_GetDcName(b,
561 p->mem_ctx, domain->dcname,
562 r->in.domain_name, &dc_info->dc_unc, &werr);
563 } else {
564 status = dcerpc_netr_GetAnyDCName(b,
565 p->mem_ctx, domain->dcname,
566 r->in.domain_name, &dc_info->dc_unc, &werr);
569 reset_cm_connection_on_error(domain, status);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
572 nt_errstr(status)));
573 goto done;
575 if (!W_ERROR_IS_OK(werr)) {
576 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
577 win_errstr(werr)));
578 status = werror_to_ntstatus(werr);
579 goto done;
582 *r->out.dc_info = dc_info;
583 status = NT_STATUS_OK;
585 done:
586 /* And restore our original timeout. */
587 rpccli_set_timeout(netlogon_pipe, orig_timeout);
589 return status;
592 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
594 struct winbindd_domain *domain = wb_child_domain();
595 char *domain_name;
596 char **names;
597 enum lsa_SidType *types;
598 struct wbint_Principal *result;
599 NTSTATUS status;
600 int i;
602 if (domain == NULL) {
603 return NT_STATUS_REQUEST_NOT_ACCEPTED;
606 status = domain->methods->rids_to_names(
607 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
608 r->in.rids->num_rids, &domain_name, &names, &types);
609 reset_cm_connection_on_error(domain, status);
610 if (!NT_STATUS_IS_OK(status)) {
611 return status;
614 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
616 result = talloc_array(p->mem_ctx, struct wbint_Principal,
617 r->in.rids->num_rids);
618 if (result == NULL) {
619 return NT_STATUS_NO_MEMORY;
622 for (i=0; i<r->in.rids->num_rids; i++) {
623 sid_compose(&result[i].sid, r->in.domain_sid,
624 r->in.rids->rids[i]);
625 result[i].type = types[i];
626 result[i].name = talloc_move(result, &names[i]);
628 TALLOC_FREE(types);
629 TALLOC_FREE(names);
631 r->out.names->num_principals = r->in.rids->num_rids;
632 r->out.names->principals = result;
633 return NT_STATUS_OK;
636 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
637 struct wbint_CheckMachineAccount *r)
639 struct winbindd_domain *domain;
640 int num_retries = 0;
641 NTSTATUS status;
643 domain = wb_child_domain();
644 if (domain == NULL) {
645 return NT_STATUS_REQUEST_NOT_ACCEPTED;
648 again:
649 invalidate_cm_connection(domain);
650 domain->conn.netlogon_force_reauth = true;
653 struct rpc_pipe_client *netlogon_pipe;
654 status = cm_connect_netlogon(domain, &netlogon_pipe);
657 /* There is a race condition between fetching the trust account
658 password and the periodic machine password change. So it's
659 possible that the trust account password has been changed on us.
660 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
662 #define MAX_RETRIES 3
664 if ((num_retries < MAX_RETRIES)
665 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
666 num_retries++;
667 goto again;
670 if (!NT_STATUS_IS_OK(status)) {
671 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
672 goto done;
675 /* Pass back result code - zero for success, other values for
676 specific failures. */
678 DEBUG(3,("domain %s secret is %s\n", domain->name,
679 NT_STATUS_IS_OK(status) ? "good" : "bad"));
681 done:
682 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
683 ("Checking the trust account password for domain %s returned %s\n",
684 domain->name, nt_errstr(status)));
686 return status;
689 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
690 struct wbint_ChangeMachineAccount *r)
692 struct messaging_context *msg_ctx = winbind_messaging_context();
693 struct winbindd_domain *domain;
694 NTSTATUS status;
695 struct rpc_pipe_client *netlogon_pipe;
697 domain = wb_child_domain();
698 if (domain == NULL) {
699 return NT_STATUS_REQUEST_NOT_ACCEPTED;
702 status = cm_connect_netlogon(domain, &netlogon_pipe);
703 if (!NT_STATUS_IS_OK(status)) {
704 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
705 goto done;
708 status = trust_pw_change(domain->conn.netlogon_creds,
709 msg_ctx,
710 netlogon_pipe->binding_handle,
711 domain->name,
712 true); /* force */
714 /* Pass back result code - zero for success, other values for
715 specific failures. */
717 DEBUG(3,("domain %s secret %s\n", domain->name,
718 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
720 done:
721 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
722 ("Changing the trust account password for domain %s returned %s\n",
723 domain->name, nt_errstr(status)));
725 return status;
728 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
730 NTSTATUS status;
731 struct winbindd_domain *domain;
732 struct rpc_pipe_client *netlogon_pipe;
733 union netr_CONTROL_QUERY_INFORMATION info;
734 WERROR werr;
735 fstring logon_server;
736 struct dcerpc_binding_handle *b;
737 bool retry = false;
739 domain = wb_child_domain();
740 if (domain == NULL) {
741 return NT_STATUS_REQUEST_NOT_ACCEPTED;
744 reconnect:
745 status = cm_connect_netlogon(domain, &netlogon_pipe);
746 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
748 * Retry to open new connection with new kerberos ticket.
750 invalidate_cm_connection(domain);
751 status = cm_connect_netlogon(domain, &netlogon_pipe);
754 reset_cm_connection_on_error(domain, status);
755 if (!NT_STATUS_IS_OK(status)) {
756 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
757 nt_errstr(status)));
758 return status;
761 b = netlogon_pipe->binding_handle;
763 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
764 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
765 if (*r->out.dcname == NULL) {
766 DEBUG(2, ("Could not allocate memory\n"));
767 return NT_STATUS_NO_MEMORY;
771 * This provokes a WERR_NOT_SUPPORTED error message. This is
772 * documented in the wspp docs. I could not get a successful
773 * call to work, but the main point here is testing that the
774 * netlogon pipe works.
776 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
777 logon_server, NETLOGON_CONTROL_QUERY,
778 2, &info, &werr);
780 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
781 DEBUG(10, ("Session might have expired. "
782 "Reconnect and retry once.\n"));
783 invalidate_cm_connection(domain);
784 retry = true;
785 goto reconnect;
788 reset_cm_connection_on_error(domain, status);
789 if (!NT_STATUS_IS_OK(status)) {
790 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
791 nt_errstr(status)));
792 return status;
795 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
796 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
797 "WERR_NOT_SUPPORTED\n",
798 win_errstr(werr)));
799 return werror_to_ntstatus(werr);
802 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
803 return NT_STATUS_OK;
806 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
807 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
809 struct winbindd_domain *domain;
810 NTSTATUS status;
811 struct rpc_pipe_client *netlogon_pipe;
813 domain = wb_child_domain();
814 if (domain == NULL) {
815 return NT_STATUS_REQUEST_NOT_ACCEPTED;
818 status = cm_connect_netlogon(domain, &netlogon_pipe);
819 if (!NT_STATUS_IS_OK(status)) {
820 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
821 goto done;
824 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
825 netlogon_pipe->binding_handle,
826 r->in.site_name,
827 r->in.dns_ttl,
828 r->in.dns_names);
830 /* Pass back result code - zero for success, other values for
831 specific failures. */
833 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
834 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
836 done:
837 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
838 ("Update of DNS records via RW DC %s returned %s\n",
839 domain->name, nt_errstr(status)));
841 return status;
844 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
845 struct winbind_SamLogon *r)
847 struct winbindd_domain *domain;
848 NTSTATUS status;
849 DATA_BLOB lm_response, nt_response;
850 domain = wb_child_domain();
851 if (domain == NULL) {
852 return NT_STATUS_REQUEST_NOT_ACCEPTED;
855 /* TODO: Handle interactive logons here */
856 if (r->in.validation_level != 3 ||
857 r->in.logon.network == NULL ||
858 (r->in.logon_level != NetlogonNetworkInformation
859 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
860 return NT_STATUS_REQUEST_NOT_ACCEPTED;
864 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
865 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
867 status = winbind_dual_SamLogon(domain, p->mem_ctx,
868 r->in.logon.network->identity_info.parameter_control,
869 r->in.logon.network->identity_info.account_name.string,
870 r->in.logon.network->identity_info.domain_name.string,
871 r->in.logon.network->identity_info.workstation.string,
872 r->in.logon.network->challenge,
873 lm_response, nt_response, &r->out.validation.sam3);
874 return status;
877 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
878 struct winbindd_domain *domain,
879 struct winbind_LogonControl *r)
881 NTSTATUS status;
882 struct rpc_pipe_client *netlogon_pipe = NULL;
883 struct netr_NETLOGON_INFO_2 *info2 = NULL;
884 WERROR check_result = WERR_INTERNAL_ERROR;
886 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
887 if (info2 == NULL) {
888 return WERR_NOMEM;
891 if (domain->internal) {
892 check_result = WERR_OK;
893 goto check_return;
897 * For now we just force a reconnect
899 * TODO: take care of the optional '\dcname'
901 invalidate_cm_connection(domain);
902 domain->conn.netlogon_force_reauth = true;
903 status = cm_connect_netlogon(domain, &netlogon_pipe);
904 reset_cm_connection_on_error(domain, status);
905 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
906 status = NT_STATUS_NO_LOGON_SERVERS;
908 if (!NT_STATUS_IS_OK(status)) {
909 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
910 __func__, domain->name, domain->alt_name,
911 nt_errstr(status)));
913 * Here we return a top level error!
914 * This is different than TC_QUERY or TC_VERIFY.
916 return ntstatus_to_werror(status);
918 check_result = WERR_OK;
920 check_return:
921 info2->pdc_connection_status = WERR_OK;
922 if (domain->dcname != NULL) {
923 info2->flags |= NETLOGON_HAS_IP;
924 info2->flags |= NETLOGON_HAS_TIMESERV;
925 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
926 domain->dcname);
927 if (info2->trusted_dc_name == NULL) {
928 return WERR_NOMEM;
930 } else {
931 info2->trusted_dc_name = talloc_strdup(info2, "");
932 if (info2->trusted_dc_name == NULL) {
933 return WERR_NOMEM;
936 info2->tc_connection_status = check_result;
938 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
939 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
940 "pdc_connection[%s] tc_connection[%s]\n",
941 __func__, domain->name, domain->alt_name,
942 domain->dcname,
943 win_errstr(info2->pdc_connection_status),
944 win_errstr(info2->tc_connection_status)));
947 r->out.query->info2 = info2;
949 DEBUG(5, ("%s: succeeded.\n", __func__));
950 return WERR_OK;
953 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
954 struct winbindd_domain *domain,
955 struct winbind_LogonControl *r)
957 NTSTATUS status;
958 struct rpc_pipe_client *netlogon_pipe = NULL;
959 struct netr_NETLOGON_INFO_2 *info2 = NULL;
960 WERROR check_result = WERR_INTERNAL_ERROR;
962 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
963 if (info2 == NULL) {
964 return WERR_NOMEM;
967 if (domain->internal) {
968 check_result = WERR_OK;
969 goto check_return;
972 status = cm_connect_netlogon(domain, &netlogon_pipe);
973 reset_cm_connection_on_error(domain, status);
974 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
975 status = NT_STATUS_NO_LOGON_SERVERS;
977 if (!NT_STATUS_IS_OK(status)) {
978 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
979 nt_errstr(status)));
980 check_result = ntstatus_to_werror(status);
981 goto check_return;
983 check_result = WERR_OK;
985 check_return:
986 info2->pdc_connection_status = WERR_OK;
987 if (domain->dcname != NULL) {
988 info2->flags |= NETLOGON_HAS_IP;
989 info2->flags |= NETLOGON_HAS_TIMESERV;
990 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
991 domain->dcname);
992 if (info2->trusted_dc_name == NULL) {
993 return WERR_NOMEM;
995 } else {
996 info2->trusted_dc_name = talloc_strdup(info2, "");
997 if (info2->trusted_dc_name == NULL) {
998 return WERR_NOMEM;
1001 info2->tc_connection_status = check_result;
1003 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1004 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1005 "pdc_connection[%s] tc_connection[%s]\n",
1006 __func__, domain->name, domain->alt_name,
1007 domain->dcname,
1008 win_errstr(info2->pdc_connection_status),
1009 win_errstr(info2->tc_connection_status)));
1012 r->out.query->info2 = info2;
1014 DEBUG(5, ("%s: succeeded.\n", __func__));
1015 return WERR_OK;
1018 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1019 struct winbindd_domain *domain,
1020 struct winbind_LogonControl *r)
1022 TALLOC_CTX *frame = talloc_stackframe();
1023 NTSTATUS status;
1024 NTSTATUS result;
1025 struct lsa_String trusted_domain_name = {};
1026 struct lsa_StringLarge trusted_domain_name_l = {};
1027 struct rpc_pipe_client *local_lsa_pipe = NULL;
1028 struct policy_handle local_lsa_policy = {};
1029 struct dcerpc_binding_handle *local_lsa = NULL;
1030 struct rpc_pipe_client *netlogon_pipe = NULL;
1031 struct cli_credentials *creds = NULL;
1032 struct samr_Password *cur_nt_hash = NULL;
1033 uint32_t trust_attributes = 0;
1034 struct samr_Password new_owf_password = {};
1035 int cmp_new = -1;
1036 struct samr_Password old_owf_password = {};
1037 int cmp_old = -1;
1038 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1039 bool fetch_fti = false;
1040 struct lsa_ForestTrustInformation *new_fti = NULL;
1041 struct netr_TrustInfo *trust_info = NULL;
1042 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1043 struct dcerpc_binding_handle *b = NULL;
1044 WERROR check_result = WERR_INTERNAL_ERROR;
1045 WERROR verify_result = WERR_INTERNAL_ERROR;
1046 bool retry = false;
1048 trusted_domain_name.string = domain->name;
1049 trusted_domain_name_l.string = domain->name;
1051 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1052 if (info2 == NULL) {
1053 TALLOC_FREE(frame);
1054 return WERR_NOMEM;
1057 if (domain->internal) {
1058 check_result = WERR_OK;
1059 goto check_return;
1062 status = pdb_get_trust_credentials(domain->name,
1063 domain->alt_name,
1064 frame,
1065 &creds);
1066 if (NT_STATUS_IS_OK(status)) {
1067 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1068 TALLOC_FREE(creds);
1071 if (!domain->primary) {
1072 union lsa_TrustedDomainInfo *tdi = NULL;
1074 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1075 &local_lsa_policy);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1078 __location__, __func__, nt_errstr(status)));
1079 TALLOC_FREE(frame);
1080 return WERR_INTERNAL_ERROR;
1082 local_lsa = local_lsa_pipe->binding_handle;
1084 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1085 &local_lsa_policy,
1086 &trusted_domain_name,
1087 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1088 &tdi, &result);
1089 if (!NT_STATUS_IS_OK(status)) {
1090 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1091 __location__, __func__, domain->name, nt_errstr(status)));
1092 TALLOC_FREE(frame);
1093 return WERR_INTERNAL_ERROR;
1095 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1096 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1097 __location__, __func__, domain->name));
1098 TALLOC_FREE(frame);
1099 return WERR_NO_SUCH_DOMAIN;
1101 if (!NT_STATUS_IS_OK(result)) {
1102 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1103 __location__, __func__, domain->name, nt_errstr(result)));
1104 TALLOC_FREE(frame);
1105 return WERR_INTERNAL_ERROR;
1107 if (tdi == NULL) {
1108 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1109 "returned no trusted domain information\n",
1110 __location__, __func__));
1111 TALLOC_FREE(frame);
1112 return WERR_INTERNAL_ERROR;
1115 local_tdo = &tdi->info_ex;
1116 trust_attributes = local_tdo->trust_attributes;
1119 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1120 struct lsa_ForestTrustInformation *old_fti = NULL;
1122 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1123 &local_lsa_policy,
1124 &trusted_domain_name,
1125 LSA_FOREST_TRUST_DOMAIN_INFO,
1126 &old_fti, &result);
1127 if (!NT_STATUS_IS_OK(status)) {
1128 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1129 __location__, __func__, domain->name, nt_errstr(status)));
1130 TALLOC_FREE(frame);
1131 return WERR_INTERNAL_ERROR;
1133 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1134 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1135 __func__, domain->name));
1136 old_fti = NULL;
1137 fetch_fti = true;
1138 result = NT_STATUS_OK;
1140 if (!NT_STATUS_IS_OK(result)) {
1141 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1142 __location__, __func__, domain->name, nt_errstr(result)));
1143 TALLOC_FREE(frame);
1144 return WERR_INTERNAL_ERROR;
1147 TALLOC_FREE(old_fti);
1150 reconnect:
1151 status = cm_connect_netlogon(domain, &netlogon_pipe);
1152 reset_cm_connection_on_error(domain, status);
1153 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1154 status = NT_STATUS_NO_LOGON_SERVERS;
1156 if (!NT_STATUS_IS_OK(status)) {
1157 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1158 nt_errstr(status)));
1159 check_result = ntstatus_to_werror(status);
1160 goto check_return;
1162 check_result = WERR_OK;
1163 b = netlogon_pipe->binding_handle;
1165 if (cur_nt_hash == NULL) {
1166 verify_result = WERR_NO_TRUST_LSA_SECRET;
1167 goto verify_return;
1170 if (fetch_fti) {
1171 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1172 b, frame,
1173 &new_fti);
1174 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1175 status = NT_STATUS_NOT_SUPPORTED;
1177 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1178 new_fti = NULL;
1179 status = NT_STATUS_OK;
1181 if (!NT_STATUS_IS_OK(status)) {
1182 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1183 invalidate_cm_connection(domain);
1184 retry = true;
1185 goto reconnect;
1187 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1188 "failed: %s\n",
1189 domain->name, nt_errstr(status)));
1190 check_result = ntstatus_to_werror(status);
1191 goto check_return;
1195 if (new_fti != NULL) {
1196 struct lsa_ForestTrustInformation old_fti = {};
1197 struct lsa_ForestTrustInformation *merged_fti = NULL;
1198 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1200 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1201 &old_fti, new_fti,
1202 &merged_fti);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1205 __location__, __func__,
1206 domain->name, nt_errstr(status)));
1207 TALLOC_FREE(frame);
1208 return ntstatus_to_werror(status);
1211 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1212 &local_lsa_policy,
1213 &trusted_domain_name_l,
1214 LSA_FOREST_TRUST_DOMAIN_INFO,
1215 merged_fti,
1216 0, /* check_only=0 => store it! */
1217 &collision_info,
1218 &result);
1219 if (!NT_STATUS_IS_OK(status)) {
1220 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1221 __location__, __func__, domain->name, nt_errstr(status)));
1222 TALLOC_FREE(frame);
1223 return WERR_INTERNAL_ERROR;
1225 if (!NT_STATUS_IS_OK(result)) {
1226 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1227 __location__, __func__, domain->name, nt_errstr(result)));
1228 TALLOC_FREE(frame);
1229 return ntstatus_to_werror(result);
1233 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1234 b, frame,
1235 &new_owf_password,
1236 &old_owf_password,
1237 &trust_info);
1238 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1239 status = NT_STATUS_NOT_SUPPORTED;
1241 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1242 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1243 nt_errstr(status)));
1244 verify_result = WERR_OK;
1245 goto verify_return;
1247 if (!NT_STATUS_IS_OK(status)) {
1248 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1249 invalidate_cm_connection(domain);
1250 retry = true;
1251 goto reconnect;
1253 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1254 nt_errstr(status)));
1256 if (!dcerpc_binding_handle_is_connected(b)) {
1257 check_result = ntstatus_to_werror(status);
1258 goto check_return;
1259 } else {
1260 verify_result = ntstatus_to_werror(status);
1261 goto verify_return;
1265 if (trust_info != NULL && trust_info->count >= 1) {
1266 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1268 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1269 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1270 goto verify_return;
1274 cmp_new = memcmp(new_owf_password.hash,
1275 cur_nt_hash->hash,
1276 sizeof(cur_nt_hash->hash));
1277 cmp_old = memcmp(old_owf_password.hash,
1278 cur_nt_hash->hash,
1279 sizeof(cur_nt_hash->hash));
1280 if (cmp_new != 0 && cmp_old != 0) {
1281 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1282 "any password known to dcname[%s]\n",
1283 __func__, domain->name, domain->alt_name,
1284 domain->dcname));
1285 verify_result = WERR_WRONG_PASSWORD;
1286 goto verify_return;
1289 if (cmp_new != 0) {
1290 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1291 "against the old password known to dcname[%s]\n",
1292 __func__, domain->name, domain->alt_name,
1293 domain->dcname));
1296 verify_result = WERR_OK;
1297 goto verify_return;
1299 check_return:
1300 verify_result = check_result;
1301 verify_return:
1302 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1303 info2->pdc_connection_status = verify_result;
1304 if (domain->dcname != NULL) {
1305 info2->flags |= NETLOGON_HAS_IP;
1306 info2->flags |= NETLOGON_HAS_TIMESERV;
1307 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1308 domain->dcname);
1309 if (info2->trusted_dc_name == NULL) {
1310 TALLOC_FREE(frame);
1311 return WERR_NOMEM;
1313 } else {
1314 info2->trusted_dc_name = talloc_strdup(info2, "");
1315 if (info2->trusted_dc_name == NULL) {
1316 TALLOC_FREE(frame);
1317 return WERR_NOMEM;
1320 info2->tc_connection_status = check_result;
1322 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1323 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1324 "pdc_connection[%s] tc_connection[%s]\n",
1325 __func__, domain->name, domain->alt_name,
1326 domain->dcname,
1327 win_errstr(info2->pdc_connection_status),
1328 win_errstr(info2->tc_connection_status)));
1331 r->out.query->info2 = info2;
1333 DEBUG(5, ("%s: succeeded.\n", __func__));
1334 TALLOC_FREE(frame);
1335 return WERR_OK;
1338 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1339 struct winbindd_domain *domain,
1340 struct winbind_LogonControl *r)
1342 struct messaging_context *msg_ctx = winbind_messaging_context();
1343 NTSTATUS status;
1344 struct rpc_pipe_client *netlogon_pipe;
1345 struct cli_credentials *creds = NULL;
1346 struct samr_Password *cur_nt_hash = NULL;
1347 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1348 struct dcerpc_binding_handle *b;
1349 WERROR change_result = WERR_OK;
1350 bool retry = false;
1352 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1353 if (info1 == NULL) {
1354 return WERR_NOMEM;
1357 if (domain->internal) {
1358 return WERR_NOT_SUPPORTED;
1361 status = pdb_get_trust_credentials(domain->name,
1362 domain->alt_name,
1363 p->mem_ctx,
1364 &creds);
1365 if (NT_STATUS_IS_OK(status)) {
1366 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1367 TALLOC_FREE(creds);
1370 reconnect:
1371 status = cm_connect_netlogon(domain, &netlogon_pipe);
1372 reset_cm_connection_on_error(domain, status);
1373 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1374 status = NT_STATUS_NO_LOGON_SERVERS;
1376 if (!NT_STATUS_IS_OK(status)) {
1377 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1378 __func__, domain->name, domain->alt_name,
1379 nt_errstr(status)));
1381 * Here we return a top level error!
1382 * This is different than TC_QUERY or TC_VERIFY.
1384 return ntstatus_to_werror(status);
1386 b = netlogon_pipe->binding_handle;
1388 if (cur_nt_hash == NULL) {
1389 change_result = WERR_NO_TRUST_LSA_SECRET;
1390 goto change_return;
1392 TALLOC_FREE(cur_nt_hash);
1394 status = trust_pw_change(domain->conn.netlogon_creds,
1395 msg_ctx, b, domain->name,
1396 true); /* force */
1397 if (!NT_STATUS_IS_OK(status)) {
1398 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1399 invalidate_cm_connection(domain);
1400 retry = true;
1401 goto reconnect;
1404 DEBUG(1, ("trust_pw_change(%s): %s\n",
1405 domain->name, nt_errstr(status)));
1407 change_result = ntstatus_to_werror(status);
1408 goto change_return;
1411 change_result = WERR_OK;
1413 change_return:
1414 info1->pdc_connection_status = change_result;
1416 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1417 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1418 "pdc_connection[%s]\n",
1419 __func__, domain->name, domain->alt_name,
1420 domain->dcname,
1421 win_errstr(info1->pdc_connection_status)));
1424 r->out.query->info1 = info1;
1426 DEBUG(5, ("%s: succeeded.\n", __func__));
1427 return WERR_OK;
1430 WERROR _winbind_LogonControl(struct pipes_struct *p,
1431 struct winbind_LogonControl *r)
1433 struct winbindd_domain *domain;
1435 domain = wb_child_domain();
1436 if (domain == NULL) {
1437 return WERR_NO_SUCH_DOMAIN;
1440 switch (r->in.function_code) {
1441 case NETLOGON_CONTROL_REDISCOVER:
1442 if (r->in.level != 2) {
1443 return WERR_INVALID_PARAMETER;
1445 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1446 case NETLOGON_CONTROL_TC_QUERY:
1447 if (r->in.level != 2) {
1448 return WERR_INVALID_PARAMETER;
1450 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1451 case NETLOGON_CONTROL_TC_VERIFY:
1452 if (r->in.level != 2) {
1453 return WERR_INVALID_PARAMETER;
1455 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1456 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1457 if (r->in.level != 1) {
1458 return WERR_INVALID_PARAMETER;
1460 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1461 default:
1462 break;
1465 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1466 __func__, r->in.function_code));
1467 return WERR_NOT_SUPPORTED;
1470 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1471 struct winbind_GetForestTrustInformation *r)
1473 TALLOC_CTX *frame = talloc_stackframe();
1474 NTSTATUS status, result;
1475 struct winbindd_domain *domain;
1476 struct rpc_pipe_client *netlogon_pipe;
1477 struct dcerpc_binding_handle *b;
1478 bool retry = false;
1479 struct lsa_String trusted_domain_name = {};
1480 struct lsa_StringLarge trusted_domain_name_l = {};
1481 union lsa_TrustedDomainInfo *tdi = NULL;
1482 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1483 struct lsa_ForestTrustInformation _old_fti = {};
1484 struct lsa_ForestTrustInformation *old_fti = NULL;
1485 struct lsa_ForestTrustInformation *new_fti = NULL;
1486 struct lsa_ForestTrustInformation *merged_fti = NULL;
1487 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1488 bool update_fti = false;
1489 struct rpc_pipe_client *local_lsa_pipe;
1490 struct policy_handle local_lsa_policy;
1491 struct dcerpc_binding_handle *local_lsa = NULL;
1493 domain = wb_child_domain();
1494 if (domain == NULL) {
1495 TALLOC_FREE(frame);
1496 return WERR_NO_SUCH_DOMAIN;
1500 * checking for domain->internal and domain->primary
1501 * makes sure we only do some work when running as DC.
1504 if (domain->internal) {
1505 TALLOC_FREE(frame);
1506 return WERR_NO_SUCH_DOMAIN;
1509 if (domain->primary) {
1510 TALLOC_FREE(frame);
1511 return WERR_NO_SUCH_DOMAIN;
1514 trusted_domain_name.string = domain->name;
1515 trusted_domain_name_l.string = domain->name;
1517 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1518 &local_lsa_policy);
1519 if (!NT_STATUS_IS_OK(status)) {
1520 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1521 __location__, __func__, nt_errstr(status)));
1522 TALLOC_FREE(frame);
1523 return WERR_INTERNAL_ERROR;
1525 local_lsa = local_lsa_pipe->binding_handle;
1527 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1528 &local_lsa_policy,
1529 &trusted_domain_name,
1530 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1531 &tdi, &result);
1532 if (!NT_STATUS_IS_OK(status)) {
1533 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1534 __location__, __func__, domain->name, nt_errstr(status)));
1535 TALLOC_FREE(frame);
1536 return WERR_INTERNAL_ERROR;
1538 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1539 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1540 __location__, __func__, domain->name));
1541 TALLOC_FREE(frame);
1542 return WERR_NO_SUCH_DOMAIN;
1544 if (!NT_STATUS_IS_OK(result)) {
1545 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1546 __location__, __func__, domain->name, nt_errstr(result)));
1547 TALLOC_FREE(frame);
1548 return WERR_INTERNAL_ERROR;
1550 if (tdi == NULL) {
1551 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1552 "returned no trusted domain information\n",
1553 __location__, __func__));
1554 TALLOC_FREE(frame);
1555 return WERR_INTERNAL_ERROR;
1558 tdo = &tdi->info_ex;
1560 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1561 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1562 __func__, tdo->netbios_name.string,
1563 tdo->domain_name.string,
1564 (unsigned)tdo->trust_attributes));
1565 TALLOC_FREE(frame);
1566 return WERR_NO_SUCH_DOMAIN;
1569 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1570 TALLOC_FREE(frame);
1571 return WERR_INVALID_FLAGS;
1574 reconnect:
1575 status = cm_connect_netlogon(domain, &netlogon_pipe);
1576 reset_cm_connection_on_error(domain, status);
1577 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1578 status = NT_STATUS_NO_LOGON_SERVERS;
1580 if (!NT_STATUS_IS_OK(status)) {
1581 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1582 nt_errstr(status)));
1583 TALLOC_FREE(frame);
1584 return ntstatus_to_werror(status);
1586 b = netlogon_pipe->binding_handle;
1588 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1589 b, p->mem_ctx,
1590 &new_fti);
1591 if (!NT_STATUS_IS_OK(status)) {
1592 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1593 invalidate_cm_connection(domain);
1594 retry = true;
1595 goto reconnect;
1597 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1598 domain->name, nt_errstr(status)));
1599 TALLOC_FREE(frame);
1600 return ntstatus_to_werror(status);
1603 *r->out.forest_trust_info = new_fti;
1605 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1606 update_fti = true;
1609 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1610 &local_lsa_policy,
1611 &trusted_domain_name,
1612 LSA_FOREST_TRUST_DOMAIN_INFO,
1613 &old_fti, &result);
1614 if (!NT_STATUS_IS_OK(status)) {
1615 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1616 __location__, __func__, domain->name, nt_errstr(status)));
1617 TALLOC_FREE(frame);
1618 return WERR_INTERNAL_ERROR;
1620 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1621 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1622 __func__, domain->name));
1623 update_fti = true;
1624 old_fti = &_old_fti;
1625 result = NT_STATUS_OK;
1627 if (!NT_STATUS_IS_OK(result)) {
1628 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1629 __location__, __func__, domain->name, nt_errstr(result)));
1630 TALLOC_FREE(frame);
1631 return WERR_INTERNAL_ERROR;
1634 if (old_fti == NULL) {
1635 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1636 "returned success without returning forest trust information\n",
1637 __location__, __func__));
1638 TALLOC_FREE(frame);
1639 return WERR_INTERNAL_ERROR;
1642 if (!update_fti) {
1643 goto done;
1646 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1647 &merged_fti);
1648 if (!NT_STATUS_IS_OK(status)) {
1649 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1650 __location__, __func__, domain->name, nt_errstr(status)));
1651 TALLOC_FREE(frame);
1652 return ntstatus_to_werror(status);
1655 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1656 &local_lsa_policy,
1657 &trusted_domain_name_l,
1658 LSA_FOREST_TRUST_DOMAIN_INFO,
1659 merged_fti,
1660 0, /* check_only=0 => store it! */
1661 &collision_info,
1662 &result);
1663 if (!NT_STATUS_IS_OK(status)) {
1664 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1665 __location__, __func__, domain->name, nt_errstr(status)));
1666 TALLOC_FREE(frame);
1667 return WERR_INTERNAL_ERROR;
1669 if (!NT_STATUS_IS_OK(result)) {
1670 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1671 __location__, __func__, domain->name, nt_errstr(result)));
1672 TALLOC_FREE(frame);
1673 return ntstatus_to_werror(result);
1676 done:
1677 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1678 TALLOC_FREE(frame);
1679 return WERR_OK;