auth/auth_sam_reply: add some const to input parameters
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blobfb65e9d1c30bac50ad621a08352789d91fd12d17
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;
126 struct lsa_DomainInfo *d;
127 struct wbint_TransID *ids;
128 uint32_t num_ids;
130 struct id_map **id_map_ptrs = NULL;
131 struct idmap_domain *dom;
132 NTSTATUS status = NT_STATUS_NO_MEMORY;
134 if (r->in.domains->count != 1) {
135 return NT_STATUS_INVALID_PARAMETER;
138 d = &r->in.domains->domains[0];
139 ids = r->in.ids->ids;
140 num_ids = r->in.ids->num_ids;
142 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
143 if (dom == NULL) {
144 DEBUG(10, ("idmap domain %s:%s not found\n",
145 d->name.string, sid_string_dbg(d->sid)));
147 for (i=0; i<num_ids; i++) {
149 ids[i].xid = (struct unixid) {
150 .id = UINT32_MAX,
151 .type = ID_TYPE_NOT_SPECIFIED
155 return NT_STATUS_OK;
158 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
159 if (id_map_ptrs == NULL) {
160 goto nomem;
164 * Convert the input data into a list of id_map structs
165 * suitable for handing in to the idmap sids_to_unixids
166 * method.
169 for (i=0; i<num_ids; i++) {
170 struct id_map *m = id_map_ptrs[i];
172 sid_compose(m->sid, d->sid, ids[i].rid);
173 m->status = ID_UNKNOWN;
174 m->xid = (struct unixid) { .type = ids[i].type };
177 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
179 if (!NT_STATUS_IS_OK(status)) {
180 DEBUG(10, ("sids_to_unixids returned %s\n",
181 nt_errstr(status)));
182 goto done;
186 * Extract the results for handing them back to the caller.
189 for (i=0; i<num_ids; i++) {
190 struct id_map *m = id_map_ptrs[i];
192 if (m->status == ID_MAPPED) {
193 ids[i].xid = m->xid;
194 } else {
195 ids[i].xid.id = UINT32_MAX;
196 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
200 goto done;
201 nomem:
202 status = NT_STATUS_NO_MEMORY;
203 done:
204 TALLOC_FREE(id_map_ptrs);
205 return status;
208 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
209 struct wbint_UnixIDs2Sids *r)
211 struct id_map **maps;
212 NTSTATUS status;
213 uint32_t i;
215 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
216 if (maps == NULL) {
217 return NT_STATUS_NO_MEMORY;
220 for (i=0; i<r->in.num_ids; i++) {
221 maps[i]->status = ID_UNKNOWN;
222 maps[i]->xid = r->in.xids[i];
225 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name);
226 if (!NT_STATUS_IS_OK(status)) {
227 TALLOC_FREE(maps);
228 return status;
231 for (i=0; i<r->in.num_ids; i++) {
232 sid_copy(&r->out.sids[i], maps[i]->sid);
235 TALLOC_FREE(maps);
237 return NT_STATUS_OK;
240 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
242 struct unixid xid;
243 NTSTATUS status;
245 status = idmap_allocate_uid(&xid);
246 if (!NT_STATUS_IS_OK(status)) {
247 return status;
249 *r->out.uid = xid.id;
250 return NT_STATUS_OK;
253 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
255 struct unixid xid;
256 NTSTATUS status;
258 status = idmap_allocate_gid(&xid);
259 if (!NT_STATUS_IS_OK(status)) {
260 return status;
262 *r->out.gid = xid.id;
263 return NT_STATUS_OK;
266 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
268 struct winbindd_domain *domain = wb_child_domain();
269 NTSTATUS status;
271 if (domain == NULL) {
272 return NT_STATUS_REQUEST_NOT_ACCEPTED;
275 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
276 r->out.info);
277 reset_cm_connection_on_error(domain, status);
278 return status;
281 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
282 struct wbint_LookupUserAliases *r)
284 struct winbindd_domain *domain = wb_child_domain();
285 NTSTATUS status;
287 if (domain == NULL) {
288 return NT_STATUS_REQUEST_NOT_ACCEPTED;
291 status = domain->methods->lookup_useraliases(
292 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
293 &r->out.rids->num_rids, &r->out.rids->rids);
294 reset_cm_connection_on_error(domain, status);
295 return status;
298 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
299 struct wbint_LookupUserGroups *r)
301 struct winbindd_domain *domain = wb_child_domain();
302 NTSTATUS status;
304 if (domain == NULL) {
305 return NT_STATUS_REQUEST_NOT_ACCEPTED;
308 status = domain->methods->lookup_usergroups(
309 domain, p->mem_ctx, r->in.sid,
310 &r->out.sids->num_sids, &r->out.sids->sids);
311 reset_cm_connection_on_error(domain, status);
312 return status;
315 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
316 struct wbint_QuerySequenceNumber *r)
318 struct winbindd_domain *domain = wb_child_domain();
319 NTSTATUS status;
321 if (domain == NULL) {
322 return NT_STATUS_REQUEST_NOT_ACCEPTED;
325 status = domain->methods->sequence_number(domain, r->out.sequence);
326 reset_cm_connection_on_error(domain, status);
327 return status;
330 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
331 struct wbint_LookupGroupMembers *r)
333 struct winbindd_domain *domain = wb_child_domain();
334 uint32_t i, num_names;
335 struct dom_sid *sid_mem;
336 char **names;
337 uint32_t *name_types;
338 NTSTATUS status;
340 if (domain == NULL) {
341 return NT_STATUS_REQUEST_NOT_ACCEPTED;
344 status = domain->methods->lookup_groupmem(
345 domain, p->mem_ctx, r->in.sid, r->in.type,
346 &num_names, &sid_mem, &names, &name_types);
347 reset_cm_connection_on_error(domain, status);
348 if (!NT_STATUS_IS_OK(status)) {
349 return status;
352 r->out.members->num_principals = num_names;
353 r->out.members->principals = talloc_array(
354 r->out.members, struct wbint_Principal, num_names);
355 if (r->out.members->principals == NULL) {
356 return NT_STATUS_NO_MEMORY;
359 for (i=0; i<num_names; i++) {
360 struct wbint_Principal *m = &r->out.members->principals[i];
361 sid_copy(&m->sid, &sid_mem[i]);
362 m->name = talloc_move(r->out.members->principals, &names[i]);
363 m->type = (enum lsa_SidType)name_types[i];
366 return NT_STATUS_OK;
369 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
370 struct wbint_QueryUserList *r)
372 struct winbindd_domain *domain = wb_child_domain();
373 NTSTATUS status;
375 if (domain == NULL) {
376 return NT_STATUS_REQUEST_NOT_ACCEPTED;
379 status = domain->methods->query_user_list(
380 domain, p->mem_ctx, &r->out.users->num_userinfos,
381 &r->out.users->userinfos);
382 reset_cm_connection_on_error(domain, status);
383 return status;
386 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
387 struct wbint_QueryGroupList *r)
389 struct winbindd_domain *domain = wb_child_domain();
390 uint32_t i;
391 uint32_t num_local_groups = 0;
392 struct wb_acct_info *local_groups = NULL;
393 uint32_t num_dom_groups = 0;
394 struct wb_acct_info *dom_groups = NULL;
395 uint32_t ti = 0;
396 uint64_t num_total = 0;
397 struct wbint_Principal *result;
398 NTSTATUS status;
399 bool include_local_groups = false;
401 if (domain == NULL) {
402 return NT_STATUS_REQUEST_NOT_ACCEPTED;
405 switch (lp_server_role()) {
406 case ROLE_ACTIVE_DIRECTORY_DC:
407 if (domain->internal) {
409 * we want to include local groups
410 * for BUILTIN and WORKGROUP
412 include_local_groups = true;
414 break;
415 default:
417 * We might include local groups in more
418 * setups later, but that requires more work
419 * elsewhere.
421 break;
424 if (include_local_groups) {
425 status = domain->methods->enum_local_groups(domain, talloc_tos(),
426 &num_local_groups,
427 &local_groups);
428 reset_cm_connection_on_error(domain, status);
429 if (!NT_STATUS_IS_OK(status)) {
430 return status;
434 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
435 &num_dom_groups,
436 &dom_groups);
437 reset_cm_connection_on_error(domain, status);
438 if (!NT_STATUS_IS_OK(status)) {
439 return status;
442 num_total = num_local_groups + num_dom_groups;
443 if (num_total > UINT32_MAX) {
444 return NT_STATUS_INTERNAL_ERROR;
447 result = talloc_array(r->out.groups, struct wbint_Principal,
448 num_total);
449 if (result == NULL) {
450 return NT_STATUS_NO_MEMORY;
453 for (i = 0; i < num_local_groups; i++) {
454 struct wb_acct_info *lg = &local_groups[i];
455 struct wbint_Principal *rg = &result[ti++];
457 sid_compose(&rg->sid, &domain->sid, lg->rid);
458 rg->type = SID_NAME_ALIAS;
459 rg->name = talloc_strdup(result, lg->acct_name);
460 if (rg->name == NULL) {
461 TALLOC_FREE(result);
462 TALLOC_FREE(dom_groups);
463 TALLOC_FREE(local_groups);
464 return NT_STATUS_NO_MEMORY;
467 num_local_groups = 0;
468 TALLOC_FREE(local_groups);
470 for (i = 0; i < num_dom_groups; i++) {
471 struct wb_acct_info *dg = &dom_groups[i];
472 struct wbint_Principal *rg = &result[ti++];
474 sid_compose(&rg->sid, &domain->sid, dg->rid);
475 rg->type = SID_NAME_DOM_GRP;
476 rg->name = talloc_strdup(result, dg->acct_name);
477 if (rg->name == NULL) {
478 TALLOC_FREE(result);
479 TALLOC_FREE(dom_groups);
480 TALLOC_FREE(local_groups);
481 return NT_STATUS_NO_MEMORY;
484 num_dom_groups = 0;
485 TALLOC_FREE(dom_groups);
487 r->out.groups->num_principals = ti;
488 r->out.groups->principals = result;
490 return NT_STATUS_OK;
493 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
495 struct winbindd_domain *domain = wb_child_domain();
496 struct rpc_pipe_client *netlogon_pipe;
497 struct netr_DsRGetDCNameInfo *dc_info;
498 NTSTATUS status;
499 WERROR werr;
500 unsigned int orig_timeout;
501 struct dcerpc_binding_handle *b;
503 if (domain == NULL) {
504 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
505 r->in.domain_name, r->in.domain_guid,
506 r->in.site_name ? r->in.site_name : "",
507 r->in.flags,
508 r->out.dc_info);
511 status = cm_connect_netlogon(domain, &netlogon_pipe);
513 reset_cm_connection_on_error(domain, status);
514 if (!NT_STATUS_IS_OK(status)) {
515 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
516 return status;
519 b = netlogon_pipe->binding_handle;
521 /* This call can take a long time - allow the server to time out.
522 35 seconds should do it. */
524 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
526 if (domain->active_directory) {
527 status = dcerpc_netr_DsRGetDCName(b,
528 p->mem_ctx, domain->dcname,
529 r->in.domain_name, NULL, r->in.domain_guid,
530 r->in.flags, r->out.dc_info, &werr);
531 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
532 goto done;
534 if (reset_cm_connection_on_error(domain, status)) {
535 /* Re-initialize. */
536 status = cm_connect_netlogon(domain, &netlogon_pipe);
538 reset_cm_connection_on_error(domain, status);
539 if (!NT_STATUS_IS_OK(status)) {
540 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
541 return status;
544 b = netlogon_pipe->binding_handle;
546 /* This call can take a long time - allow the server to time out.
547 35 seconds should do it. */
549 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
554 * Fallback to less capable methods
557 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
558 if (dc_info == NULL) {
559 status = NT_STATUS_NO_MEMORY;
560 goto done;
563 if (r->in.flags & DS_PDC_REQUIRED) {
564 status = dcerpc_netr_GetDcName(b,
565 p->mem_ctx, domain->dcname,
566 r->in.domain_name, &dc_info->dc_unc, &werr);
567 } else {
568 status = dcerpc_netr_GetAnyDCName(b,
569 p->mem_ctx, domain->dcname,
570 r->in.domain_name, &dc_info->dc_unc, &werr);
573 reset_cm_connection_on_error(domain, status);
574 if (!NT_STATUS_IS_OK(status)) {
575 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
576 nt_errstr(status)));
577 goto done;
579 if (!W_ERROR_IS_OK(werr)) {
580 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
581 win_errstr(werr)));
582 status = werror_to_ntstatus(werr);
583 goto done;
586 *r->out.dc_info = dc_info;
587 status = NT_STATUS_OK;
589 done:
590 /* And restore our original timeout. */
591 rpccli_set_timeout(netlogon_pipe, orig_timeout);
593 return status;
596 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
598 struct winbindd_domain *domain = wb_child_domain();
599 char *domain_name;
600 char **names;
601 enum lsa_SidType *types;
602 struct wbint_Principal *result;
603 NTSTATUS status;
604 int i;
606 if (domain == NULL) {
607 return NT_STATUS_REQUEST_NOT_ACCEPTED;
610 status = domain->methods->rids_to_names(
611 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
612 r->in.rids->num_rids, &domain_name, &names, &types);
613 reset_cm_connection_on_error(domain, status);
614 if (!NT_STATUS_IS_OK(status)) {
615 return status;
618 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
620 result = talloc_array(p->mem_ctx, struct wbint_Principal,
621 r->in.rids->num_rids);
622 if (result == NULL) {
623 return NT_STATUS_NO_MEMORY;
626 for (i=0; i<r->in.rids->num_rids; i++) {
627 sid_compose(&result[i].sid, r->in.domain_sid,
628 r->in.rids->rids[i]);
629 result[i].type = types[i];
630 result[i].name = talloc_move(result, &names[i]);
632 TALLOC_FREE(types);
633 TALLOC_FREE(names);
635 r->out.names->num_principals = r->in.rids->num_rids;
636 r->out.names->principals = result;
637 return NT_STATUS_OK;
640 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
641 struct wbint_CheckMachineAccount *r)
643 struct winbindd_domain *domain;
644 int num_retries = 0;
645 NTSTATUS status;
647 domain = wb_child_domain();
648 if (domain == NULL) {
649 return NT_STATUS_REQUEST_NOT_ACCEPTED;
652 again:
653 invalidate_cm_connection(domain);
654 domain->conn.netlogon_force_reauth = true;
657 struct rpc_pipe_client *netlogon_pipe;
658 status = cm_connect_netlogon(domain, &netlogon_pipe);
661 /* There is a race condition between fetching the trust account
662 password and the periodic machine password change. So it's
663 possible that the trust account password has been changed on us.
664 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
666 #define MAX_RETRIES 3
668 if ((num_retries < MAX_RETRIES)
669 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
670 num_retries++;
671 goto again;
674 if (!NT_STATUS_IS_OK(status)) {
675 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
676 goto done;
679 /* Pass back result code - zero for success, other values for
680 specific failures. */
682 DEBUG(3,("domain %s secret is %s\n", domain->name,
683 NT_STATUS_IS_OK(status) ? "good" : "bad"));
685 done:
686 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
687 ("Checking the trust account password for domain %s returned %s\n",
688 domain->name, nt_errstr(status)));
690 return status;
693 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
694 struct wbint_ChangeMachineAccount *r)
696 struct messaging_context *msg_ctx = winbind_messaging_context();
697 struct winbindd_domain *domain;
698 NTSTATUS status;
699 struct rpc_pipe_client *netlogon_pipe;
701 domain = wb_child_domain();
702 if (domain == NULL) {
703 return NT_STATUS_REQUEST_NOT_ACCEPTED;
706 status = cm_connect_netlogon(domain, &netlogon_pipe);
707 if (!NT_STATUS_IS_OK(status)) {
708 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
709 goto done;
712 status = trust_pw_change(domain->conn.netlogon_creds,
713 msg_ctx,
714 netlogon_pipe->binding_handle,
715 domain->name,
716 true); /* force */
718 /* Pass back result code - zero for success, other values for
719 specific failures. */
721 DEBUG(3,("domain %s secret %s\n", domain->name,
722 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
724 done:
725 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
726 ("Changing the trust account password for domain %s returned %s\n",
727 domain->name, nt_errstr(status)));
729 return status;
732 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
734 NTSTATUS status;
735 struct winbindd_domain *domain;
736 struct rpc_pipe_client *netlogon_pipe;
737 union netr_CONTROL_QUERY_INFORMATION info;
738 WERROR werr;
739 fstring logon_server;
740 struct dcerpc_binding_handle *b;
741 bool retry = false;
743 domain = wb_child_domain();
744 if (domain == NULL) {
745 return NT_STATUS_REQUEST_NOT_ACCEPTED;
748 reconnect:
749 status = cm_connect_netlogon(domain, &netlogon_pipe);
750 reset_cm_connection_on_error(domain, status);
751 if (!NT_STATUS_IS_OK(status)) {
752 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
753 nt_errstr(status)));
754 return status;
757 b = netlogon_pipe->binding_handle;
759 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
760 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
761 if (*r->out.dcname == NULL) {
762 DEBUG(2, ("Could not allocate memory\n"));
763 return NT_STATUS_NO_MEMORY;
767 * This provokes a WERR_NOT_SUPPORTED error message. This is
768 * documented in the wspp docs. I could not get a successful
769 * call to work, but the main point here is testing that the
770 * netlogon pipe works.
772 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
773 logon_server, NETLOGON_CONTROL_QUERY,
774 2, &info, &werr);
776 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
777 DEBUG(10, ("Session might have expired. "
778 "Reconnect and retry once.\n"));
779 invalidate_cm_connection(domain);
780 retry = true;
781 goto reconnect;
784 reset_cm_connection_on_error(domain, status);
785 if (!NT_STATUS_IS_OK(status)) {
786 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
787 nt_errstr(status)));
788 return status;
791 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
792 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
793 "WERR_NOT_SUPPORTED\n",
794 win_errstr(werr)));
795 return werror_to_ntstatus(werr);
798 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
799 return NT_STATUS_OK;
802 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
803 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
805 struct winbindd_domain *domain;
806 NTSTATUS status;
807 struct rpc_pipe_client *netlogon_pipe;
809 domain = wb_child_domain();
810 if (domain == NULL) {
811 return NT_STATUS_REQUEST_NOT_ACCEPTED;
814 status = cm_connect_netlogon(domain, &netlogon_pipe);
815 if (!NT_STATUS_IS_OK(status)) {
816 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
817 goto done;
820 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
821 netlogon_pipe->binding_handle,
822 r->in.site_name,
823 r->in.dns_ttl,
824 r->in.dns_names);
826 /* Pass back result code - zero for success, other values for
827 specific failures. */
829 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
830 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
832 done:
833 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
834 ("Update of DNS records via RW DC %s returned %s\n",
835 domain->name, nt_errstr(status)));
837 return status;
840 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
841 struct winbind_SamLogon *r)
843 struct winbindd_domain *domain;
844 NTSTATUS status;
845 DATA_BLOB lm_response, nt_response;
846 domain = wb_child_domain();
847 if (domain == NULL) {
848 return NT_STATUS_REQUEST_NOT_ACCEPTED;
851 /* TODO: Handle interactive logons here */
852 if (r->in.validation_level != 3 ||
853 r->in.logon.network == NULL ||
854 (r->in.logon_level != NetlogonNetworkInformation
855 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
856 return NT_STATUS_REQUEST_NOT_ACCEPTED;
860 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
861 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
863 status = winbind_dual_SamLogon(domain, p->mem_ctx,
864 r->in.logon.network->identity_info.parameter_control,
865 r->in.logon.network->identity_info.account_name.string,
866 r->in.logon.network->identity_info.domain_name.string,
867 r->in.logon.network->identity_info.workstation.string,
868 r->in.logon.network->challenge,
869 lm_response, nt_response, &r->out.validation.sam3);
870 return status;
873 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
874 struct winbindd_domain *domain,
875 struct winbind_LogonControl *r)
877 NTSTATUS status;
878 struct rpc_pipe_client *netlogon_pipe = NULL;
879 struct netr_NETLOGON_INFO_2 *info2 = NULL;
880 WERROR check_result = WERR_INTERNAL_ERROR;
882 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
883 if (info2 == NULL) {
884 return WERR_NOMEM;
887 if (domain->internal) {
888 check_result = WERR_OK;
889 goto check_return;
893 * For now we just force a reconnect
895 * TODO: take care of the optional '\dcname'
897 invalidate_cm_connection(domain);
898 domain->conn.netlogon_force_reauth = true;
899 status = cm_connect_netlogon(domain, &netlogon_pipe);
900 reset_cm_connection_on_error(domain, status);
901 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
902 status = NT_STATUS_NO_LOGON_SERVERS;
904 if (!NT_STATUS_IS_OK(status)) {
905 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
906 __func__, domain->name, domain->alt_name,
907 nt_errstr(status)));
909 * Here we return a top level error!
910 * This is different than TC_QUERY or TC_VERIFY.
912 return ntstatus_to_werror(status);
914 check_result = WERR_OK;
916 check_return:
917 info2->pdc_connection_status = WERR_OK;
918 if (domain->dcname != NULL) {
919 info2->flags |= NETLOGON_HAS_IP;
920 info2->flags |= NETLOGON_HAS_TIMESERV;
921 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
922 domain->dcname);
923 if (info2->trusted_dc_name == NULL) {
924 return WERR_NOMEM;
926 } else {
927 info2->trusted_dc_name = talloc_strdup(info2, "");
928 if (info2->trusted_dc_name == NULL) {
929 return WERR_NOMEM;
932 info2->tc_connection_status = check_result;
934 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
935 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
936 "pdc_connection[%s] tc_connection[%s]\n",
937 __func__, domain->name, domain->alt_name,
938 domain->dcname,
939 win_errstr(info2->pdc_connection_status),
940 win_errstr(info2->tc_connection_status)));
943 r->out.query->info2 = info2;
945 DEBUG(5, ("%s: succeeded.\n", __func__));
946 return WERR_OK;
949 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
950 struct winbindd_domain *domain,
951 struct winbind_LogonControl *r)
953 NTSTATUS status;
954 struct rpc_pipe_client *netlogon_pipe = NULL;
955 struct netr_NETLOGON_INFO_2 *info2 = NULL;
956 WERROR check_result = WERR_INTERNAL_ERROR;
958 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
959 if (info2 == NULL) {
960 return WERR_NOMEM;
963 if (domain->internal) {
964 check_result = WERR_OK;
965 goto check_return;
968 status = cm_connect_netlogon(domain, &netlogon_pipe);
969 reset_cm_connection_on_error(domain, status);
970 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
971 status = NT_STATUS_NO_LOGON_SERVERS;
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
975 nt_errstr(status)));
976 check_result = ntstatus_to_werror(status);
977 goto check_return;
979 check_result = WERR_OK;
981 check_return:
982 info2->pdc_connection_status = WERR_OK;
983 if (domain->dcname != NULL) {
984 info2->flags |= NETLOGON_HAS_IP;
985 info2->flags |= NETLOGON_HAS_TIMESERV;
986 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
987 domain->dcname);
988 if (info2->trusted_dc_name == NULL) {
989 return WERR_NOMEM;
991 } else {
992 info2->trusted_dc_name = talloc_strdup(info2, "");
993 if (info2->trusted_dc_name == NULL) {
994 return WERR_NOMEM;
997 info2->tc_connection_status = check_result;
999 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1000 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1001 "pdc_connection[%s] tc_connection[%s]\n",
1002 __func__, domain->name, domain->alt_name,
1003 domain->dcname,
1004 win_errstr(info2->pdc_connection_status),
1005 win_errstr(info2->tc_connection_status)));
1008 r->out.query->info2 = info2;
1010 DEBUG(5, ("%s: succeeded.\n", __func__));
1011 return WERR_OK;
1014 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1015 struct winbindd_domain *domain,
1016 struct winbind_LogonControl *r)
1018 TALLOC_CTX *frame = talloc_stackframe();
1019 NTSTATUS status;
1020 NTSTATUS result;
1021 struct lsa_String trusted_domain_name = {};
1022 struct lsa_StringLarge trusted_domain_name_l = {};
1023 struct rpc_pipe_client *local_lsa_pipe = NULL;
1024 struct policy_handle local_lsa_policy = {};
1025 struct dcerpc_binding_handle *local_lsa = NULL;
1026 struct rpc_pipe_client *netlogon_pipe = NULL;
1027 struct cli_credentials *creds = NULL;
1028 struct samr_Password *cur_nt_hash = NULL;
1029 uint32_t trust_attributes = 0;
1030 struct samr_Password new_owf_password = {};
1031 int cmp_new = -1;
1032 struct samr_Password old_owf_password = {};
1033 int cmp_old = -1;
1034 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1035 bool fetch_fti = false;
1036 struct lsa_ForestTrustInformation *new_fti = NULL;
1037 struct netr_TrustInfo *trust_info = NULL;
1038 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1039 struct dcerpc_binding_handle *b = NULL;
1040 WERROR check_result = WERR_INTERNAL_ERROR;
1041 WERROR verify_result = WERR_INTERNAL_ERROR;
1042 bool retry = false;
1044 trusted_domain_name.string = domain->name;
1045 trusted_domain_name_l.string = domain->name;
1047 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1048 if (info2 == NULL) {
1049 TALLOC_FREE(frame);
1050 return WERR_NOMEM;
1053 if (domain->internal) {
1054 check_result = WERR_OK;
1055 goto check_return;
1058 status = pdb_get_trust_credentials(domain->name,
1059 domain->alt_name,
1060 frame,
1061 &creds);
1062 if (NT_STATUS_IS_OK(status)) {
1063 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1064 TALLOC_FREE(creds);
1067 if (!domain->primary) {
1068 union lsa_TrustedDomainInfo *tdi = NULL;
1070 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1071 &local_lsa_policy);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1074 __location__, __func__, nt_errstr(status)));
1075 TALLOC_FREE(frame);
1076 return WERR_INTERNAL_ERROR;
1078 local_lsa = local_lsa_pipe->binding_handle;
1080 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1081 &local_lsa_policy,
1082 &trusted_domain_name,
1083 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1084 &tdi, &result);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1087 __location__, __func__, domain->name, nt_errstr(status)));
1088 TALLOC_FREE(frame);
1089 return WERR_INTERNAL_ERROR;
1091 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1092 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1093 __location__, __func__, domain->name));
1094 TALLOC_FREE(frame);
1095 return WERR_NO_SUCH_DOMAIN;
1097 if (!NT_STATUS_IS_OK(result)) {
1098 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1099 __location__, __func__, domain->name, nt_errstr(result)));
1100 TALLOC_FREE(frame);
1101 return WERR_INTERNAL_ERROR;
1103 if (tdi == NULL) {
1104 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1105 "returned no trusted domain information\n",
1106 __location__, __func__));
1107 TALLOC_FREE(frame);
1108 return WERR_INTERNAL_ERROR;
1111 local_tdo = &tdi->info_ex;
1112 trust_attributes = local_tdo->trust_attributes;
1115 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1116 struct lsa_ForestTrustInformation *old_fti = NULL;
1118 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1119 &local_lsa_policy,
1120 &trusted_domain_name,
1121 LSA_FOREST_TRUST_DOMAIN_INFO,
1122 &old_fti, &result);
1123 if (!NT_STATUS_IS_OK(status)) {
1124 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1125 __location__, __func__, domain->name, nt_errstr(status)));
1126 TALLOC_FREE(frame);
1127 return WERR_INTERNAL_ERROR;
1129 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1130 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1131 __func__, domain->name));
1132 old_fti = NULL;
1133 fetch_fti = true;
1134 result = NT_STATUS_OK;
1136 if (!NT_STATUS_IS_OK(result)) {
1137 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1138 __location__, __func__, domain->name, nt_errstr(result)));
1139 TALLOC_FREE(frame);
1140 return WERR_INTERNAL_ERROR;
1143 TALLOC_FREE(old_fti);
1146 reconnect:
1147 status = cm_connect_netlogon(domain, &netlogon_pipe);
1148 reset_cm_connection_on_error(domain, status);
1149 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1150 status = NT_STATUS_NO_LOGON_SERVERS;
1152 if (!NT_STATUS_IS_OK(status)) {
1153 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1154 nt_errstr(status)));
1155 check_result = ntstatus_to_werror(status);
1156 goto check_return;
1158 check_result = WERR_OK;
1159 b = netlogon_pipe->binding_handle;
1161 if (cur_nt_hash == NULL) {
1162 verify_result = WERR_NO_TRUST_LSA_SECRET;
1163 goto verify_return;
1166 if (fetch_fti) {
1167 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1168 b, frame,
1169 &new_fti);
1170 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1171 status = NT_STATUS_NOT_SUPPORTED;
1173 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1174 new_fti = NULL;
1175 status = NT_STATUS_OK;
1177 if (!NT_STATUS_IS_OK(status)) {
1178 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1179 invalidate_cm_connection(domain);
1180 retry = true;
1181 goto reconnect;
1183 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1184 "failed: %s\n",
1185 domain->name, nt_errstr(status)));
1186 check_result = ntstatus_to_werror(status);
1187 goto check_return;
1191 if (new_fti != NULL) {
1192 struct lsa_ForestTrustInformation old_fti = {};
1193 struct lsa_ForestTrustInformation *merged_fti = NULL;
1194 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1196 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1197 &old_fti, new_fti,
1198 &merged_fti);
1199 if (!NT_STATUS_IS_OK(status)) {
1200 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1201 __location__, __func__,
1202 domain->name, nt_errstr(status)));
1203 TALLOC_FREE(frame);
1204 return ntstatus_to_werror(status);
1207 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1208 &local_lsa_policy,
1209 &trusted_domain_name_l,
1210 LSA_FOREST_TRUST_DOMAIN_INFO,
1211 merged_fti,
1212 0, /* check_only=0 => store it! */
1213 &collision_info,
1214 &result);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1217 __location__, __func__, domain->name, nt_errstr(status)));
1218 TALLOC_FREE(frame);
1219 return WERR_INTERNAL_ERROR;
1221 if (!NT_STATUS_IS_OK(result)) {
1222 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1223 __location__, __func__, domain->name, nt_errstr(result)));
1224 TALLOC_FREE(frame);
1225 return ntstatus_to_werror(result);
1229 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1230 b, frame,
1231 &new_owf_password,
1232 &old_owf_password,
1233 &trust_info);
1234 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1235 status = NT_STATUS_NOT_SUPPORTED;
1237 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1238 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1239 nt_errstr(status)));
1240 verify_result = WERR_OK;
1241 goto verify_return;
1243 if (!NT_STATUS_IS_OK(status)) {
1244 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1245 invalidate_cm_connection(domain);
1246 retry = true;
1247 goto reconnect;
1249 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1250 nt_errstr(status)));
1252 if (!dcerpc_binding_handle_is_connected(b)) {
1253 check_result = ntstatus_to_werror(status);
1254 goto check_return;
1255 } else {
1256 verify_result = ntstatus_to_werror(status);
1257 goto verify_return;
1261 if (trust_info != NULL && trust_info->count >= 1) {
1262 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1264 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1265 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1266 goto verify_return;
1270 cmp_new = memcmp(new_owf_password.hash,
1271 cur_nt_hash->hash,
1272 sizeof(cur_nt_hash->hash));
1273 cmp_old = memcmp(old_owf_password.hash,
1274 cur_nt_hash->hash,
1275 sizeof(cur_nt_hash->hash));
1276 if (cmp_new != 0 && cmp_old != 0) {
1277 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1278 "any password known to dcname[%s]\n",
1279 __func__, domain->name, domain->alt_name,
1280 domain->dcname));
1281 verify_result = WERR_WRONG_PASSWORD;
1282 goto verify_return;
1285 if (cmp_new != 0) {
1286 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1287 "against the old password known to dcname[%s]\n",
1288 __func__, domain->name, domain->alt_name,
1289 domain->dcname));
1292 verify_result = WERR_OK;
1293 goto verify_return;
1295 check_return:
1296 verify_result = check_result;
1297 verify_return:
1298 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1299 info2->pdc_connection_status = verify_result;
1300 if (domain->dcname != NULL) {
1301 info2->flags |= NETLOGON_HAS_IP;
1302 info2->flags |= NETLOGON_HAS_TIMESERV;
1303 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1304 domain->dcname);
1305 if (info2->trusted_dc_name == NULL) {
1306 TALLOC_FREE(frame);
1307 return WERR_NOMEM;
1309 } else {
1310 info2->trusted_dc_name = talloc_strdup(info2, "");
1311 if (info2->trusted_dc_name == NULL) {
1312 TALLOC_FREE(frame);
1313 return WERR_NOMEM;
1316 info2->tc_connection_status = check_result;
1318 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1319 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1320 "pdc_connection[%s] tc_connection[%s]\n",
1321 __func__, domain->name, domain->alt_name,
1322 domain->dcname,
1323 win_errstr(info2->pdc_connection_status),
1324 win_errstr(info2->tc_connection_status)));
1327 r->out.query->info2 = info2;
1329 DEBUG(5, ("%s: succeeded.\n", __func__));
1330 TALLOC_FREE(frame);
1331 return WERR_OK;
1334 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1335 struct winbindd_domain *domain,
1336 struct winbind_LogonControl *r)
1338 struct messaging_context *msg_ctx = winbind_messaging_context();
1339 NTSTATUS status;
1340 struct rpc_pipe_client *netlogon_pipe;
1341 struct cli_credentials *creds = NULL;
1342 struct samr_Password *cur_nt_hash = NULL;
1343 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1344 struct dcerpc_binding_handle *b;
1345 WERROR change_result = WERR_OK;
1346 bool retry = false;
1348 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1349 if (info1 == NULL) {
1350 return WERR_NOMEM;
1353 if (domain->internal) {
1354 return WERR_NOT_SUPPORTED;
1357 status = pdb_get_trust_credentials(domain->name,
1358 domain->alt_name,
1359 p->mem_ctx,
1360 &creds);
1361 if (NT_STATUS_IS_OK(status)) {
1362 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1363 TALLOC_FREE(creds);
1366 reconnect:
1367 status = cm_connect_netlogon(domain, &netlogon_pipe);
1368 reset_cm_connection_on_error(domain, status);
1369 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1370 status = NT_STATUS_NO_LOGON_SERVERS;
1372 if (!NT_STATUS_IS_OK(status)) {
1373 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1374 __func__, domain->name, domain->alt_name,
1375 nt_errstr(status)));
1377 * Here we return a top level error!
1378 * This is different than TC_QUERY or TC_VERIFY.
1380 return ntstatus_to_werror(status);
1382 b = netlogon_pipe->binding_handle;
1384 if (cur_nt_hash == NULL) {
1385 change_result = WERR_NO_TRUST_LSA_SECRET;
1386 goto change_return;
1388 TALLOC_FREE(cur_nt_hash);
1390 status = trust_pw_change(domain->conn.netlogon_creds,
1391 msg_ctx, b, domain->name,
1392 true); /* force */
1393 if (!NT_STATUS_IS_OK(status)) {
1394 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1395 invalidate_cm_connection(domain);
1396 retry = true;
1397 goto reconnect;
1400 DEBUG(1, ("trust_pw_change(%s): %s\n",
1401 domain->name, nt_errstr(status)));
1403 change_result = ntstatus_to_werror(status);
1404 goto change_return;
1407 change_result = WERR_OK;
1409 change_return:
1410 info1->pdc_connection_status = change_result;
1412 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1413 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1414 "pdc_connection[%s]\n",
1415 __func__, domain->name, domain->alt_name,
1416 domain->dcname,
1417 win_errstr(info1->pdc_connection_status)));
1420 r->out.query->info1 = info1;
1422 DEBUG(5, ("%s: succeeded.\n", __func__));
1423 return WERR_OK;
1426 WERROR _winbind_LogonControl(struct pipes_struct *p,
1427 struct winbind_LogonControl *r)
1429 struct winbindd_domain *domain;
1431 domain = wb_child_domain();
1432 if (domain == NULL) {
1433 return WERR_NO_SUCH_DOMAIN;
1436 switch (r->in.function_code) {
1437 case NETLOGON_CONTROL_REDISCOVER:
1438 if (r->in.level != 2) {
1439 return WERR_INVALID_PARAMETER;
1441 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1442 case NETLOGON_CONTROL_TC_QUERY:
1443 if (r->in.level != 2) {
1444 return WERR_INVALID_PARAMETER;
1446 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1447 case NETLOGON_CONTROL_TC_VERIFY:
1448 if (r->in.level != 2) {
1449 return WERR_INVALID_PARAMETER;
1451 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1452 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1453 if (r->in.level != 1) {
1454 return WERR_INVALID_PARAMETER;
1456 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1457 default:
1458 break;
1461 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1462 __func__, r->in.function_code));
1463 return WERR_NOT_SUPPORTED;
1466 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1467 struct winbind_GetForestTrustInformation *r)
1469 TALLOC_CTX *frame = talloc_stackframe();
1470 NTSTATUS status, result;
1471 struct winbindd_domain *domain;
1472 struct rpc_pipe_client *netlogon_pipe;
1473 struct dcerpc_binding_handle *b;
1474 bool retry = false;
1475 struct lsa_String trusted_domain_name = {};
1476 struct lsa_StringLarge trusted_domain_name_l = {};
1477 union lsa_TrustedDomainInfo *tdi = NULL;
1478 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1479 struct lsa_ForestTrustInformation _old_fti = {};
1480 struct lsa_ForestTrustInformation *old_fti = NULL;
1481 struct lsa_ForestTrustInformation *new_fti = NULL;
1482 struct lsa_ForestTrustInformation *merged_fti = NULL;
1483 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1484 bool update_fti = false;
1485 struct rpc_pipe_client *local_lsa_pipe;
1486 struct policy_handle local_lsa_policy;
1487 struct dcerpc_binding_handle *local_lsa = NULL;
1489 domain = wb_child_domain();
1490 if (domain == NULL) {
1491 TALLOC_FREE(frame);
1492 return WERR_NO_SUCH_DOMAIN;
1496 * checking for domain->internal and domain->primary
1497 * makes sure we only do some work when running as DC.
1500 if (domain->internal) {
1501 TALLOC_FREE(frame);
1502 return WERR_NO_SUCH_DOMAIN;
1505 if (domain->primary) {
1506 TALLOC_FREE(frame);
1507 return WERR_NO_SUCH_DOMAIN;
1510 trusted_domain_name.string = domain->name;
1511 trusted_domain_name_l.string = domain->name;
1513 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1514 &local_lsa_policy);
1515 if (!NT_STATUS_IS_OK(status)) {
1516 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1517 __location__, __func__, nt_errstr(status)));
1518 TALLOC_FREE(frame);
1519 return WERR_INTERNAL_ERROR;
1521 local_lsa = local_lsa_pipe->binding_handle;
1523 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1524 &local_lsa_policy,
1525 &trusted_domain_name,
1526 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1527 &tdi, &result);
1528 if (!NT_STATUS_IS_OK(status)) {
1529 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1530 __location__, __func__, domain->name, nt_errstr(status)));
1531 TALLOC_FREE(frame);
1532 return WERR_INTERNAL_ERROR;
1534 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1535 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1536 __location__, __func__, domain->name));
1537 TALLOC_FREE(frame);
1538 return WERR_NO_SUCH_DOMAIN;
1540 if (!NT_STATUS_IS_OK(result)) {
1541 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1542 __location__, __func__, domain->name, nt_errstr(result)));
1543 TALLOC_FREE(frame);
1544 return WERR_INTERNAL_ERROR;
1546 if (tdi == NULL) {
1547 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1548 "returned no trusted domain information\n",
1549 __location__, __func__));
1550 TALLOC_FREE(frame);
1551 return WERR_INTERNAL_ERROR;
1554 tdo = &tdi->info_ex;
1556 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1557 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1558 __func__, tdo->netbios_name.string,
1559 tdo->domain_name.string,
1560 (unsigned)tdo->trust_attributes));
1561 TALLOC_FREE(frame);
1562 return WERR_NO_SUCH_DOMAIN;
1565 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1566 TALLOC_FREE(frame);
1567 return WERR_INVALID_FLAGS;
1570 reconnect:
1571 status = cm_connect_netlogon(domain, &netlogon_pipe);
1572 reset_cm_connection_on_error(domain, status);
1573 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1574 status = NT_STATUS_NO_LOGON_SERVERS;
1576 if (!NT_STATUS_IS_OK(status)) {
1577 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1578 nt_errstr(status)));
1579 TALLOC_FREE(frame);
1580 return ntstatus_to_werror(status);
1582 b = netlogon_pipe->binding_handle;
1584 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1585 b, p->mem_ctx,
1586 &new_fti);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1589 invalidate_cm_connection(domain);
1590 retry = true;
1591 goto reconnect;
1593 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1594 domain->name, nt_errstr(status)));
1595 TALLOC_FREE(frame);
1596 return ntstatus_to_werror(status);
1599 *r->out.forest_trust_info = new_fti;
1601 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1602 update_fti = true;
1605 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1606 &local_lsa_policy,
1607 &trusted_domain_name,
1608 LSA_FOREST_TRUST_DOMAIN_INFO,
1609 &old_fti, &result);
1610 if (!NT_STATUS_IS_OK(status)) {
1611 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1612 __location__, __func__, domain->name, nt_errstr(status)));
1613 TALLOC_FREE(frame);
1614 return WERR_INTERNAL_ERROR;
1616 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1617 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1618 __func__, domain->name));
1619 update_fti = true;
1620 old_fti = &_old_fti;
1621 result = NT_STATUS_OK;
1623 if (!NT_STATUS_IS_OK(result)) {
1624 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1625 __location__, __func__, domain->name, nt_errstr(result)));
1626 TALLOC_FREE(frame);
1627 return WERR_INTERNAL_ERROR;
1630 if (old_fti == NULL) {
1631 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1632 "returned success without returning forest trust information\n",
1633 __location__, __func__));
1634 TALLOC_FREE(frame);
1635 return WERR_INTERNAL_ERROR;
1638 if (!update_fti) {
1639 goto done;
1642 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1643 &merged_fti);
1644 if (!NT_STATUS_IS_OK(status)) {
1645 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1646 __location__, __func__, domain->name, nt_errstr(status)));
1647 TALLOC_FREE(frame);
1648 return ntstatus_to_werror(status);
1651 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1652 &local_lsa_policy,
1653 &trusted_domain_name_l,
1654 LSA_FOREST_TRUST_DOMAIN_INFO,
1655 merged_fti,
1656 0, /* check_only=0 => store it! */
1657 &collision_info,
1658 &result);
1659 if (!NT_STATUS_IS_OK(status)) {
1660 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1661 __location__, __func__, domain->name, nt_errstr(status)));
1662 TALLOC_FREE(frame);
1663 return WERR_INTERNAL_ERROR;
1665 if (!NT_STATUS_IS_OK(result)) {
1666 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1667 __location__, __func__, domain->name, nt_errstr(result)));
1668 TALLOC_FREE(frame);
1669 return ntstatus_to_werror(result);
1672 done:
1673 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1674 TALLOC_FREE(frame);
1675 return WERR_OK;